@polymorphism-tech/morph-spec 4.11.1 → 4.13.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 (317) hide show
  1. package/README.md +21 -29
  2. package/bin/morph-spec.js +41 -24
  3. package/bin/task-manager.js +962 -1341
  4. package/bin/validate.js +1 -1
  5. package/claude-plugin.json +1 -1
  6. package/docs/CHEATSHEET.md +10 -11
  7. package/docs/QUICKSTART.md +15 -15
  8. package/framework/CLAUDE.md +5 -2
  9. package/framework/agents/README.md +3 -4
  10. package/framework/agents/ai-agents/ai-system-architect.md +6 -10
  11. package/framework/agents/architecture/seo-growth-hacker.md +166 -326
  12. package/framework/agents/architecture/standards-architect.md +21 -31
  13. package/framework/agents/backend/dotnet-senior.md +160 -86
  14. package/framework/agents/backend/ef-modeler.md +2 -6
  15. package/framework/agents/backend/hangfire-orchestrator.md +8 -9
  16. package/framework/agents/backend/ms-agent-expert.md +1 -1
  17. package/framework/agents/frontend/nextjs-expert.md +198 -133
  18. package/framework/agents/frontend/ui-ux-designer.md +226 -267
  19. package/framework/agents/infrastructure/infra-architect.md +191 -27
  20. package/framework/agents/integrations/clerk-auth.md +19 -26
  21. package/framework/agents/integrations/hangfire-integration.md +1 -4
  22. package/framework/agents.json +226 -1454
  23. package/framework/commands/morph-apply.md +4 -4
  24. package/framework/commands/morph-preflight.md +4 -26
  25. package/framework/commands/morph-proposal.md +19 -19
  26. package/framework/commands/morph-status.md +2 -2
  27. package/framework/commands/morph-troubleshoot.md +6 -13
  28. package/framework/hooks/README.md +1 -6
  29. package/framework/hooks/claude-code/post-tool-use/agent-complete.js +122 -0
  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/dispatch-helpers.js +17 -0
  42. package/framework/hooks/shared/phase-utils.js +4 -8
  43. package/framework/hooks/shared/state-reader.js +34 -3
  44. package/framework/phases.json +7 -45
  45. package/framework/rules/ai-agents-standards.md +15 -0
  46. package/framework/rules/asaas-standards.md +13 -0
  47. package/framework/rules/clerk-standards.md +13 -0
  48. package/framework/rules/csharp-standards.md +8 -4
  49. package/framework/rules/data-standards.md +18 -0
  50. package/framework/rules/dotnet-templates.md +87 -0
  51. package/framework/rules/frontend-standards.md +13 -13
  52. package/framework/rules/hangfire-standards.md +13 -0
  53. package/framework/rules/infrastructure-standards.md +27 -16
  54. package/framework/rules/morph-workflow.md +73 -13
  55. package/framework/rules/nextjs-standards.md +1 -0
  56. package/framework/rules/nextjs-templates.md +40 -0
  57. package/framework/rules/resend-standards.md +12 -0
  58. package/framework/rules/supabase-standards.md +29 -0
  59. package/framework/skills/README.md +6 -8
  60. package/framework/skills/level-0-meta/mcp-registry.json +21 -99
  61. package/framework/{standards/ai-agents/team-orchestration.md → skills/level-0-meta/morph-agent-teams/SKILL.md} +472 -479
  62. package/framework/skills/level-0-meta/morph-brainstorming/SKILL.md +28 -1
  63. package/framework/skills/level-0-meta/morph-checklist/SKILL.md +2 -2
  64. package/framework/skills/level-0-meta/morph-code-review/SKILL.md +1 -5
  65. package/framework/skills/level-0-meta/morph-code-review/scripts/scan-csharp.mjs +1 -1
  66. package/framework/skills/level-0-meta/morph-frontend-review/SKILL.md +23 -41
  67. package/framework/skills/level-0-meta/morph-init/SKILL.md +18 -14
  68. package/framework/skills/level-0-meta/morph-parallel-dispatch/SKILL.md +225 -0
  69. package/framework/skills/level-0-meta/morph-post-implementation/SKILL.md +20 -0
  70. package/framework/skills/level-0-meta/morph-tool-usage-guide/SKILL.md +4 -8
  71. package/framework/skills/level-0-meta/morph-tool-usage-guide/references/tools-per-phase.md +15 -59
  72. package/framework/skills/level-0-meta/morph-verification-before-completion/SKILL.md +7 -19
  73. package/framework/skills/level-0-meta/morph-verification-before-completion/scripts/check-phase-outputs.mjs +8 -8
  74. package/framework/skills/level-1-workflows/README.md +1 -1
  75. package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +49 -50
  76. package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +58 -124
  77. package/framework/skills/level-1-workflows/morph-phase-design/references/architecture-analysis-guide.md +5 -50
  78. package/framework/skills/level-1-workflows/morph-phase-design/references/spec-example.md +1 -1
  79. package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +127 -159
  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 +0 -2
  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 +275 -61
  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 -2338
  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 +342 -211
  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/mcp/mcp-setup.js +28 -6
  159. package/src/commands/phase/phase-reset.js +1 -1
  160. package/src/commands/project/doctor.js +10 -32
  161. package/src/commands/project/init.js +32 -1
  162. package/src/commands/project/status.js +6 -12
  163. package/src/commands/scaffold/scaffold.js +131 -0
  164. package/src/commands/scope/escalate.js +1 -1
  165. package/src/commands/state/advance-phase.js +15 -29
  166. package/src/commands/state/state.js +20 -5
  167. package/src/commands/tasks/task.js +0 -30
  168. package/src/commands/validation/validate-feature.js +3 -10
  169. package/src/core/paths/output-schema.js +12 -13
  170. package/src/core/state/phase-state-machine.js +211 -217
  171. package/src/core/state/state-manager.js +9 -9
  172. package/src/lib/agents/agents-manager.js +2 -2
  173. package/src/lib/agents/output-collector.js +1 -2
  174. package/src/lib/detectors/design-system-detector.js +4 -4
  175. package/src/lib/detectors/index.js +1 -11
  176. package/src/lib/generators/architecture-scanner.js +640 -0
  177. package/src/lib/generators/context-generator.js +3 -3
  178. package/src/lib/generators/design-system-generator.js +508 -298
  179. package/src/lib/generators/index.js +12 -10
  180. package/src/lib/generators/metadata-extractor.js +386 -387
  181. package/src/lib/generators/recap-generator.js +4 -4
  182. package/src/lib/generators/scaffold-generator.js +317 -0
  183. package/src/lib/generators/settings-generator.js +0 -1
  184. package/src/lib/phase-chain/phase-validator.js +64 -42
  185. package/src/lib/stack/stack-profile.js +2 -2
  186. package/src/lib/standards/digest-builder.js +72 -285
  187. package/src/lib/tasks/task-parser.js +11 -5
  188. package/src/lib/validators/architecture/architecture-validator.js +259 -387
  189. package/src/lib/validators/content/content-validator.js +287 -287
  190. package/src/lib/validators/css/css-validator.js +340 -352
  191. package/src/lib/validators/design-system/design-system-validator.js +11 -5
  192. package/src/lib/validators/packages/package-validator.js +347 -360
  193. package/src/lib/validators/shared/issue-counter.js +14 -18
  194. package/src/lib/validators/validation-runner.js +3 -19
  195. package/src/scripts/setup-infra.js +1 -1
  196. package/src/utils/agents-installer.js +24 -3
  197. package/src/utils/file-copier.js +1 -0
  198. package/src/utils/hooks-installer.js +21 -19
  199. package/src/utils/skills-installer.js +178 -178
  200. package/framework/agents/architecture/prompt-engineer.md +0 -195
  201. package/framework/agents/backend/api-designer.md +0 -106
  202. package/framework/agents/frontend/blazor-builder.md +0 -229
  203. package/framework/agents/frontend/nextjs-ui-specialist.md +0 -218
  204. package/framework/agents/infrastructure/azure-architect.md +0 -150
  205. package/framework/agents/infrastructure/azure-deploy-specialist.md +0 -707
  206. package/framework/agents/infrastructure/bicep-architect.md +0 -132
  207. package/framework/agents/infrastructure/container-specialist.md +0 -137
  208. package/framework/agents/infrastructure/devops-engineer.md +0 -126
  209. package/framework/agents/integrations/azure-identity.md +0 -148
  210. package/framework/agents/quality/code-analyzer.md +0 -239
  211. package/framework/agents/quality/testing-specialist.md +0 -130
  212. package/framework/hooks/claude-code/notification/approval-reminder.js +0 -57
  213. package/framework/hooks/claude-code/post-tool-use/context-refresh.js +0 -109
  214. package/framework/hooks/claude-code/post-tool-use/skill-reminder.js +0 -78
  215. package/framework/index/troubleshooting-index.json +0 -184
  216. package/framework/rules/testing-standards.md +0 -14
  217. package/framework/skills/level-0-meta/morph-replicate/SKILL.md +0 -230
  218. package/framework/skills/level-0-meta/morph-replicate/references/blazor-html-mapping.md +0 -70
  219. package/framework/skills/level-1-workflows/morph-phase-clarify/SKILL.md +0 -256
  220. package/framework/skills/level-1-workflows/morph-phase-clarify/references/clarifications-example.md +0 -117
  221. package/framework/skills/level-1-workflows/morph-phase-setup/SKILL.md +0 -269
  222. package/framework/standards/ai-agents/blazor-ui.md +0 -364
  223. package/framework/standards/architecture/ddd/aggregates.md +0 -120
  224. package/framework/standards/architecture/ddd/bounded-contexts.md +0 -105
  225. package/framework/standards/architecture/ddd/complexity-levels.md +0 -108
  226. package/framework/standards/architecture/ddd/entities.md +0 -99
  227. package/framework/standards/architecture/ddd/ubiquitous-language.md +0 -58
  228. package/framework/standards/architecture/ddd/value-objects.md +0 -124
  229. package/framework/standards/backend/api/minimal-api.md +0 -494
  230. package/framework/standards/backend/api/rest.md +0 -492
  231. package/framework/standards/backend/authentication/passkeys.md +0 -428
  232. package/framework/standards/backend/database/ef-core.md +0 -199
  233. package/framework/standards/backend/database/migrations.md +0 -393
  234. package/framework/standards/backend/database/repository-patterns.md +0 -528
  235. package/framework/standards/backend/dotnet/async.md +0 -366
  236. package/framework/standards/backend/dotnet/core.md +0 -117
  237. package/framework/standards/backend/dotnet/di.md +0 -439
  238. package/framework/standards/backend/dotnet/program-cs-checklist.md +0 -92
  239. package/framework/standards/context/analytics.md +0 -96
  240. package/framework/standards/context/bundles.md +0 -110
  241. package/framework/standards/context/priming.md +0 -78
  242. package/framework/standards/core/architecture.md +0 -185
  243. package/framework/standards/core/coding.md +0 -214
  244. package/framework/standards/core/git-branching-strategy.md +0 -403
  245. package/framework/standards/core/git.md +0 -185
  246. package/framework/standards/core/testing.md +0 -295
  247. package/framework/standards/data/nosql/blob-storage.md +0 -102
  248. package/framework/standards/data/vector-search/azure-ai-search.md +0 -121
  249. package/framework/standards/frontend/blazor/design-checklist.md +0 -222
  250. package/framework/standards/frontend/blazor/fluent-ui-setup.md +0 -595
  251. package/framework/standards/frontend/blazor/fluent-ui.md +0 -137
  252. package/framework/standards/frontend/blazor/html-conversion.md +0 -184
  253. package/framework/standards/frontend/blazor/lifecycle.md +0 -195
  254. package/framework/standards/frontend/blazor/pitfalls.md +0 -198
  255. package/framework/standards/frontend/blazor/state.md +0 -191
  256. package/framework/standards/frontend/design-system/aesthetic-direction.md +0 -213
  257. package/framework/standards/infrastructure/azure/azure.md +0 -624
  258. package/framework/standards/infrastructure/azure/bicep/bicep-patterns.md +0 -422
  259. package/framework/standards/infrastructure/azure/devops/azure-devops-setup.md +0 -516
  260. package/framework/standards/infrastructure/azure/devops/local-development.md +0 -520
  261. package/framework/standards/infrastructure/azure/services/functions.md +0 -486
  262. package/framework/standards/infrastructure/azure/services/service-bus.md +0 -459
  263. package/framework/standards/infrastructure/azure/services/storage.md +0 -407
  264. package/framework/standards/infrastructure/vercel/vercel-database.md +0 -106
  265. package/framework/standards/integration/api/graphql.md +0 -91
  266. package/framework/standards/integration/api/grpc.md +0 -114
  267. package/framework/standards/integration/api/rest-design.md +0 -95
  268. package/framework/standards/integration/event-driven/cqrs.md +0 -101
  269. package/framework/standards/integration/event-driven/event-sourcing.md +0 -124
  270. package/framework/standards/integration/event-driven/service-bus.md +0 -95
  271. package/framework/standards/observability/logging.md +0 -131
  272. package/framework/standards/observability/metrics.md +0 -121
  273. package/framework/standards/observability/monitoring.md +0 -114
  274. package/framework/standards/observability/tracing.md +0 -132
  275. package/framework/standards/workflows/parallel-execution.md +0 -112
  276. package/framework/standards/workflows/thread-management.md +0 -113
  277. package/framework/templates/code/dotnet/backend/service.cs +0 -139
  278. package/framework/templates/code/dotnet/contracts/Commands.cs +0 -74
  279. package/framework/templates/code/dotnet/contracts/Entities.cs +0 -25
  280. package/framework/templates/code/dotnet/contracts/Queries.cs +0 -74
  281. package/framework/templates/code/dotnet/contracts/api-contracts.cs +0 -173
  282. package/framework/templates/code/dotnet/contracts/contracts-level1.cs +0 -69
  283. package/framework/templates/code/dotnet/contracts/contracts-level2.cs +0 -86
  284. package/framework/templates/code/dotnet/contracts/contracts-level3.cs +0 -41
  285. package/framework/templates/code/dotnet/frontend/component.razor +0 -239
  286. package/framework/templates/infrastructure/azure/Dockerfile.example +0 -82
  287. package/framework/templates/infrastructure/azure/README.md +0 -286
  288. package/framework/templates/infrastructure/azure/app-insights.bicep +0 -63
  289. package/framework/templates/infrastructure/azure/app-service.bicep +0 -164
  290. package/framework/templates/infrastructure/azure/container-app-env.bicep +0 -49
  291. package/framework/templates/infrastructure/azure/container-app.bicep +0 -156
  292. package/framework/templates/infrastructure/azure/deploy-checklist.md +0 -426
  293. package/framework/templates/infrastructure/azure/deploy.ps1 +0 -229
  294. package/framework/templates/infrastructure/azure/deploy.sh +0 -208
  295. package/framework/templates/infrastructure/azure/key-vault.bicep +0 -91
  296. package/framework/templates/infrastructure/azure/main.bicep +0 -189
  297. package/framework/templates/infrastructure/azure/parameters.dev.json +0 -29
  298. package/framework/templates/infrastructure/azure/parameters.prod.json +0 -29
  299. package/framework/templates/infrastructure/azure/parameters.staging.json +0 -29
  300. package/framework/templates/infrastructure/azure/sql-database.bicep +0 -103
  301. package/framework/templates/infrastructure/azure/storage.bicep +0 -106
  302. package/framework/templates/infrastructure/github/actions/azure-auth/action.yml.hbs +0 -22
  303. package/framework/templates/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs +0 -61
  304. package/framework/templates/integrations/azure-identity-config.cs +0 -288
  305. package/framework/templates/project-structure/dotnet-ddd.md +0 -70
  306. package/framework/templates/saas/subscription.cs +0 -347
  307. package/framework/templates/saas/tenant.cs +0 -338
  308. package/framework/templates/ui/FluentDesignTheme.cs +0 -149
  309. package/framework/templates/ui/MudTheme.cs +0 -281
  310. package/framework/workflows/configs/nodejs-cli.json +0 -40
  311. package/src/commands/standards/context-budget.js +0 -89
  312. package/src/lib/standards/index.js +0 -7
  313. package/src/lib/standards/standards-context-injector.js +0 -302
  314. package/src/lib/validators/blazor/blazor-concurrency-analyzer.js +0 -316
  315. package/src/lib/validators/blazor/blazor-state-validator.js +0 -279
  316. package/src/lib/validators/blazor/blazor-validator.js +0 -369
  317. 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
 
@@ -171,10 +171,23 @@ function buildFrontmatter(agent, description) {
171
171
  return lines.join('\n');
172
172
  }
173
173
 
174
+ /** Maps agent group to task categories for routing hints in description */
175
+ const GROUP_TO_CATEGORIES = {
176
+ 'backend': 'Domain, Infrastructure, Application',
177
+ 'frontend': 'Presentation',
178
+ 'domain-analysis': 'Architecture, Cross-cutting',
179
+ 'testing': 'Tests',
180
+ 'infra': 'Infra, DevOps',
181
+ 'ai': 'AI, Automation',
182
+ };
183
+
174
184
  function buildDescription(agent) {
175
- const base = agent.teammate?.role ?? `Handles ${(agent.domains ?? []).join(', ')}`;
185
+ const role = agent.teammate?.role ?? `Handles ${(agent.domains ?? []).join(', ')}`;
186
+ const categories = GROUP_TO_CATEGORIES[agent.group];
187
+ const suffix = categories ? ` | Tasks: ${categories}` : '';
188
+ const full = `${role}${suffix}`;
176
189
  // Truncate to 200 chars for settings display
177
- return base.length > 200 ? base.slice(0, 197) + '...' : base;
190
+ return full.length > 200 ? full.slice(0, 197) + '...' : full;
178
191
  }
179
192
 
180
193
  /**
@@ -200,8 +213,16 @@ function buildBody(agent) {
200
213
  lines.push(`\n## Domains\n${agent.domains.map(d => `- ${d}`).join('\n')}`);
201
214
  }
202
215
  }
216
+
217
+ // Task routing — tells the agent which task categories it handles
218
+ const categories = GROUP_TO_CATEGORIES[agent.group];
219
+ if (categories) {
220
+ lines.push(`\n## Task Routing\nHandle tasks categorized as: ${categories}`);
221
+ }
222
+
223
+ // Key standards — @ references for upfront awareness
203
224
  if (agent.standards?.length) {
204
- lines.push(`\n## Standards to Reference\n${agent.standards.map(formatStandardRef).join('\n')}`);
225
+ lines.push(`\n## Key Standards\n${agent.standards.map(formatStandardRef).join('\n')}`);
205
226
  }
206
227
  return lines.join('\n');
207
228
  }
@@ -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.12.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',
@@ -119,6 +129,16 @@ Otherwise respond: {"ok": true}`
119
129
  }]
120
130
  },
121
131
 
132
+ // === PostToolUse: Agent ===
133
+ {
134
+ event: 'PostToolUse',
135
+ matcher: 'Agent',
136
+ hooks: [{
137
+ type: 'command',
138
+ command: 'node framework/hooks/claude-code/post-tool-use/agent-complete.js'
139
+ }]
140
+ },
141
+
122
142
  // === PostToolUse: Bash ===
123
143
  {
124
144
  event: 'PostToolUse',
@@ -128,14 +148,6 @@ Otherwise respond: {"ok": true}`
128
148
  type: 'command',
129
149
  command: 'node framework/hooks/claude-code/post-tool-use/dispatch.js'
130
150
  },
131
- {
132
- type: 'command',
133
- command: 'node framework/hooks/claude-code/post-tool-use/context-refresh.js'
134
- },
135
- {
136
- type: 'command',
137
- command: 'node framework/hooks/claude-code/post-tool-use/skill-reminder.js'
138
- },
139
151
  {
140
152
  type: 'command',
141
153
  command: 'node framework/hooks/claude-code/post-tool-use/validator-feedback.js'
@@ -174,16 +186,6 @@ Otherwise respond: {"ok": true}`
174
186
  }]
175
187
  },
176
188
 
177
- // === Notification ===
178
- {
179
- event: 'Notification',
180
- matcher: 'idle_prompt',
181
- hooks: [{
182
- type: 'command',
183
- command: 'node framework/hooks/claude-code/notification/approval-reminder.js'
184
- }]
185
- },
186
-
187
189
  // === TeammateIdle ===
188
190
  // Fires when an Agent Team teammate finishes and is about to go idle.
189
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
+ }