@polymorphism-tech/morph-spec 4.7.2 → 4.8.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (342) hide show
  1. package/LICENSE +1 -2
  2. package/README.md +379 -414
  3. package/bin/morph-spec.js +57 -394
  4. package/bin/validate.js +2 -26
  5. package/claude-plugin.json +2 -2
  6. package/docs/CHEATSHEET.md +203 -221
  7. package/docs/QUICKSTART.md +2 -8
  8. package/framework/CLAUDE.md +1 -1
  9. package/framework/commands/morph-proposal.md +3 -3
  10. package/framework/hooks/README.md +2 -5
  11. package/framework/hooks/claude-code/pre-tool-use/protect-readonly-files.js +4 -55
  12. package/framework/hooks/claude-code/session-start/inject-morph-context.js +20 -5
  13. package/framework/hooks/claude-code/statusline.py +6 -1
  14. package/framework/hooks/dev/check-sync-health.js +117 -0
  15. package/framework/hooks/dev/guard-version-numbers.js +57 -0
  16. package/framework/hooks/dev/sync-standards-registry.js +60 -0
  17. package/framework/hooks/dev/sync-template-registry.js +60 -0
  18. package/framework/hooks/dev/validate-skill-format.js +70 -0
  19. package/framework/hooks/dev/validate-standard-format.js +73 -0
  20. package/framework/hooks/shared/payload-utils.js +39 -0
  21. package/framework/hooks/shared/state-reader.js +25 -1
  22. package/framework/rules/morph-workflow.md +1 -1
  23. package/framework/skills/level-0-meta/morph-init/SKILL.md +216 -0
  24. package/framework/skills/level-0-meta/morph-replicate/SKILL.md +4 -4
  25. package/framework/skills/level-0-meta/tool-usage-guide/SKILL.md +4 -4
  26. package/framework/skills/level-0-meta/verification-before-completion/SKILL.md +1 -1
  27. package/framework/skills/level-1-workflows/phase-clarify/SKILL.md +192 -191
  28. package/framework/skills/level-1-workflows/phase-codebase-analysis/SKILL.md +181 -180
  29. package/framework/skills/level-1-workflows/phase-design/SKILL.md +339 -338
  30. package/framework/skills/level-1-workflows/phase-implement/SKILL.md +254 -253
  31. package/framework/skills/level-1-workflows/phase-setup/SKILL.md +168 -170
  32. package/framework/skills/level-1-workflows/phase-tasks/SKILL.md +284 -283
  33. package/framework/skills/level-1-workflows/phase-uiux/SKILL.md +246 -245
  34. package/framework/templates/examples/design-system-examples.md +1 -1
  35. package/framework/templates/ui/FluentDesignTheme.cs +1 -1
  36. package/framework/templates/ui/MudTheme.cs +1 -1
  37. package/framework/templates/ui/design-system.css +1 -1
  38. package/package.json +7 -5
  39. package/src/commands/agents/index.js +1 -2
  40. package/src/commands/index.js +13 -16
  41. package/src/commands/project/doctor.js +100 -14
  42. package/src/commands/project/index.js +7 -10
  43. package/src/commands/project/init.js +398 -528
  44. package/src/commands/project/install-plugin-cmd.js +28 -0
  45. package/src/commands/project/setup-infra-cmd.js +12 -0
  46. package/src/commands/project/tutorial.js +115 -0
  47. package/src/commands/state/approve.js +213 -221
  48. package/src/commands/state/index.js +0 -1
  49. package/src/commands/state/state.js +337 -365
  50. package/src/commands/templates/index.js +0 -4
  51. package/src/commands/trust/trust.js +1 -93
  52. package/src/commands/utils/index.js +1 -5
  53. package/src/commands/validation/index.js +1 -5
  54. package/src/core/registry/command-registry.js +11 -285
  55. package/src/core/state/state-manager.js +5 -2
  56. package/src/lib/detectors/index.js +81 -87
  57. package/src/lib/detectors/structure-detector.js +275 -273
  58. package/src/lib/generators/recap-generator.js +232 -225
  59. package/src/scripts/global-install.js +34 -0
  60. package/src/scripts/install-plugin.js +126 -0
  61. package/src/scripts/setup-infra.js +203 -0
  62. package/src/utils/agents-installer.js +10 -1
  63. package/src/utils/hooks-installer.js +66 -3
  64. package/.morph/.morphversion +0 -5
  65. package/.morph/analytics/threads-log.jsonl +0 -5
  66. package/.morph/config/config.json +0 -8
  67. package/.morph/framework/agents.json +0 -1815
  68. package/.morph/framework/hooks/README.md +0 -205
  69. package/.morph/framework/hooks/claude-code/notification/approval-reminder.js +0 -54
  70. package/.morph/framework/hooks/claude-code/post-tool-use/dispatch.js +0 -83
  71. package/.morph/framework/hooks/claude-code/post-tool-use/handle-tool-failure.js +0 -42
  72. package/.morph/framework/hooks/claude-code/pre-compact/save-morph-context.js +0 -61
  73. package/.morph/framework/hooks/claude-code/pre-tool-use/enforce-phase-writes.js +0 -71
  74. package/.morph/framework/hooks/claude-code/pre-tool-use/protect-readonly-files.js +0 -58
  75. package/.morph/framework/hooks/claude-code/pre-tool-use/protect-spec-files.js +0 -64
  76. package/.morph/framework/hooks/claude-code/session-start/inject-morph-context.js +0 -94
  77. package/.morph/framework/hooks/claude-code/statusline.py +0 -538
  78. package/.morph/framework/hooks/claude-code/statusline.sh +0 -7
  79. package/.morph/framework/hooks/claude-code/stop/validate-completion.js +0 -88
  80. package/.morph/framework/hooks/claude-code/user-prompt/enrich-prompt.js +0 -91
  81. package/.morph/framework/hooks/git/commit-msg/conventional-commits.sh +0 -33
  82. package/.morph/framework/hooks/git/pre-commit/agents.sh +0 -25
  83. package/.morph/framework/hooks/git/pre-commit/orchestrator.sh +0 -64
  84. package/.morph/framework/hooks/git/pre-commit/specs.sh +0 -50
  85. package/.morph/framework/hooks/git/pre-push/run-tests.sh +0 -44
  86. package/.morph/framework/hooks/shared/hook-response.js +0 -45
  87. package/.morph/framework/hooks/shared/phase-utils.js +0 -129
  88. package/.morph/framework/hooks/shared/state-reader.js +0 -138
  89. package/.morph/framework/hooks/shared/stdin-reader.js +0 -26
  90. package/.morph/framework/standards/STANDARDS.json +0 -933
  91. package/.morph/framework/standards/ai-agents/blazor-ui.md +0 -364
  92. package/.morph/framework/standards/ai-agents/production.md +0 -415
  93. package/.morph/framework/standards/ai-agents/setup.md +0 -418
  94. package/.morph/framework/standards/ai-agents/team-orchestration.md +0 -479
  95. package/.morph/framework/standards/ai-agents/workflows.md +0 -354
  96. package/.morph/framework/standards/architecture/ddd/aggregates.md +0 -120
  97. package/.morph/framework/standards/architecture/ddd/bounded-contexts.md +0 -105
  98. package/.morph/framework/standards/architecture/ddd/complexity-levels.md +0 -108
  99. package/.morph/framework/standards/architecture/ddd/entities.md +0 -99
  100. package/.morph/framework/standards/architecture/ddd/ubiquitous-language.md +0 -58
  101. package/.morph/framework/standards/architecture/ddd/value-objects.md +0 -124
  102. package/.morph/framework/standards/backend/api/minimal-api.md +0 -494
  103. package/.morph/framework/standards/backend/api/rest.md +0 -492
  104. package/.morph/framework/standards/backend/api/validation.md +0 -88
  105. package/.morph/framework/standards/backend/authentication/passkeys.md +0 -428
  106. package/.morph/framework/standards/backend/database/ef-core.md +0 -199
  107. package/.morph/framework/standards/backend/database/migrations.md +0 -393
  108. package/.morph/framework/standards/backend/database/postgresql/database.md +0 -352
  109. package/.morph/framework/standards/backend/database/repository-patterns.md +0 -528
  110. package/.morph/framework/standards/backend/database/vector-search-rag.md +0 -541
  111. package/.morph/framework/standards/backend/dotnet/async.md +0 -366
  112. package/.morph/framework/standards/backend/dotnet/core.md +0 -117
  113. package/.morph/framework/standards/backend/dotnet/di.md +0 -439
  114. package/.morph/framework/standards/backend/dotnet/program-cs-checklist.md +0 -92
  115. package/.morph/framework/standards/backend/integrations/asaas/asaas-api.md +0 -216
  116. package/.morph/framework/standards/backend/integrations/clerk/clerk-auth.md +0 -290
  117. package/.morph/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +0 -350
  118. package/.morph/framework/standards/backend/integrations/resend/resend-email.md +0 -385
  119. package/.morph/framework/standards/context/analytics.md +0 -96
  120. package/.morph/framework/standards/context/bundles.md +0 -110
  121. package/.morph/framework/standards/context/priming.md +0 -78
  122. package/.morph/framework/standards/core/architecture.md +0 -185
  123. package/.morph/framework/standards/core/coding.md +0 -214
  124. package/.morph/framework/standards/core/git-branching-strategy.md +0 -403
  125. package/.morph/framework/standards/core/git.md +0 -185
  126. package/.morph/framework/standards/core/testing.md +0 -295
  127. package/.morph/framework/standards/data/nosql/blob-storage.md +0 -102
  128. package/.morph/framework/standards/data/nosql/cache/redis.md +0 -97
  129. package/.morph/framework/standards/data/nosql/cosmos-db.md +0 -118
  130. package/.morph/framework/standards/data/vector-search/azure-ai-search.md +0 -121
  131. package/.morph/framework/standards/data/vector-search/rag-chunking.md +0 -104
  132. package/.morph/framework/standards/frontend/blazor/design-checklist.md +0 -222
  133. package/.morph/framework/standards/frontend/blazor/fluent-ui-setup.md +0 -595
  134. package/.morph/framework/standards/frontend/blazor/fluent-ui.md +0 -137
  135. package/.morph/framework/standards/frontend/blazor/html-conversion.md +0 -184
  136. package/.morph/framework/standards/frontend/blazor/lifecycle.md +0 -195
  137. package/.morph/framework/standards/frontend/blazor/pitfalls.md +0 -198
  138. package/.morph/framework/standards/frontend/blazor/state.md +0 -191
  139. package/.morph/framework/standards/frontend/design-system/animations.md +0 -151
  140. package/.morph/framework/standards/frontend/design-system/naming.md +0 -64
  141. package/.morph/framework/standards/frontend/nextjs/app-router.md +0 -123
  142. package/.morph/framework/standards/frontend/nextjs/components.md +0 -132
  143. package/.morph/framework/standards/frontend/nextjs/data-fetching.md +0 -126
  144. package/.morph/framework/standards/frontend/nextjs/forms.md +0 -128
  145. package/.morph/framework/standards/frontend/nextjs/naming-conventions.md +0 -67
  146. package/.morph/framework/standards/frontend/nextjs/nextjs-patterns.md +0 -215
  147. package/.morph/framework/standards/frontend/nextjs/project-structure.md +0 -102
  148. package/.morph/framework/standards/frontend/nextjs/state-management.md +0 -72
  149. package/.morph/framework/standards/frontend/nextjs/testing.md +0 -111
  150. package/.morph/framework/standards/infrastructure/azure/azure.md +0 -624
  151. package/.morph/framework/standards/infrastructure/azure/bicep/bicep-patterns.md +0 -422
  152. package/.morph/framework/standards/infrastructure/azure/devops/azure-devops-setup.md +0 -516
  153. package/.morph/framework/standards/infrastructure/azure/devops/local-development.md +0 -520
  154. package/.morph/framework/standards/infrastructure/azure/services/functions.md +0 -486
  155. package/.morph/framework/standards/infrastructure/azure/services/service-bus.md +0 -459
  156. package/.morph/framework/standards/infrastructure/azure/services/storage.md +0 -407
  157. package/.morph/framework/standards/infrastructure/docker/easypanel-deploy.md +0 -196
  158. package/.morph/framework/standards/infrastructure/supabase/mcp-setup.md +0 -252
  159. package/.morph/framework/standards/infrastructure/supabase/supabase-auth.md +0 -176
  160. package/.morph/framework/standards/infrastructure/supabase/supabase-pgvector.md +0 -169
  161. package/.morph/framework/standards/infrastructure/supabase/supabase-rls.md +0 -184
  162. package/.morph/framework/standards/infrastructure/supabase/supabase-storage.md +0 -153
  163. package/.morph/framework/standards/integration/api/graphql.md +0 -91
  164. package/.morph/framework/standards/integration/api/grpc.md +0 -114
  165. package/.morph/framework/standards/integration/api/rest-design.md +0 -95
  166. package/.morph/framework/standards/integration/event-driven/cqrs.md +0 -101
  167. package/.morph/framework/standards/integration/event-driven/event-sourcing.md +0 -124
  168. package/.morph/framework/standards/integration/event-driven/service-bus.md +0 -95
  169. package/.morph/framework/standards/integration/mcp/mcp-tools.md +0 -384
  170. package/.morph/framework/standards/observability/logging.md +0 -131
  171. package/.morph/framework/standards/observability/metrics.md +0 -121
  172. package/.morph/framework/standards/observability/monitoring.md +0 -114
  173. package/.morph/framework/standards/observability/tracing.md +0 -132
  174. package/.morph/framework/standards/workflows/parallel-execution.md +0 -112
  175. package/.morph/framework/standards/workflows/thread-management.md +0 -113
  176. package/.morph/framework/templates/.idea/morph-templates.xml +0 -92
  177. package/.morph/framework/templates/.vscode/morph-templates.code-snippets +0 -186
  178. package/.morph/framework/templates/IDE-SNIPPETS.md +0 -266
  179. package/.morph/framework/templates/README.md +0 -814
  180. package/.morph/framework/templates/REGISTRY.json +0 -1888
  181. package/.morph/framework/templates/code/dotnet/backend/repository.cs +0 -141
  182. package/.morph/framework/templates/code/dotnet/backend/service.cs +0 -139
  183. package/.morph/framework/templates/code/dotnet/contracts/Commands.cs +0 -74
  184. package/.morph/framework/templates/code/dotnet/contracts/Entities.cs +0 -25
  185. package/.morph/framework/templates/code/dotnet/contracts/Queries.cs +0 -74
  186. package/.morph/framework/templates/code/dotnet/contracts/README.md +0 -74
  187. package/.morph/framework/templates/code/dotnet/contracts/api-contracts.cs +0 -173
  188. package/.morph/framework/templates/code/dotnet/contracts/contracts-level1.cs +0 -69
  189. package/.morph/framework/templates/code/dotnet/contracts/contracts-level2.cs +0 -86
  190. package/.morph/framework/templates/code/dotnet/contracts/contracts-level3.cs +0 -41
  191. package/.morph/framework/templates/code/dotnet/database/migration.cs +0 -83
  192. package/.morph/framework/templates/code/dotnet/frontend/component.razor +0 -239
  193. package/.morph/framework/templates/code/dotnet/jobs/agent.cs +0 -163
  194. package/.morph/framework/templates/code/dotnet/jobs/job.cs +0 -171
  195. package/.morph/framework/templates/code/dotnet/test.cs +0 -239
  196. package/.morph/framework/templates/code/sql/rls-policy.sql +0 -57
  197. package/.morph/framework/templates/code/sql/supabase-migration.sql +0 -100
  198. package/.morph/framework/templates/code/sql/supabase-migration.template.sql +0 -113
  199. package/.morph/framework/templates/code/typescript/contracts.ts +0 -168
  200. package/.morph/framework/templates/context/CONTEXT-FEATURE.md +0 -276
  201. package/.morph/framework/templates/context/CONTEXT.md +0 -181
  202. package/.morph/framework/templates/docs/clarifications.md +0 -253
  203. package/.morph/framework/templates/docs/onboarding.md +0 -123
  204. package/.morph/framework/templates/docs/proposal.md +0 -182
  205. package/.morph/framework/templates/docs/schema-analysis.md +0 -119
  206. package/.morph/framework/templates/docs/spec.md +0 -198
  207. package/.morph/framework/templates/docs/ui-components.md +0 -124
  208. package/.morph/framework/templates/docs/ui-design-system.md +0 -76
  209. package/.morph/framework/templates/docs/ui-flows.md +0 -167
  210. package/.morph/framework/templates/docs/ui-mockups.md +0 -98
  211. package/.morph/framework/templates/docs/user-stories.md +0 -34
  212. package/.morph/framework/templates/examples/design-system-examples.md +0 -357
  213. package/.morph/framework/templates/examples/spec-examples.md +0 -90
  214. package/.morph/framework/templates/feature/decisions.md +0 -187
  215. package/.morph/framework/templates/feature/recap.md +0 -146
  216. package/.morph/framework/templates/feature/tasks.md +0 -199
  217. package/.morph/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +0 -43
  218. package/.morph/framework/templates/frontend/nextjs/client-component.tsx.hbs +0 -26
  219. package/.morph/framework/templates/frontend/nextjs/env.mjs.hbs +0 -32
  220. package/.morph/framework/templates/frontend/nextjs/feature-form.tsx.hbs +0 -56
  221. package/.morph/framework/templates/frontend/nextjs/page.tsx.hbs +0 -22
  222. package/.morph/framework/templates/frontend/nextjs/tsconfig.json.hbs +0 -26
  223. package/.morph/framework/templates/frontend/nextjs/use-feature.ts.hbs +0 -54
  224. package/.morph/framework/templates/infrastructure/azure/Dockerfile.example +0 -82
  225. package/.morph/framework/templates/infrastructure/azure/README.md +0 -286
  226. package/.morph/framework/templates/infrastructure/azure/app-insights.bicep +0 -63
  227. package/.morph/framework/templates/infrastructure/azure/app-service.bicep +0 -164
  228. package/.morph/framework/templates/infrastructure/azure/container-app-env.bicep +0 -49
  229. package/.morph/framework/templates/infrastructure/azure/container-app.bicep +0 -156
  230. package/.morph/framework/templates/infrastructure/azure/deploy-checklist.md +0 -426
  231. package/.morph/framework/templates/infrastructure/azure/deploy.ps1 +0 -229
  232. package/.morph/framework/templates/infrastructure/azure/deploy.sh +0 -208
  233. package/.morph/framework/templates/infrastructure/azure/key-vault.bicep +0 -91
  234. package/.morph/framework/templates/infrastructure/azure/main.bicep +0 -189
  235. package/.morph/framework/templates/infrastructure/azure/parameters.dev.json +0 -29
  236. package/.morph/framework/templates/infrastructure/azure/parameters.prod.json +0 -29
  237. package/.morph/framework/templates/infrastructure/azure/parameters.staging.json +0 -29
  238. package/.morph/framework/templates/infrastructure/azure/sql-database.bicep +0 -103
  239. package/.morph/framework/templates/infrastructure/azure/storage.bicep +0 -106
  240. package/.morph/framework/templates/infrastructure/docker/Dockerfile.template +0 -58
  241. package/.morph/framework/templates/infrastructure/docker/docker-compose.template.yml +0 -67
  242. package/.morph/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +0 -38
  243. package/.morph/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +0 -48
  244. package/.morph/framework/templates/infrastructure/docker/easypanel.template.json +0 -54
  245. package/.morph/framework/templates/infrastructure/github/README.md +0 -593
  246. package/.morph/framework/templates/infrastructure/github/actions/azure-auth/action.yml.hbs +0 -22
  247. package/.morph/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +0 -45
  248. package/.morph/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +0 -27
  249. package/.morph/framework/templates/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs +0 -61
  250. package/.morph/framework/templates/infrastructure/github/workflows/deploy-easypanel.yml.hbs +0 -31
  251. package/.morph/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +0 -59
  252. package/.morph/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +0 -39
  253. package/.morph/framework/templates/integrations/asaas-client.cs +0 -387
  254. package/.morph/framework/templates/integrations/asaas-webhook.cs +0 -351
  255. package/.morph/framework/templates/integrations/azure-identity-config.cs +0 -288
  256. package/.morph/framework/templates/integrations/clerk-config.cs +0 -258
  257. package/.morph/framework/templates/meta-prompts/fusion/fusion-agent.md +0 -76
  258. package/.morph/framework/templates/meta-prompts/fusion/fusion-aggregator.md +0 -100
  259. package/.morph/framework/templates/meta-prompts/hops/hop-retry.md +0 -78
  260. package/.morph/framework/templates/meta-prompts/hops/hop-validation.md +0 -97
  261. package/.morph/framework/templates/meta-prompts/hops/hop-wrapper.md +0 -36
  262. package/.morph/framework/templates/meta-prompts/parallel-workers/parallel-coordinator.md +0 -113
  263. package/.morph/framework/templates/meta-prompts/parallel-workers/parallel-worker.md +0 -80
  264. package/.morph/framework/templates/meta-prompts/squad-leaders/backend-squad.md +0 -90
  265. package/.morph/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +0 -126
  266. package/.morph/framework/templates/meta-prompts/squad-leaders/squad-leader.md +0 -43
  267. package/.morph/framework/templates/meta-prompts/validators/checkpoint-validator.md +0 -107
  268. package/.morph/framework/templates/meta-prompts/validators/pre-commit-validator.md +0 -95
  269. package/.morph/framework/templates/project-structure/dotnet-ddd.md +0 -70
  270. package/.morph/framework/templates/saas/subscription.cs +0 -347
  271. package/.morph/framework/templates/saas/tenant.cs +0 -338
  272. package/.morph/framework/templates/state.template.json +0 -17
  273. package/.morph/framework/templates/ui/FluentDesignTheme.cs +0 -149
  274. package/.morph/framework/templates/ui/MudTheme.cs +0 -281
  275. package/.morph/framework/templates/ui/design-system.css +0 -226
  276. package/.morph/logs/tool-failures.log +0 -17
  277. package/.morph/memory/pre-compact-2026-02-24T17-43-30-049Z.json +0 -16
  278. package/.morph/plans/eager-watching-bunny.md +0 -105
  279. package/.morph/plans/temporal-seeking-nebula.md +0 -45
  280. package/.morph/state.json +0 -48
  281. package/CLAUDE.md +0 -77
  282. package/docs/ARCHITECTURE.md +0 -331
  283. package/docs/COMMAND-FLOWS.md +0 -368
  284. package/docs/claude-alignment-report.md +0 -137
  285. package/docs/examples/order-management/contracts.cs +0 -84
  286. package/docs/examples/order-management/proposal.md +0 -24
  287. package/docs/examples/order-management/spec.md +0 -162
  288. package/docs/plans/2026-02-22-claude-docs-morph-alignment-analysis.md +0 -512
  289. package/docs/plans/2026-02-22-claude-settings.md +0 -515
  290. package/docs/plans/2026-02-22-morph-cc-alignment-impl.md +0 -728
  291. package/docs/plans/2026-02-22-morph-spec-next.md +0 -478
  292. package/docs/plans/2026-02-22-native-alignment-design.md +0 -199
  293. package/docs/plans/2026-02-22-native-alignment-impl.md +0 -925
  294. package/docs/plans/2026-02-22-native-enrichment-design.md +0 -244
  295. package/docs/plans/2026-02-22-native-enrichment.md +0 -735
  296. package/docs/plans/2026-02-23-ddd-architecture-refactor.md +0 -1153
  297. package/docs/plans/2026-02-23-ddd-nextsteps.md +0 -682
  298. package/docs/plans/2026-02-23-infra-architect-refactor.md +0 -437
  299. package/docs/plans/2026-02-23-nextjs-code-review-design.md +0 -156
  300. package/docs/plans/2026-02-23-nextjs-code-review-impl.md +0 -1254
  301. package/docs/plans/2026-02-23-nextjs-standards-design.md +0 -149
  302. package/docs/plans/2026-02-23-nextjs-standards-impl.md +0 -1846
  303. package/scripts/generate-refs.js +0 -336
  304. package/scripts/generate-standards-registry.js +0 -44
  305. package/scripts/scan-nextjs.mjs +0 -169
  306. package/scripts/validate-real.mjs +0 -255
  307. package/src/commands/feature/create-story.js +0 -362
  308. package/src/commands/feature/index.js +0 -6
  309. package/src/commands/feature/shard-spec.js +0 -225
  310. package/src/commands/feature/sprint-status.js +0 -250
  311. package/src/commands/generation/generate-onboarding.js +0 -169
  312. package/src/commands/generation/generate.js +0 -276
  313. package/src/commands/generation/index.js +0 -5
  314. package/src/commands/learning/capture-pattern.js +0 -121
  315. package/src/commands/learning/index.js +0 -5
  316. package/src/commands/learning/search-patterns.js +0 -126
  317. package/src/commands/mcp/mcp.js +0 -102
  318. package/src/commands/project/changes.js +0 -66
  319. package/src/commands/project/cost.js +0 -179
  320. package/src/commands/project/diff.js +0 -278
  321. package/src/commands/project/revert.js +0 -173
  322. package/src/commands/project/standards.js +0 -80
  323. package/src/commands/project/sync.js +0 -167
  324. package/src/commands/project/update-agents.js +0 -23
  325. package/src/commands/state/rollback-phase.js +0 -185
  326. package/src/commands/templates/template-customize.js +0 -87
  327. package/src/commands/templates/template-list.js +0 -114
  328. package/src/commands/templates/template-show.js +0 -129
  329. package/src/commands/templates/template-validate.js +0 -91
  330. package/src/commands/utils/troubleshoot.js +0 -222
  331. package/src/commands/validation/analyze-blazor-concurrency.js +0 -193
  332. package/src/commands/validation/lint-fluent.js +0 -352
  333. package/src/commands/validation/validate-blazor-state.js +0 -210
  334. package/src/commands/validation/validate-blazor.js +0 -156
  335. package/src/commands/validation/validate-css.js +0 -84
  336. package/src/lib/detectors/conversation-analyzer.js +0 -163
  337. package/src/lib/learning/index.js +0 -7
  338. package/src/lib/learning/learning-system.js +0 -520
  339. package/src/lib/troubleshooting/index.js +0 -8
  340. package/src/lib/troubleshooting/troubleshoot-grep.js +0 -198
  341. package/src/lib/troubleshooting/troubleshoot-index.js +0 -144
  342. package/src/llm/environment-detector.js +0 -43
@@ -1,528 +1,398 @@
1
- import { join } from 'path';
2
- import fs from 'fs-extra';
3
- import ora from 'ora';
4
- import chalk from 'chalk';
5
- import { logger } from '../../utils/logger.js';
6
- import {
7
- copyDirectory,
8
- copyFile,
9
- pathExists,
10
- readJson,
11
- writeJson,
12
- ensureDir,
13
- writeFile,
14
- readFile,
15
- updateGitignore
16
- } from '../../utils/file-copier.js';
17
- import { saveProjectMorphVersion, getInstalledCLIVersion } from '../../utils/version-checker.js';
18
- import { installClaudeHooks, installGlobalStatusline } from '../../utils/claude-settings-manager.js';
19
- import { installSkills } from '../../utils/skills-installer.js';
20
- import { installAgents, installDomainAgents } from '../../utils/agents-installer.js';
21
- import inquirer from 'inquirer';
22
- import { detectProject } from '../../lib/detectors/index.js';
23
- import { detectClaudeConfig, mapMcpsToPhases, formatConfigSummary } from '../../lib/detectors/claude-config-detector.js';
24
- import { generateSettings, saveIntegrations } from '../../lib/generators/settings-generator.js';
25
- import {
26
- orchestrateMcpSetup,
27
- installAutoMcps,
28
- installMcpWithCredentials,
29
- generateSetupInstructions,
30
- formatMcpStatusTable
31
- } from '../../lib/installers/mcp-installer.js';
32
-
33
- export async function initCommand(options) {
34
- const targetPath = options.path || process.cwd();
35
- const claudeMdPath = join(import.meta.dirname, '..', '..', '..', 'framework', 'CLAUDE.md');
36
-
37
- logger.header('MORPH-SPEC Framework Installation');
38
- logger.dim(`Target: ${targetPath}`);
39
- logger.blank();
40
-
41
- // Check if already initialized
42
- const morphPath = join(targetPath, '.morph');
43
- if (await pathExists(morphPath)) {
44
- if (!options.force) {
45
- logger.warn('MORPH already initialized in this directory.');
46
- logger.dim('Use --force to overwrite existing installation.');
47
- process.exit(1);
48
- }
49
- logger.warn('Overwriting existing MORPH installation...');
50
- }
51
-
52
- const spinner = ora('Installing MORPH-SPEC...').start();
53
-
54
- try {
55
- // 1. Copy CLAUDE.md
56
- spinner.text = 'Copying CLAUDE.md...';
57
- const claudeMdDest = join(targetPath, 'CLAUDE.md');
58
-
59
- // Backup existing CLAUDE.md if not from MORPH
60
- if (await pathExists(claudeMdDest)) {
61
- const existingContent = await readFile(claudeMdDest);
62
- if (!existingContent.includes('MORPH-SPEC')) {
63
- await copyFile(claudeMdDest, `${claudeMdDest}.backup`);
64
- logger.dim('Backed up existing CLAUDE.md');
65
- }
66
- }
67
- await copyFile(claudeMdPath, claudeMdDest);
68
-
69
- // 2. Create .morph directory structure
70
- spinner.text = 'Creating .morph structure...';
71
- const configDir = join(morphPath, 'config');
72
- const frameworkDestDir = join(morphPath, 'framework');
73
- const contextDir = join(morphPath, 'context');
74
- const featuresDir = join(morphPath, 'features');
75
- await ensureDir(contextDir);
76
- await ensureDir(featuresDir);
77
- await ensureDir(configDir);
78
- await ensureDir(frameworkDestDir);
79
-
80
- // 3. Create config.json
81
- spinner.text = 'Generating config.json...';
82
- const configPath = join(configDir, 'config.json');
83
- const dirName = targetPath.split(/[\\/]/).pop();
84
-
85
- const config = {
86
- framework: 'global',
87
- frameworkVersion: getInstalledCLIVersion(),
88
- project: {
89
- name: dirName,
90
- architecture: 'unknown'
91
- }
92
- };
93
-
94
- await writeJson(configPath, config);
95
-
96
- // 4. Create context/README.md
97
- spinner.text = 'Creating context README...';
98
- const contextReadme = join(contextDir, 'README.md');
99
- const readmeContent = `# ${dirName} - Project Context
100
-
101
- ## Overview
102
-
103
- This file describes your project context for MORPH-SPEC agents.
104
-
105
- ## Stack
106
-
107
- Edit this file to describe your project context.
108
-
109
- ## Technologies
110
-
111
- (To be detected)
112
-
113
- ## Architecture
114
-
115
- (To be detected)
116
- `;
117
- await writeFile(contextReadme, readmeContent);
118
-
119
- // 5. Copy framework templates (project-local overrides start from framework defaults)
120
- const frameworkTemplatesSrc = join(import.meta.dirname, '..', '..', '..', 'framework', 'templates');
121
- const templatesDest = join(frameworkDestDir, 'templates');
122
- let templatesCopied = false;
123
- if (await pathExists(frameworkTemplatesSrc)) {
124
- await copyDirectory(frameworkTemplatesSrc, templatesDest);
125
- templatesCopied = true;
126
- } else {
127
- await ensureDir(templatesDest);
128
- }
129
-
130
- // 6b. Copy framework standards hierarchy (universal standards)
131
- spinner.text = 'Copying framework standards hierarchy...';
132
- const frameworkStandardsSrc = join(import.meta.dirname, '..', '..', '..', 'framework', 'standards');
133
- const frameworkStandardsDest = join(frameworkDestDir, 'standards');
134
- if (await pathExists(frameworkStandardsSrc)) {
135
- // Copy entire hierarchy (core/, backend/, frontend/, infrastructure/)
136
- await copyDirectory(frameworkStandardsSrc, frameworkStandardsDest);
137
- logger.dim(' ✓ Copied framework standards: core/, backend/, frontend/, infrastructure/');
138
- }
139
-
140
- // 6c. Copy hooks to .morph/framework/hooks/ (required for hook commands at runtime)
141
- spinner.text = 'Copying hooks...';
142
- const hooksSrc = join(import.meta.dirname, '..', '..', '..', 'framework', 'hooks');
143
- const hooksDest = join(frameworkDestDir, 'hooks');
144
- if (await pathExists(hooksSrc)) {
145
- await copyDirectory(hooksSrc, hooksDest);
146
- }
147
-
148
- // 7. Copy agents.json (sourced from framework/ — canonical single source of truth)
149
- spinner.text = 'Copying agents configuration...';
150
- const agentsSrc = join(import.meta.dirname, '..', '..', '..', 'framework', 'agents.json');
151
- const agentsDest = join(frameworkDestDir, 'agents.json');
152
- if (await pathExists(agentsSrc)) {
153
- await copyFile(agentsSrc, agentsDest);
154
- }
155
-
156
- // 8. Copy .claude commands and install skills
157
- // Source: framework/ (canonical for all stacks)
158
- spinner.text = 'Setting up Claude Code integration...';
159
- const frameworkDir = join(import.meta.dirname, '..', '..', '..', 'framework');
160
- const claudeDest = join(targetPath, '.claude');
161
-
162
- let commandsCopied = false;
163
-
164
- // Copy commands directory (slash commands): framework/commands/ → .claude/commands/
165
- const commandsSrc = join(frameworkDir, 'commands');
166
- const commandsDest = join(claudeDest, 'commands');
167
- if (await pathExists(commandsSrc)) {
168
- await copyDirectory(commandsSrc, commandsDest);
169
- commandsCopied = true;
170
- } else {
171
- logger.warn(' ⚠ framework/commands/ source missing commands not installed');
172
- }
173
-
174
- // 9a. Install path-scoped rules to .claude/rules/ (native Claude Code pattern)
175
- spinner.text = 'Installing path-scoped rules to .claude/rules/...';
176
- const rulesSrc = join(frameworkDir, 'rules');
177
- const rulesDest = join(claudeDest, 'rules');
178
- let rulesCopied = false;
179
- if (await pathExists(rulesSrc)) {
180
- await copyDirectory(rulesSrc, rulesDest);
181
- rulesCopied = true;
182
- }
183
-
184
- // 9b. Install morph skills to .claude/skills/ for native Claude Code discovery
185
- spinner.text = 'Installing morph skills to .claude/skills/...';
186
- await installSkills(targetPath);
187
-
188
- // 9b2. Install tier-1/2 agents as native Claude Code subagents in .claude/agents/
189
- spinner.text = 'Installing native subagents to .claude/agents/...';
190
- const detectedStackForAgents = config.project.stack ?? null;
191
- await installAgents(targetPath, frameworkDir, { projectStack: detectedStackForAgents });
192
-
193
- // 9b2b. Install level-2 domain agents as native Claude Code subagents in .claude/agents/
194
- await installDomainAgents(targetPath, frameworkDir);
195
-
196
- // 9b3. Install runtime CLAUDE.md to .claude/CLAUDE.md (Claude Code runtime instructions)
197
- spinner.text = 'Installing .claude/CLAUDE.md...';
198
- const runtimeClaudeMdSrc = join(frameworkDir, 'CLAUDE.md');
199
- const runtimeClaudeMdDest = join(claudeDest, 'CLAUDE.md');
200
- if (await pathExists(runtimeClaudeMdSrc)) {
201
- await copyFile(runtimeClaudeMdSrc, runtimeClaudeMdDest);
202
- }
203
-
204
- // 9c. Install statusline globally to ~/.claude/ (applies to all Claude Code sessions)
205
- spinner.text = 'Installing statusline globally to ~/.claude/...';
206
- const HOOKS_SRC = join(import.meta.dirname, '..', '..', '..', 'framework', 'hooks', 'claude-code');
207
- try {
208
- await installGlobalStatusline(HOOKS_SRC);
209
- } catch {
210
- // Non-critical: global dir may not be writable in all environments
211
- logger.dim(' ⚠ Could not install statusline globally (non-critical)');
212
- }
213
-
214
- // 9d. Install/update Claude Code hooks in .claude/settings.local.json
215
- spinner.text = 'Installing Claude Code hooks...';
216
- const hooksResult = await installClaudeHooks(targetPath);
217
-
218
- // 10. Save version info
219
- spinner.text = 'Saving version info...';
220
- const cliVersion = getInstalledCLIVersion();
221
- await saveProjectMorphVersion(targetPath, cliVersion);
222
-
223
- // 11. Update .gitignore
224
- spinner.text = 'Updating .gitignore...';
225
- await updateGitignore(targetPath);
226
-
227
- // 11b. Detect Claude Code environment (plugins, MCPs, skills)
228
- spinner.text = 'Detecting Claude Code environment...';
229
- let claudeConfigDetected = null;
230
- let integrationsCreated = false;
231
- try {
232
- claudeConfigDetected = await detectClaudeConfig(targetPath);
233
- const hasIntegrations = claudeConfigDetected.plugins.length > 0
234
- || claudeConfigDetected.mcpServers.length > 0
235
- || claudeConfigDetected.superpowers.installed;
236
-
237
- if (hasIntegrations) {
238
- spinner.stop();
239
- logger.blank();
240
- logger.header('Claude Code Environment Detected');
241
-
242
- const summary = formatConfigSummary(claudeConfigDetected);
243
- if (summary) {
244
- logger.info(summary);
245
- }
246
-
247
- // Show MCP-to-phase mapping
248
- if (claudeConfigDetected.mcpServers.length > 0) {
249
- const phaseMap = mapMcpsToPhases(claudeConfigDetected.mcpServers);
250
- logger.blank();
251
- logger.dim('MCP usage by phase:');
252
- for (const [phase, mcps] of Object.entries(phaseMap)) {
253
- if (mcps.length > 0) {
254
- logger.dim(` ${phase}: ${mcps.map(m => m.name).join(', ')}`);
255
- }
256
- }
257
- }
258
-
259
- logger.blank();
260
- const { saveIntegrationsChoice } = await inquirer.prompt([{
261
- type: 'confirm',
262
- name: 'saveIntegrationsChoice',
263
- message: 'Save detected integrations and generate optimized settings?',
264
- default: true
265
- }]);
266
-
267
- if (saveIntegrationsChoice) {
268
- spinner.start('Saving integrations...');
269
- await saveIntegrations(targetPath, claudeConfigDetected);
270
- await generateSettings(targetPath, claudeConfigDetected, config);
271
- integrationsCreated = true;
272
- spinner.succeed('Integrations saved to .morph/config/integrations.json');
273
- } else {
274
- spinner.start('Continuing...');
275
- }
276
- }
277
- } catch (error) {
278
- // Non-fatal: continue without integrations
279
- logger.dim(` Claude config detection skipped: ${error.message}`);
280
- }
281
-
282
- // 11c. Stack detection (moved before MCP setup so we know the stack)
283
- spinner.text = 'Detecting project stack...';
284
- let detectedStack = 'unknown';
285
- const hasProjectFiles = await pathExists(join(targetPath, 'package.json'))
286
- || await pathExists(join(targetPath, 'src'))
287
- || (await fs.readdir(targetPath)).some(f => f.endsWith('.csproj'));
288
-
289
- if (hasProjectFiles) {
290
- try {
291
- const quickResults = await detectProject(targetPath, { conversation: false, generateStandards: false });
292
- const structure = quickResults.structure;
293
-
294
- if (structure?.stack && structure.stack !== 'unknown') {
295
- detectedStack = structure.stack;
296
-
297
- // Persist detected stack to config.json
298
- if (structure?.stack && structure.stack !== 'unknown') {
299
- config.project.stack = structure.stack;
300
- }
301
- if (structure?.architecture && structure.architecture !== 'unknown') {
302
- config.project.architecture = structure.architecture;
303
- }
304
- if (structure?.uiLibrary) {
305
- config.project.uiLibrary = structure.uiLibrary;
306
- }
307
- await writeJson(configPath, config);
308
-
309
- spinner.stop();
310
- logger.blank();
311
- logger.header('Existing Project Detected');
312
- logger.info(`Stack detected: ${structure.stack}`);
313
- if (structure?.architecture) logger.dim(`Architecture: ${structure.architecture}`);
314
- if (structure?.uiLibrary) logger.dim(`UI Library: ${structure.uiLibrary}`);
315
-
316
- const { standardsChoice } = await inquirer.prompt([{
317
- type: 'list',
318
- name: 'standardsChoice',
319
- message: 'How should morph-spec handle your project standards?',
320
- choices: [
321
- { name: 'Keep morph-spec defaults (recommended)', value: 'morph-spec' },
322
- { name: 'Detect project-specific standards', value: 'detect' }
323
- ]
324
- }]);
325
-
326
- if (standardsChoice === 'detect') {
327
- spinner.start('Generating project-specific standards...');
328
- const fullResults = await detectProject(targetPath, { conversation: false });
329
- const inferredPath = join(contextDir, 'standards.md');
330
- await writeFile(inferredPath, fullResults.inferred.markdown);
331
- spinner.succeed('Generated .morph/context/standards.md');
332
- logger.dim('Review and edit .morph/context/standards.md as needed.');
333
- }
334
-
335
- spinner.start('Continuing...');
336
- }
337
- } catch (error) {
338
- logger.dim(` Stack detection skipped: ${error.message}`);
339
- }
340
- }
341
-
342
- // 11d. MCP Auto-Setup
343
- let mcpSetupResult = null;
344
- if (!options.skipMcp) {
345
- try {
346
- spinner.stop();
347
- const existingMcps = claudeConfigDetected?.mcpServers || [];
348
- const orchestration = orchestrateMcpSetup(targetPath, detectedStack, existingMcps);
349
-
350
- const autoNames = Object.keys(orchestration.autoInstallable);
351
- const manualNames = Object.keys(orchestration.needsManualSetup);
352
- const hasAutoMcps = autoNames.length > 0;
353
- const hasManualMcps = manualNames.length > 0;
354
-
355
- if (hasAutoMcps || hasManualMcps) {
356
- logger.blank();
357
- logger.header('MCP Server Setup');
358
-
359
- // Auto-install prompt
360
- let autoInstalled = {};
361
- if (hasAutoMcps) {
362
- const { installAuto } = await inquirer.prompt([{
363
- type: 'confirm',
364
- name: 'installAuto',
365
- message: `Install recommended MCP servers? (${autoNames.join(', ')})`,
366
- default: true
367
- }]);
368
-
369
- if (installAuto) {
370
- spinner.start('Installing MCP servers...');
371
- const result = await installAutoMcps(targetPath, orchestration.autoInstallable);
372
- spinner.succeed(`Installed ${result.added.length} MCP server(s)`);
373
- for (const name of result.added) {
374
- autoInstalled[name] = orchestration.autoInstallable[name];
375
- }
376
- }
377
- }
378
-
379
- // Credential MCPs inline setup or instructions
380
- const manualInstalled = {};
381
- if (hasManualMcps) {
382
- for (const [name, entry] of Object.entries(orchestration.needsManualSetup)) {
383
- logger.blank();
384
-
385
- // Show warnings
386
- for (const warning of entry.install.warnings || []) {
387
- logger.warn(` ${warning}`);
388
- }
389
-
390
- const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
391
- const { setupNow } = await inquirer.prompt([{
392
- type: 'confirm',
393
- name: 'setupNow',
394
- message: `Set up ${capitalizedName} MCP now? (${entry.usage})`,
395
- default: false
396
- }]);
397
-
398
- if (setupNow) {
399
- // Collect credentials
400
- const credentialValues = {};
401
- for (const cred of entry.install.credentials) {
402
- const { value } = await inquirer.prompt([{
403
- type: cred.secret ? 'password' : 'input',
404
- name: 'value',
405
- message: `${cred.name}:`,
406
- mask: cred.secret ? '*' : undefined
407
- }]);
408
- credentialValues[cred.envVar] = value;
409
- }
410
-
411
- spinner.start(`Configuring ${name}...`);
412
- await installMcpWithCredentials(targetPath, name, entry, credentialValues);
413
- spinner.succeed(`${capitalizedName} MCP configured`);
414
- manualInstalled[name] = entry;
415
- } else {
416
- // Show setup instructions
417
- const instructions = generateSetupInstructions(name, entry);
418
- logger.blank();
419
- logger.dim(' Add to .claude/settings.local.json → mcpServers:');
420
- logger.dim(' ' + '─'.repeat(55));
421
- for (const line of instructions.configSnippet.split('\n')) {
422
- logger.dim(` ${line}`);
423
- }
424
- logger.dim(' ' + '─'.repeat(55));
425
-
426
- for (const cred of instructions.credentialUrls) {
427
- logger.dim(` Get ${cred.name}: ${cred.helpUrl}`);
428
- }
429
- logger.dim(` Or run later: ${instructions.cliCommand}`);
430
- }
431
- }
432
- }
433
-
434
- // Summary table
435
- const justInstalled = { ...autoInstalled, ...manualInstalled };
436
- const statusRows = formatMcpStatusTable(orchestration, justInstalled);
437
-
438
- if (statusRows.length > 0) {
439
- logger.blank();
440
- logger.info('MCP Servers');
441
- logger.dim('─'.repeat(60));
442
-
443
- const STATUS_ICONS = {
444
- installed: '✓',
445
- available: '○',
446
- already_configured: '✓',
447
- needs_setup: '⚠',
448
- prereq_missing: '✗',
449
- not_relevant: '─'
450
- };
451
-
452
- for (const row of statusRows) {
453
- const icon = STATUS_ICONS[row.status] || '?';
454
- const statusLabel = row.status.replace(/_/g, ' ');
455
- logger.dim(` ${icon} ${row.name.padEnd(15)} ${statusLabel.padEnd(20)} ${row.detail}`);
456
- }
457
- }
458
-
459
- mcpSetupResult = { autoInstalled, manualInstalled, orchestration };
460
- }
461
- } catch (error) {
462
- logger.dim(` MCP setup skipped: ${error.message}`);
463
- }
464
- } else {
465
- logger.dim('\nSkipped MCP setup (--skip-mcp flag)');
466
- }
467
-
468
- spinner.succeed('MORPH-SPEC installed successfully!');
469
-
470
- // Show next steps
471
- logger.blank();
472
- logger.success(`MORPH-SPEC v${cliVersion} installed successfully!`);
473
- logger.blank();
474
- logger.header('Next Steps');
475
-
476
- logger.step(1, 'Review .morph/config/config.json');
477
- logger.step(2, 'Open project in VS Code with Claude Code');
478
- logger.step(3, 'Start your first feature:');
479
- logger.blank();
480
- logger.box([
481
- 'Ask Claude Code to implement a feature'
482
- ]);
483
- logger.blank();
484
-
485
- logger.info('Files installed:');
486
- logger.dim(` ✓ CLAUDE.md`);
487
- logger.dim(` ✓ .morph/config/ (config.json)`);
488
- logger.dim(` ✓ .morph/framework/ (agents.json, standards/, templates/, hooks/)`);
489
- logger.dim(` ✓ .morph/context/ (project context)`);
490
- logger.dim(` ✓ .morph/features/ (feature outputs)`);
491
- if (commandsCopied) {
492
- logger.dim(` ✓ .claude/commands/ (slash commands)`);
493
- }
494
- if (rulesCopied) {
495
- logger.dim(` ✓ .claude/rules/ (5 path-scoped rules)`);
496
- }
497
- logger.dim(` ✓ .claude/settings.local.json (${hooksResult.installed} hooks installed)`);
498
- if (integrationsCreated) {
499
- logger.dim(` ✓ .morph/config/integrations.json (detected plugins & MCPs)`);
500
- }
501
- if (mcpSetupResult) {
502
- const autoCount = Object.keys(mcpSetupResult.autoInstalled).length;
503
- const manualCount = Object.keys(mcpSetupResult.manualInstalled).length;
504
- if (autoCount + manualCount > 0) {
505
- logger.dim(` ✓ MCP servers (${autoCount + manualCount} configured)`);
506
- }
507
- }
508
-
509
- logger.dim(' ✓ .claude/skills/ (installed as skill directories)');
510
- logger.dim(' ✓ .claude/agents/ (native subagents installed)');
511
- logger.dim(' ✓ ~/.claude/statusline.sh (global statusline installed)');
512
-
513
- logger.blank();
514
-
515
- // Suggest tutorial for first-time users
516
- if (integrationsCreated) {
517
- logger.blank();
518
- logger.info('First time using morph-spec? Run `morph-spec tutorial` to get started.');
519
- }
520
-
521
- logger.blank();
522
-
523
- } catch (error) {
524
- spinner.fail('Installation failed');
525
- logger.error(error.message);
526
- process.exit(1);
527
- }
528
- }
1
+ import { join } from 'path';
2
+ import { homedir } from 'os';
3
+ import fs from 'fs-extra';
4
+ import ora from 'ora';
5
+ import { logger } from '../../utils/logger.js';
6
+ import {
7
+ pathExists,
8
+ readJson,
9
+ writeJson,
10
+ writeFile
11
+ } from '../../utils/file-copier.js';
12
+ import { getInstalledCLIVersion } from '../../utils/version-checker.js';
13
+ import { installClaudeHooks } from '../../utils/claude-settings-manager.js';
14
+ import inquirer from 'inquirer';
15
+ import { detectProject } from '../../lib/detectors/index.js';
16
+ import { detectClaudeConfig, mapMcpsToPhases, formatConfigSummary } from '../../lib/detectors/claude-config-detector.js';
17
+ import { generateSettings, saveIntegrations } from '../../lib/generators/settings-generator.js';
18
+ import {
19
+ orchestrateMcpSetup,
20
+ installAutoMcps,
21
+ installMcpWithCredentials,
22
+ generateSetupInstructions,
23
+ formatMcpStatusTable
24
+ } from '../../lib/installers/mcp-installer.js';
25
+ import { setupInfra } from '../../scripts/setup-infra.js';
26
+
27
+ export async function initCommand(options) {
28
+ const targetPath = options.path || process.cwd();
29
+
30
+ logger.header('MORPH-SPEC Framework Installation');
31
+ logger.dim(`Target: ${targetPath}`);
32
+ logger.blank();
33
+
34
+ // Check if already initialized
35
+ const morphPath = join(targetPath, '.morph');
36
+ if (await pathExists(morphPath)) {
37
+ if (!options.force) {
38
+ logger.warn('MORPH already initialized in this directory.');
39
+ logger.dim('Use --force to overwrite existing installation.');
40
+ process.exit(1);
41
+ }
42
+ logger.warn('Overwriting existing MORPH installation...');
43
+ }
44
+
45
+ const spinner = ora('Installing MORPH-SPEC...').start();
46
+
47
+ try {
48
+
49
+ // Steps 1-10: Infrastructure (headless, no prompts)
50
+ spinner.stop();
51
+ const infraResult = await setupInfra(targetPath);
52
+ spinner.start('Continuing...');
53
+
54
+ // Derive display variables from what setupInfra installed
55
+ const cliVersion = getInstalledCLIVersion();
56
+ const commandsCopied = await pathExists(join(targetPath, '.claude', 'commands'));
57
+ const rulesCopied = await pathExists(join(targetPath, '.claude', 'rules'));
58
+ // Re-run installClaudeHooks to get the result object (idempotent — hooks already installed)
59
+ const hooksResult = await installClaudeHooks(targetPath);
60
+
61
+ // Re-derive config path for stack detection updates
62
+ const configDir = join(morphPath, 'config');
63
+ const configPath = join(configDir, 'config.json');
64
+ const contextDir = join(morphPath, 'context');
65
+
66
+ // Read config written by setupInfra so stack detection can update it
67
+ let config = (await pathExists(configPath)) ? await readJson(configPath) : { project: {} };
68
+ if (!config.project) config.project = {};
69
+
70
+ // 11b. Detect Claude Code environment (plugins, MCPs, skills)
71
+ spinner.text = 'Detecting Claude Code environment...';
72
+ let claudeConfigDetected = null;
73
+ let integrationsCreated = false;
74
+ try {
75
+ claudeConfigDetected = await detectClaudeConfig(targetPath);
76
+ const hasIntegrations = claudeConfigDetected.plugins.length > 0
77
+ || claudeConfigDetected.mcpServers.length > 0
78
+ || claudeConfigDetected.superpowers.installed;
79
+
80
+ if (hasIntegrations) {
81
+ spinner.stop();
82
+ logger.blank();
83
+ logger.header('Claude Code Environment Detected');
84
+
85
+ const summary = formatConfigSummary(claudeConfigDetected);
86
+ if (summary) {
87
+ logger.info(summary);
88
+ }
89
+
90
+ // Show MCP-to-phase mapping
91
+ if (claudeConfigDetected.mcpServers.length > 0) {
92
+ const phaseMap = mapMcpsToPhases(claudeConfigDetected.mcpServers);
93
+ logger.blank();
94
+ logger.dim('MCP usage by phase:');
95
+ for (const [phase, mcps] of Object.entries(phaseMap)) {
96
+ if (mcps.length > 0) {
97
+ logger.dim(` ${phase}: ${mcps.map(m => m.name).join(', ')}`);
98
+ }
99
+ }
100
+ }
101
+
102
+ logger.blank();
103
+ const { saveIntegrationsChoice } = await inquirer.prompt([{
104
+ type: 'confirm',
105
+ name: 'saveIntegrationsChoice',
106
+ message: 'Save detected integrations and generate optimized settings?',
107
+ default: true
108
+ }]);
109
+
110
+ if (saveIntegrationsChoice) {
111
+ spinner.start('Saving integrations...');
112
+ await saveIntegrations(targetPath, claudeConfigDetected);
113
+ await generateSettings(targetPath, claudeConfigDetected, config);
114
+ integrationsCreated = true;
115
+ spinner.succeed('Integrations saved to .morph/config/integrations.json');
116
+ } else {
117
+ spinner.start('Continuing...');
118
+ }
119
+ }
120
+ } catch (error) {
121
+ // Non-fatal: continue without integrations
122
+ logger.dim(` Claude config detection skipped: ${error.message}`);
123
+ }
124
+
125
+ // 11c. Stack detection (moved before MCP setup so we know the stack)
126
+ spinner.text = 'Detecting project stack...';
127
+ let detectedStack = 'unknown';
128
+ const hasProjectFiles = await pathExists(join(targetPath, 'package.json'))
129
+ || await pathExists(join(targetPath, 'src'))
130
+ || (await fs.readdir(targetPath)).some(f => f.endsWith('.csproj'));
131
+
132
+ if (hasProjectFiles) {
133
+ try {
134
+ const quickResults = await detectProject(targetPath, { conversation: false, generateStandards: false });
135
+ const structure = quickResults.structure;
136
+
137
+ if (structure?.stack && structure.stack !== 'unknown') {
138
+ detectedStack = structure.stack;
139
+
140
+ // Persist detected stack to config.json
141
+ if (structure?.stack && structure.stack !== 'unknown') {
142
+ config.project.stack = structure.stack;
143
+ }
144
+ if (structure?.architecture && structure.architecture !== 'unknown') {
145
+ config.project.architecture = structure.architecture;
146
+ }
147
+ if (structure?.uiLibrary) {
148
+ config.project.uiLibrary = structure.uiLibrary;
149
+ }
150
+ await writeJson(configPath, config);
151
+
152
+ spinner.stop();
153
+ logger.blank();
154
+ logger.header('Existing Project Detected');
155
+ logger.info(`Stack detected: ${structure.stack}`);
156
+ if (structure?.architecture) logger.dim(`Architecture: ${structure.architecture}`);
157
+ if (structure?.uiLibrary) logger.dim(`UI Library: ${structure.uiLibrary}`);
158
+
159
+ const { standardsChoice } = await inquirer.prompt([{
160
+ type: 'list',
161
+ name: 'standardsChoice',
162
+ message: 'How should morph-spec handle your project standards?',
163
+ choices: [
164
+ { name: 'Keep morph-spec defaults (recommended)', value: 'morph-spec' },
165
+ { name: 'Detect project-specific standards', value: 'detect' }
166
+ ]
167
+ }]);
168
+
169
+ if (standardsChoice === 'detect') {
170
+ spinner.start('Generating project-specific standards...');
171
+ const fullResults = await detectProject(targetPath, { conversation: false });
172
+ const inferredPath = join(contextDir, 'standards.md');
173
+ await writeFile(inferredPath, fullResults.inferred.markdown);
174
+ spinner.succeed('Generated .morph/context/standards.md');
175
+ logger.dim('Review and edit .morph/context/standards.md as needed.');
176
+ }
177
+
178
+ spinner.start('Continuing...');
179
+ }
180
+ } catch (error) {
181
+ logger.dim(` Stack detection skipped: ${error.message}`);
182
+ }
183
+ }
184
+
185
+ // 11d. MCP Auto-Setup
186
+ let mcpSetupResult = null;
187
+ if (!options.skipMcp) {
188
+ try {
189
+ spinner.stop();
190
+ const existingMcps = claudeConfigDetected?.mcpServers || [];
191
+ const orchestration = orchestrateMcpSetup(targetPath, detectedStack, existingMcps);
192
+
193
+ const autoNames = Object.keys(orchestration.autoInstallable);
194
+ const manualNames = Object.keys(orchestration.needsManualSetup);
195
+ const hasAutoMcps = autoNames.length > 0;
196
+ const hasManualMcps = manualNames.length > 0;
197
+
198
+ if (hasAutoMcps || hasManualMcps) {
199
+ logger.blank();
200
+ logger.header('MCP Server Setup');
201
+
202
+ // Auto-install prompt
203
+ let autoInstalled = {};
204
+ if (hasAutoMcps) {
205
+ const { installAuto } = await inquirer.prompt([{
206
+ type: 'confirm',
207
+ name: 'installAuto',
208
+ message: `Install recommended MCP servers? (${autoNames.join(', ')})`,
209
+ default: true
210
+ }]);
211
+
212
+ if (installAuto) {
213
+ spinner.start('Installing MCP servers...');
214
+ const result = await installAutoMcps(targetPath, orchestration.autoInstallable);
215
+ spinner.succeed(`Installed ${result.added.length} MCP server(s)`);
216
+ for (const name of result.added) {
217
+ autoInstalled[name] = orchestration.autoInstallable[name];
218
+ }
219
+ }
220
+ }
221
+
222
+ // Credential MCPs — inline setup or instructions
223
+ const manualInstalled = {};
224
+ if (hasManualMcps) {
225
+ for (const [name, entry] of Object.entries(orchestration.needsManualSetup)) {
226
+ logger.blank();
227
+
228
+ // Show warnings
229
+ for (const warning of entry.install.warnings || []) {
230
+ logger.warn(` ${warning}`);
231
+ }
232
+
233
+ const capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
234
+ const { setupNow } = await inquirer.prompt([{
235
+ type: 'confirm',
236
+ name: 'setupNow',
237
+ message: `Set up ${capitalizedName} MCP now? (${entry.usage})`,
238
+ default: false
239
+ }]);
240
+
241
+ if (setupNow) {
242
+ // Collect credentials
243
+ const credentialValues = {};
244
+ for (const cred of entry.install.credentials) {
245
+ const { value } = await inquirer.prompt([{
246
+ type: cred.secret ? 'password' : 'input',
247
+ name: 'value',
248
+ message: `${cred.name}:`,
249
+ mask: cred.secret ? '*' : undefined
250
+ }]);
251
+ credentialValues[cred.envVar] = value;
252
+ }
253
+
254
+ spinner.start(`Configuring ${name}...`);
255
+ await installMcpWithCredentials(targetPath, name, entry, credentialValues);
256
+ spinner.succeed(`${capitalizedName} MCP configured`);
257
+ manualInstalled[name] = entry;
258
+ } else {
259
+ // Show setup instructions
260
+ const instructions = generateSetupInstructions(name, entry);
261
+ logger.blank();
262
+ logger.dim(' Add to .claude/settings.local.json → mcpServers:');
263
+ logger.dim(' ' + '─'.repeat(55));
264
+ for (const line of instructions.configSnippet.split('\n')) {
265
+ logger.dim(` ${line}`);
266
+ }
267
+ logger.dim(' ' + '─'.repeat(55));
268
+
269
+ for (const cred of instructions.credentialUrls) {
270
+ logger.dim(` Get ${cred.name}: ${cred.helpUrl}`);
271
+ }
272
+ logger.dim(` Or run later: ${instructions.cliCommand}`);
273
+ }
274
+ }
275
+ }
276
+
277
+ // Summary table
278
+ const justInstalled = { ...autoInstalled, ...manualInstalled };
279
+ const statusRows = formatMcpStatusTable(orchestration, justInstalled);
280
+
281
+ if (statusRows.length > 0) {
282
+ logger.blank();
283
+ logger.info('MCP Servers');
284
+ logger.dim(''.repeat(60));
285
+
286
+ const STATUS_ICONS = {
287
+ installed: '',
288
+ available: '○',
289
+ already_configured: '✓',
290
+ needs_setup: '⚠',
291
+ prereq_missing: '✗',
292
+ not_relevant: '─'
293
+ };
294
+
295
+ for (const row of statusRows) {
296
+ const icon = STATUS_ICONS[row.status] || '?';
297
+ const statusLabel = row.status.replace(/_/g, ' ');
298
+ logger.dim(` ${icon} ${row.name.padEnd(15)} ${statusLabel.padEnd(20)} ${row.detail}`);
299
+ }
300
+ }
301
+
302
+ mcpSetupResult = { autoInstalled, manualInstalled, orchestration };
303
+ }
304
+ } catch (error) {
305
+ logger.dim(` MCP setup skipped: ${error.message}`);
306
+ }
307
+ } else {
308
+ logger.dim('\nSkipped MCP setup (--skip-mcp flag)');
309
+ }
310
+
311
+ spinner.succeed('MORPH-SPEC installed successfully!');
312
+
313
+ // Show next steps
314
+ logger.blank();
315
+ logger.success(`MORPH-SPEC v${cliVersion} installed successfully!`);
316
+ logger.blank();
317
+ logger.header('Next Steps');
318
+
319
+ logger.step(1, 'Review .morph/config/config.json');
320
+ logger.step(2, 'Open project in VS Code with Claude Code');
321
+ logger.step(3, 'Start your first feature:');
322
+ logger.blank();
323
+ logger.box([
324
+ 'Ask Claude Code to implement a feature'
325
+ ]);
326
+ logger.blank();
327
+
328
+ logger.info('Files installed:');
329
+ logger.dim(` ✓ CLAUDE.md`);
330
+ logger.dim(` ✓ .morph/config/ (config.json)`);
331
+ logger.dim(` ✓ .morph/framework/ (agents.json, standards/, templates/, hooks/)`);
332
+ logger.dim(` ✓ .morph/context/ (project context)`);
333
+ logger.dim(` ✓ .morph/features/ (feature outputs)`);
334
+ if (commandsCopied) {
335
+ logger.dim(` ✓ .claude/commands/ (slash commands)`);
336
+ }
337
+ if (rulesCopied) {
338
+ logger.dim(` .claude/rules/ (5 path-scoped rules)`);
339
+ }
340
+ logger.dim(` ✓ .claude/settings.local.json (${hooksResult.installed} hooks installed)`);
341
+ if (integrationsCreated) {
342
+ logger.dim(` ✓ .morph/config/integrations.json (detected plugins & MCPs)`);
343
+ }
344
+ if (mcpSetupResult) {
345
+ const autoCount = Object.keys(mcpSetupResult.autoInstalled).length;
346
+ const manualCount = Object.keys(mcpSetupResult.manualInstalled).length;
347
+ if (autoCount + manualCount > 0) {
348
+ logger.dim(` ✓ MCP servers (${autoCount + manualCount} configured)`);
349
+ }
350
+ }
351
+
352
+ logger.dim(' ✓ .claude/skills/ (installed as skill directories)');
353
+
354
+ // Show agent team breakdown from setup-infra result
355
+ const agents = infraResult?.agents;
356
+ if (agents) {
357
+ const total = agents.tier1 + agents.tier2 + agents.specialists;
358
+ logger.dim(` ✓ .claude/agents/ (${total} agents: ${agents.tier1} orchestrators, ${agents.tier2} domain leaders, ${agents.specialists} specialists)`);
359
+ } else {
360
+ logger.dim(' ✓ .claude/agents/ (native subagents installed)');
361
+ }
362
+
363
+ logger.dim(' ✓ ~/.claude/statusline.sh (global statusline installed)');
364
+
365
+ // Check CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS in ~/.claude/settings.local.json
366
+ logger.blank();
367
+ const globalSettingsPath = join(homedir(), '.claude', 'settings.local.json');
368
+ let agentTeamsEnabled = false;
369
+ try {
370
+ const globalSettings = await readJson(globalSettingsPath);
371
+ agentTeamsEnabled = globalSettings?.env?.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === '1';
372
+ } catch {
373
+ // File missing or unreadable — treat as not enabled
374
+ }
375
+
376
+ if (agentTeamsEnabled) {
377
+ logger.success('Agent Teams: CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS enabled ✓');
378
+ } else {
379
+ logger.warn('Agent Teams not enabled. To activate multi-agent workflows, add to ~/.claude/settings.local.json:');
380
+ logger.dim(' {"env": {"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"}}');
381
+ }
382
+
383
+ logger.blank();
384
+
385
+ // Suggest tutorial for first-time users
386
+ if (integrationsCreated) {
387
+ logger.blank();
388
+ logger.info('First time using morph-spec? Run `morph-spec tutorial` to get started.');
389
+ }
390
+
391
+ logger.blank();
392
+
393
+ } catch (error) {
394
+ spinner.fail('Installation failed');
395
+ logger.error(error.message);
396
+ process.exit(1);
397
+ }
398
+ }