@polymorphism-tech/morph-spec 4.7.2 → 4.8.1

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 (346) hide show
  1. package/.morph/analytics/threads-log.jsonl +54 -5
  2. package/.morph/state.json +152 -2
  3. package/LICENSE +1 -2
  4. package/README.md +379 -414
  5. package/bin/morph-spec.js +57 -394
  6. package/bin/validate.js +2 -26
  7. package/claude-plugin.json +2 -2
  8. package/docs/ARCHITECTURE.md +43 -46
  9. package/docs/CHEATSHEET.md +203 -221
  10. package/docs/COMMAND-FLOWS.md +319 -289
  11. package/docs/QUICKSTART.md +2 -8
  12. package/docs/plans/2026-02-22-claude-docs-morph-alignment-analysis.md +2 -0
  13. package/docs/plans/2026-02-22-claude-settings.md +2 -0
  14. package/docs/plans/2026-02-22-morph-cc-alignment-impl.md +2 -0
  15. package/docs/plans/2026-02-22-morph-spec-next.md +2 -0
  16. package/docs/plans/2026-02-22-native-alignment-design.md +2 -0
  17. package/docs/plans/2026-02-22-native-alignment-impl.md +2 -0
  18. package/docs/plans/2026-02-22-native-enrichment-design.md +2 -0
  19. package/docs/plans/2026-02-22-native-enrichment.md +2 -0
  20. package/docs/plans/2026-02-23-ddd-architecture-refactor.md +2 -0
  21. package/docs/plans/2026-02-23-ddd-nextsteps.md +2 -0
  22. package/docs/plans/2026-02-23-infra-architect-refactor.md +2 -0
  23. package/docs/plans/2026-02-23-nextjs-code-review-design.md +2 -1
  24. package/docs/plans/2026-02-23-nextjs-code-review-impl.md +2 -0
  25. package/docs/plans/2026-02-23-nextjs-standards-design.md +2 -1
  26. package/docs/plans/2026-02-23-nextjs-standards-impl.md +2 -0
  27. package/docs/plans/2026-02-24-cli-radical-simplification.md +592 -0
  28. package/docs/plans/2026-02-24-framework-failure-points.md +125 -0
  29. package/docs/plans/2026-02-24-morph-init-design.md +337 -0
  30. package/docs/plans/2026-02-24-morph-init-impl.md +1269 -0
  31. package/docs/plans/2026-02-24-tutorial-command-design.md +71 -0
  32. package/docs/plans/2026-02-24-tutorial-command.md +298 -0
  33. package/framework/CLAUDE.md +1 -1
  34. package/framework/commands/morph-proposal.md +3 -3
  35. package/framework/hooks/README.md +2 -5
  36. package/framework/hooks/claude-code/pre-tool-use/protect-readonly-files.js +4 -55
  37. package/framework/hooks/claude-code/session-start/inject-morph-context.js +20 -5
  38. package/framework/hooks/claude-code/statusline.py +6 -1
  39. package/framework/hooks/dev/check-sync-health.js +117 -0
  40. package/framework/hooks/dev/guard-version-numbers.js +57 -0
  41. package/framework/hooks/dev/sync-standards-registry.js +60 -0
  42. package/framework/hooks/dev/sync-template-registry.js +60 -0
  43. package/framework/hooks/dev/validate-skill-format.js +70 -0
  44. package/framework/hooks/dev/validate-standard-format.js +73 -0
  45. package/framework/hooks/shared/payload-utils.js +39 -0
  46. package/framework/hooks/shared/state-reader.js +25 -1
  47. package/framework/rules/morph-workflow.md +1 -1
  48. package/framework/skills/level-0-meta/morph-init/SKILL.md +216 -0
  49. package/framework/skills/level-0-meta/morph-replicate/SKILL.md +4 -4
  50. package/framework/skills/level-0-meta/tool-usage-guide/SKILL.md +4 -4
  51. package/framework/skills/level-0-meta/verification-before-completion/SKILL.md +1 -1
  52. package/framework/skills/level-1-workflows/phase-clarify/SKILL.md +192 -191
  53. package/framework/skills/level-1-workflows/phase-codebase-analysis/SKILL.md +181 -180
  54. package/framework/skills/level-1-workflows/phase-design/SKILL.md +339 -338
  55. package/framework/skills/level-1-workflows/phase-implement/SKILL.md +254 -253
  56. package/framework/skills/level-1-workflows/phase-setup/SKILL.md +168 -170
  57. package/framework/skills/level-1-workflows/phase-tasks/SKILL.md +284 -283
  58. package/framework/skills/level-1-workflows/phase-uiux/SKILL.md +246 -245
  59. package/framework/templates/examples/design-system-examples.md +1 -1
  60. package/framework/templates/ui/FluentDesignTheme.cs +1 -1
  61. package/framework/templates/ui/MudTheme.cs +1 -1
  62. package/framework/templates/ui/design-system.css +1 -1
  63. package/package.json +4 -2
  64. package/scripts/bump-version.js +248 -0
  65. package/scripts/install-dev-hooks.js +138 -0
  66. package/src/commands/agents/index.js +1 -2
  67. package/src/commands/index.js +13 -16
  68. package/src/commands/project/doctor.js +100 -14
  69. package/src/commands/project/index.js +7 -10
  70. package/src/commands/project/init.js +398 -528
  71. package/src/commands/project/install-plugin-cmd.js +28 -0
  72. package/src/commands/project/setup-infra-cmd.js +12 -0
  73. package/src/commands/project/tutorial.js +115 -0
  74. package/src/commands/state/approve.js +213 -221
  75. package/src/commands/state/index.js +0 -1
  76. package/src/commands/state/state.js +337 -365
  77. package/src/commands/templates/index.js +0 -4
  78. package/src/commands/trust/trust.js +1 -93
  79. package/src/commands/utils/index.js +1 -5
  80. package/src/commands/validation/index.js +1 -5
  81. package/src/core/registry/command-registry.js +11 -285
  82. package/src/core/state/state-manager.js +5 -2
  83. package/src/lib/detectors/index.js +81 -87
  84. package/src/lib/detectors/structure-detector.js +275 -273
  85. package/src/lib/generators/recap-generator.js +232 -225
  86. package/src/scripts/global-install.js +34 -0
  87. package/src/scripts/install-plugin.js +126 -0
  88. package/src/scripts/setup-infra.js +203 -0
  89. package/src/utils/agents-installer.js +10 -1
  90. package/src/utils/hooks-installer.js +66 -3
  91. package/.morph/.morphversion +0 -5
  92. package/.morph/config/config.json +0 -8
  93. package/.morph/framework/agents.json +0 -1815
  94. package/.morph/framework/hooks/README.md +0 -205
  95. package/.morph/framework/hooks/claude-code/notification/approval-reminder.js +0 -54
  96. package/.morph/framework/hooks/claude-code/post-tool-use/dispatch.js +0 -83
  97. package/.morph/framework/hooks/claude-code/post-tool-use/handle-tool-failure.js +0 -42
  98. package/.morph/framework/hooks/claude-code/pre-compact/save-morph-context.js +0 -61
  99. package/.morph/framework/hooks/claude-code/pre-tool-use/enforce-phase-writes.js +0 -71
  100. package/.morph/framework/hooks/claude-code/pre-tool-use/protect-readonly-files.js +0 -58
  101. package/.morph/framework/hooks/claude-code/pre-tool-use/protect-spec-files.js +0 -64
  102. package/.morph/framework/hooks/claude-code/session-start/inject-morph-context.js +0 -94
  103. package/.morph/framework/hooks/claude-code/statusline.py +0 -538
  104. package/.morph/framework/hooks/claude-code/statusline.sh +0 -7
  105. package/.morph/framework/hooks/claude-code/stop/validate-completion.js +0 -88
  106. package/.morph/framework/hooks/claude-code/user-prompt/enrich-prompt.js +0 -91
  107. package/.morph/framework/hooks/git/commit-msg/conventional-commits.sh +0 -33
  108. package/.morph/framework/hooks/git/pre-commit/agents.sh +0 -25
  109. package/.morph/framework/hooks/git/pre-commit/orchestrator.sh +0 -64
  110. package/.morph/framework/hooks/git/pre-commit/specs.sh +0 -50
  111. package/.morph/framework/hooks/git/pre-push/run-tests.sh +0 -44
  112. package/.morph/framework/hooks/shared/hook-response.js +0 -45
  113. package/.morph/framework/hooks/shared/phase-utils.js +0 -129
  114. package/.morph/framework/hooks/shared/state-reader.js +0 -138
  115. package/.morph/framework/hooks/shared/stdin-reader.js +0 -26
  116. package/.morph/framework/standards/STANDARDS.json +0 -933
  117. package/.morph/framework/standards/ai-agents/blazor-ui.md +0 -364
  118. package/.morph/framework/standards/ai-agents/production.md +0 -415
  119. package/.morph/framework/standards/ai-agents/setup.md +0 -418
  120. package/.morph/framework/standards/ai-agents/team-orchestration.md +0 -479
  121. package/.morph/framework/standards/ai-agents/workflows.md +0 -354
  122. package/.morph/framework/standards/architecture/ddd/aggregates.md +0 -120
  123. package/.morph/framework/standards/architecture/ddd/bounded-contexts.md +0 -105
  124. package/.morph/framework/standards/architecture/ddd/complexity-levels.md +0 -108
  125. package/.morph/framework/standards/architecture/ddd/entities.md +0 -99
  126. package/.morph/framework/standards/architecture/ddd/ubiquitous-language.md +0 -58
  127. package/.morph/framework/standards/architecture/ddd/value-objects.md +0 -124
  128. package/.morph/framework/standards/backend/api/minimal-api.md +0 -494
  129. package/.morph/framework/standards/backend/api/rest.md +0 -492
  130. package/.morph/framework/standards/backend/api/validation.md +0 -88
  131. package/.morph/framework/standards/backend/authentication/passkeys.md +0 -428
  132. package/.morph/framework/standards/backend/database/ef-core.md +0 -199
  133. package/.morph/framework/standards/backend/database/migrations.md +0 -393
  134. package/.morph/framework/standards/backend/database/postgresql/database.md +0 -352
  135. package/.morph/framework/standards/backend/database/repository-patterns.md +0 -528
  136. package/.morph/framework/standards/backend/database/vector-search-rag.md +0 -541
  137. package/.morph/framework/standards/backend/dotnet/async.md +0 -366
  138. package/.morph/framework/standards/backend/dotnet/core.md +0 -117
  139. package/.morph/framework/standards/backend/dotnet/di.md +0 -439
  140. package/.morph/framework/standards/backend/dotnet/program-cs-checklist.md +0 -92
  141. package/.morph/framework/standards/backend/integrations/asaas/asaas-api.md +0 -216
  142. package/.morph/framework/standards/backend/integrations/clerk/clerk-auth.md +0 -290
  143. package/.morph/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +0 -350
  144. package/.morph/framework/standards/backend/integrations/resend/resend-email.md +0 -385
  145. package/.morph/framework/standards/context/analytics.md +0 -96
  146. package/.morph/framework/standards/context/bundles.md +0 -110
  147. package/.morph/framework/standards/context/priming.md +0 -78
  148. package/.morph/framework/standards/core/architecture.md +0 -185
  149. package/.morph/framework/standards/core/coding.md +0 -214
  150. package/.morph/framework/standards/core/git-branching-strategy.md +0 -403
  151. package/.morph/framework/standards/core/git.md +0 -185
  152. package/.morph/framework/standards/core/testing.md +0 -295
  153. package/.morph/framework/standards/data/nosql/blob-storage.md +0 -102
  154. package/.morph/framework/standards/data/nosql/cache/redis.md +0 -97
  155. package/.morph/framework/standards/data/nosql/cosmos-db.md +0 -118
  156. package/.morph/framework/standards/data/vector-search/azure-ai-search.md +0 -121
  157. package/.morph/framework/standards/data/vector-search/rag-chunking.md +0 -104
  158. package/.morph/framework/standards/frontend/blazor/design-checklist.md +0 -222
  159. package/.morph/framework/standards/frontend/blazor/fluent-ui-setup.md +0 -595
  160. package/.morph/framework/standards/frontend/blazor/fluent-ui.md +0 -137
  161. package/.morph/framework/standards/frontend/blazor/html-conversion.md +0 -184
  162. package/.morph/framework/standards/frontend/blazor/lifecycle.md +0 -195
  163. package/.morph/framework/standards/frontend/blazor/pitfalls.md +0 -198
  164. package/.morph/framework/standards/frontend/blazor/state.md +0 -191
  165. package/.morph/framework/standards/frontend/design-system/animations.md +0 -151
  166. package/.morph/framework/standards/frontend/design-system/naming.md +0 -64
  167. package/.morph/framework/standards/frontend/nextjs/app-router.md +0 -123
  168. package/.morph/framework/standards/frontend/nextjs/components.md +0 -132
  169. package/.morph/framework/standards/frontend/nextjs/data-fetching.md +0 -126
  170. package/.morph/framework/standards/frontend/nextjs/forms.md +0 -128
  171. package/.morph/framework/standards/frontend/nextjs/naming-conventions.md +0 -67
  172. package/.morph/framework/standards/frontend/nextjs/nextjs-patterns.md +0 -215
  173. package/.morph/framework/standards/frontend/nextjs/project-structure.md +0 -102
  174. package/.morph/framework/standards/frontend/nextjs/state-management.md +0 -72
  175. package/.morph/framework/standards/frontend/nextjs/testing.md +0 -111
  176. package/.morph/framework/standards/infrastructure/azure/azure.md +0 -624
  177. package/.morph/framework/standards/infrastructure/azure/bicep/bicep-patterns.md +0 -422
  178. package/.morph/framework/standards/infrastructure/azure/devops/azure-devops-setup.md +0 -516
  179. package/.morph/framework/standards/infrastructure/azure/devops/local-development.md +0 -520
  180. package/.morph/framework/standards/infrastructure/azure/services/functions.md +0 -486
  181. package/.morph/framework/standards/infrastructure/azure/services/service-bus.md +0 -459
  182. package/.morph/framework/standards/infrastructure/azure/services/storage.md +0 -407
  183. package/.morph/framework/standards/infrastructure/docker/easypanel-deploy.md +0 -196
  184. package/.morph/framework/standards/infrastructure/supabase/mcp-setup.md +0 -252
  185. package/.morph/framework/standards/infrastructure/supabase/supabase-auth.md +0 -176
  186. package/.morph/framework/standards/infrastructure/supabase/supabase-pgvector.md +0 -169
  187. package/.morph/framework/standards/infrastructure/supabase/supabase-rls.md +0 -184
  188. package/.morph/framework/standards/infrastructure/supabase/supabase-storage.md +0 -153
  189. package/.morph/framework/standards/integration/api/graphql.md +0 -91
  190. package/.morph/framework/standards/integration/api/grpc.md +0 -114
  191. package/.morph/framework/standards/integration/api/rest-design.md +0 -95
  192. package/.morph/framework/standards/integration/event-driven/cqrs.md +0 -101
  193. package/.morph/framework/standards/integration/event-driven/event-sourcing.md +0 -124
  194. package/.morph/framework/standards/integration/event-driven/service-bus.md +0 -95
  195. package/.morph/framework/standards/integration/mcp/mcp-tools.md +0 -384
  196. package/.morph/framework/standards/observability/logging.md +0 -131
  197. package/.morph/framework/standards/observability/metrics.md +0 -121
  198. package/.morph/framework/standards/observability/monitoring.md +0 -114
  199. package/.morph/framework/standards/observability/tracing.md +0 -132
  200. package/.morph/framework/standards/workflows/parallel-execution.md +0 -112
  201. package/.morph/framework/standards/workflows/thread-management.md +0 -113
  202. package/.morph/framework/templates/.idea/morph-templates.xml +0 -92
  203. package/.morph/framework/templates/.vscode/morph-templates.code-snippets +0 -186
  204. package/.morph/framework/templates/IDE-SNIPPETS.md +0 -266
  205. package/.morph/framework/templates/README.md +0 -814
  206. package/.morph/framework/templates/REGISTRY.json +0 -1888
  207. package/.morph/framework/templates/code/dotnet/backend/repository.cs +0 -141
  208. package/.morph/framework/templates/code/dotnet/backend/service.cs +0 -139
  209. package/.morph/framework/templates/code/dotnet/contracts/Commands.cs +0 -74
  210. package/.morph/framework/templates/code/dotnet/contracts/Entities.cs +0 -25
  211. package/.morph/framework/templates/code/dotnet/contracts/Queries.cs +0 -74
  212. package/.morph/framework/templates/code/dotnet/contracts/README.md +0 -74
  213. package/.morph/framework/templates/code/dotnet/contracts/api-contracts.cs +0 -173
  214. package/.morph/framework/templates/code/dotnet/contracts/contracts-level1.cs +0 -69
  215. package/.morph/framework/templates/code/dotnet/contracts/contracts-level2.cs +0 -86
  216. package/.morph/framework/templates/code/dotnet/contracts/contracts-level3.cs +0 -41
  217. package/.morph/framework/templates/code/dotnet/database/migration.cs +0 -83
  218. package/.morph/framework/templates/code/dotnet/frontend/component.razor +0 -239
  219. package/.morph/framework/templates/code/dotnet/jobs/agent.cs +0 -163
  220. package/.morph/framework/templates/code/dotnet/jobs/job.cs +0 -171
  221. package/.morph/framework/templates/code/dotnet/test.cs +0 -239
  222. package/.morph/framework/templates/code/sql/rls-policy.sql +0 -57
  223. package/.morph/framework/templates/code/sql/supabase-migration.sql +0 -100
  224. package/.morph/framework/templates/code/sql/supabase-migration.template.sql +0 -113
  225. package/.morph/framework/templates/code/typescript/contracts.ts +0 -168
  226. package/.morph/framework/templates/context/CONTEXT-FEATURE.md +0 -276
  227. package/.morph/framework/templates/context/CONTEXT.md +0 -181
  228. package/.morph/framework/templates/docs/clarifications.md +0 -253
  229. package/.morph/framework/templates/docs/onboarding.md +0 -123
  230. package/.morph/framework/templates/docs/proposal.md +0 -182
  231. package/.morph/framework/templates/docs/schema-analysis.md +0 -119
  232. package/.morph/framework/templates/docs/spec.md +0 -198
  233. package/.morph/framework/templates/docs/ui-components.md +0 -124
  234. package/.morph/framework/templates/docs/ui-design-system.md +0 -76
  235. package/.morph/framework/templates/docs/ui-flows.md +0 -167
  236. package/.morph/framework/templates/docs/ui-mockups.md +0 -98
  237. package/.morph/framework/templates/docs/user-stories.md +0 -34
  238. package/.morph/framework/templates/examples/design-system-examples.md +0 -357
  239. package/.morph/framework/templates/examples/spec-examples.md +0 -90
  240. package/.morph/framework/templates/feature/decisions.md +0 -187
  241. package/.morph/framework/templates/feature/recap.md +0 -146
  242. package/.morph/framework/templates/feature/tasks.md +0 -199
  243. package/.morph/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +0 -43
  244. package/.morph/framework/templates/frontend/nextjs/client-component.tsx.hbs +0 -26
  245. package/.morph/framework/templates/frontend/nextjs/env.mjs.hbs +0 -32
  246. package/.morph/framework/templates/frontend/nextjs/feature-form.tsx.hbs +0 -56
  247. package/.morph/framework/templates/frontend/nextjs/page.tsx.hbs +0 -22
  248. package/.morph/framework/templates/frontend/nextjs/tsconfig.json.hbs +0 -26
  249. package/.morph/framework/templates/frontend/nextjs/use-feature.ts.hbs +0 -54
  250. package/.morph/framework/templates/infrastructure/azure/Dockerfile.example +0 -82
  251. package/.morph/framework/templates/infrastructure/azure/README.md +0 -286
  252. package/.morph/framework/templates/infrastructure/azure/app-insights.bicep +0 -63
  253. package/.morph/framework/templates/infrastructure/azure/app-service.bicep +0 -164
  254. package/.morph/framework/templates/infrastructure/azure/container-app-env.bicep +0 -49
  255. package/.morph/framework/templates/infrastructure/azure/container-app.bicep +0 -156
  256. package/.morph/framework/templates/infrastructure/azure/deploy-checklist.md +0 -426
  257. package/.morph/framework/templates/infrastructure/azure/deploy.ps1 +0 -229
  258. package/.morph/framework/templates/infrastructure/azure/deploy.sh +0 -208
  259. package/.morph/framework/templates/infrastructure/azure/key-vault.bicep +0 -91
  260. package/.morph/framework/templates/infrastructure/azure/main.bicep +0 -189
  261. package/.morph/framework/templates/infrastructure/azure/parameters.dev.json +0 -29
  262. package/.morph/framework/templates/infrastructure/azure/parameters.prod.json +0 -29
  263. package/.morph/framework/templates/infrastructure/azure/parameters.staging.json +0 -29
  264. package/.morph/framework/templates/infrastructure/azure/sql-database.bicep +0 -103
  265. package/.morph/framework/templates/infrastructure/azure/storage.bicep +0 -106
  266. package/.morph/framework/templates/infrastructure/docker/Dockerfile.template +0 -58
  267. package/.morph/framework/templates/infrastructure/docker/docker-compose.template.yml +0 -67
  268. package/.morph/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +0 -38
  269. package/.morph/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +0 -48
  270. package/.morph/framework/templates/infrastructure/docker/easypanel.template.json +0 -54
  271. package/.morph/framework/templates/infrastructure/github/README.md +0 -593
  272. package/.morph/framework/templates/infrastructure/github/actions/azure-auth/action.yml.hbs +0 -22
  273. package/.morph/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +0 -45
  274. package/.morph/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +0 -27
  275. package/.morph/framework/templates/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs +0 -61
  276. package/.morph/framework/templates/infrastructure/github/workflows/deploy-easypanel.yml.hbs +0 -31
  277. package/.morph/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +0 -59
  278. package/.morph/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +0 -39
  279. package/.morph/framework/templates/integrations/asaas-client.cs +0 -387
  280. package/.morph/framework/templates/integrations/asaas-webhook.cs +0 -351
  281. package/.morph/framework/templates/integrations/azure-identity-config.cs +0 -288
  282. package/.morph/framework/templates/integrations/clerk-config.cs +0 -258
  283. package/.morph/framework/templates/meta-prompts/fusion/fusion-agent.md +0 -76
  284. package/.morph/framework/templates/meta-prompts/fusion/fusion-aggregator.md +0 -100
  285. package/.morph/framework/templates/meta-prompts/hops/hop-retry.md +0 -78
  286. package/.morph/framework/templates/meta-prompts/hops/hop-validation.md +0 -97
  287. package/.morph/framework/templates/meta-prompts/hops/hop-wrapper.md +0 -36
  288. package/.morph/framework/templates/meta-prompts/parallel-workers/parallel-coordinator.md +0 -113
  289. package/.morph/framework/templates/meta-prompts/parallel-workers/parallel-worker.md +0 -80
  290. package/.morph/framework/templates/meta-prompts/squad-leaders/backend-squad.md +0 -90
  291. package/.morph/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +0 -126
  292. package/.morph/framework/templates/meta-prompts/squad-leaders/squad-leader.md +0 -43
  293. package/.morph/framework/templates/meta-prompts/validators/checkpoint-validator.md +0 -107
  294. package/.morph/framework/templates/meta-prompts/validators/pre-commit-validator.md +0 -95
  295. package/.morph/framework/templates/project-structure/dotnet-ddd.md +0 -70
  296. package/.morph/framework/templates/saas/subscription.cs +0 -347
  297. package/.morph/framework/templates/saas/tenant.cs +0 -338
  298. package/.morph/framework/templates/state.template.json +0 -17
  299. package/.morph/framework/templates/ui/FluentDesignTheme.cs +0 -149
  300. package/.morph/framework/templates/ui/MudTheme.cs +0 -281
  301. package/.morph/framework/templates/ui/design-system.css +0 -226
  302. package/.morph/logs/tool-failures.log +0 -17
  303. package/.morph/memory/pre-compact-2026-02-24T17-43-30-049Z.json +0 -16
  304. package/.morph/plans/eager-watching-bunny.md +0 -105
  305. package/.morph/plans/temporal-seeking-nebula.md +0 -45
  306. package/CLAUDE.md +0 -77
  307. package/docs/claude-alignment-report.md +0 -137
  308. package/docs/examples/order-management/contracts.cs +0 -84
  309. package/docs/examples/order-management/proposal.md +0 -24
  310. package/docs/examples/order-management/spec.md +0 -162
  311. package/src/commands/feature/create-story.js +0 -362
  312. package/src/commands/feature/index.js +0 -6
  313. package/src/commands/feature/shard-spec.js +0 -225
  314. package/src/commands/feature/sprint-status.js +0 -250
  315. package/src/commands/generation/generate-onboarding.js +0 -169
  316. package/src/commands/generation/generate.js +0 -276
  317. package/src/commands/generation/index.js +0 -5
  318. package/src/commands/learning/capture-pattern.js +0 -121
  319. package/src/commands/learning/index.js +0 -5
  320. package/src/commands/learning/search-patterns.js +0 -126
  321. package/src/commands/mcp/mcp.js +0 -102
  322. package/src/commands/project/changes.js +0 -66
  323. package/src/commands/project/cost.js +0 -179
  324. package/src/commands/project/diff.js +0 -278
  325. package/src/commands/project/revert.js +0 -173
  326. package/src/commands/project/standards.js +0 -80
  327. package/src/commands/project/sync.js +0 -167
  328. package/src/commands/project/update-agents.js +0 -23
  329. package/src/commands/state/rollback-phase.js +0 -185
  330. package/src/commands/templates/template-customize.js +0 -87
  331. package/src/commands/templates/template-list.js +0 -114
  332. package/src/commands/templates/template-show.js +0 -129
  333. package/src/commands/templates/template-validate.js +0 -91
  334. package/src/commands/utils/troubleshoot.js +0 -222
  335. package/src/commands/validation/analyze-blazor-concurrency.js +0 -193
  336. package/src/commands/validation/lint-fluent.js +0 -352
  337. package/src/commands/validation/validate-blazor-state.js +0 -210
  338. package/src/commands/validation/validate-blazor.js +0 -156
  339. package/src/commands/validation/validate-css.js +0 -84
  340. package/src/lib/detectors/conversation-analyzer.js +0 -163
  341. package/src/lib/learning/index.js +0 -7
  342. package/src/lib/learning/learning-system.js +0 -520
  343. package/src/lib/troubleshooting/index.js +0 -8
  344. package/src/lib/troubleshooting/troubleshoot-grep.js +0 -198
  345. package/src/lib/troubleshooting/troubleshoot-index.js +0 -144
  346. 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
+ }