@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,255 +0,0 @@
1
- /**
2
- * scripts/validate-real.mjs
3
- *
4
- * Real-world integration validation for output-schema.js centralization.
5
- * Creates a temp .morph project, creates a feature, and verifies all paths.
6
- *
7
- * Usage: node scripts/validate-real.mjs
8
- */
9
-
10
- import { join, dirname } from 'path';
11
- import { writeFileSync, mkdirSync, existsSync, readFileSync, rmSync } from 'fs';
12
- import { spawnSync } from 'child_process';
13
- import { fileURLToPath, pathToFileURL } from 'url';
14
- import { tmpdir } from 'os';
15
-
16
- // Helper: convert Windows absolute path to file:// URL for dynamic import
17
- function toFileUrl(p) { return pathToFileURL(p).href; }
18
-
19
- const __dirname = dirname(fileURLToPath(import.meta.url));
20
- const ROOT = join(__dirname, '..');
21
-
22
- let passed = 0;
23
- let failed = 0;
24
-
25
- function ok(label, condition, detail = '') {
26
- if (condition) {
27
- console.log(` ✓ ${label}`);
28
- passed++;
29
- } else {
30
- console.error(` ✗ ${label}${detail ? '\n ' + detail : ''}`);
31
- failed++;
32
- }
33
- }
34
-
35
- function section(title) {
36
- console.log(`\n── ${title} ──`);
37
- }
38
-
39
- // ============================================================================
40
- // 1. output-schema.js — paths and derived constants
41
- // ============================================================================
42
- section('1. output-schema.js exports');
43
-
44
- const {
45
- OUTPUT_SCHEMA, getOutputPath, getAbsoluteOutputPath, getFeatureDir, getAllOutputPaths,
46
- FILENAME_TO_OUTPUT, OUTPUT_PHASE_MAP, PROTECTED_SPEC_FILES,
47
- } = await import(toFileUrl(join(ROOT, 'src/core/paths/output-schema.js')));
48
-
49
- ok('OUTPUT_SCHEMA has 12 keys', Object.keys(OUTPUT_SCHEMA).length === 12);
50
- ok('spec path correct',
51
- getOutputPath('my-feature', 'spec') === '.morph/features/my-feature/1-design/spec.md');
52
- ok('contracts path correct',
53
- getOutputPath('my-feature', 'contracts') === '.morph/features/my-feature/1-design/contracts.cs');
54
- ok('tasks path correct',
55
- getOutputPath('my-feature', 'tasks') === '.morph/features/my-feature/3-tasks/tasks.md');
56
- ok('uiDesignSystem path correct',
57
- getOutputPath('my-feature', 'uiDesignSystem') === '.morph/features/my-feature/2-ui/design-system.md');
58
- ok('clarifications path correct',
59
- getOutputPath('my-feature', 'clarifications') === '.morph/features/my-feature/1-design/clarifications.md');
60
- ok('recap path correct',
61
- getOutputPath('my-feature', 'recap') === '.morph/features/my-feature/4-implement/recap.md');
62
-
63
- const allPaths = Object.keys(OUTPUT_SCHEMA).map(k => getOutputPath('feat', k));
64
- ok('no backslashes in any getOutputPath() result',
65
- allPaths.every(p => !p.includes('\\')),
66
- allPaths.filter(p => p.includes('\\')).join(', ') || 'all clean');
67
-
68
- const absSpec = getAbsoluteOutputPath('/project', 'my-feature', 'spec');
69
- ok('getAbsoluteOutputPath ends with spec.md', absSpec.endsWith('spec.md'));
70
-
71
- const all = getAllOutputPaths('test-feat');
72
- ok('getAllOutputPaths returns 12 entries', Object.keys(all).length === 12);
73
- ok('getAllOutputPaths created:false for all', Object.values(all).every(v => v.created === false));
74
- ok('getAllOutputPaths paths match getOutputPath',
75
- Object.entries(all).every(([k, v]) => v.path === getOutputPath('test-feat', k)));
76
-
77
- ok("FILENAME_TO_OUTPUT['spec.md'] === 'spec'", FILENAME_TO_OUTPUT['spec.md'] === 'spec');
78
- ok("FILENAME_TO_OUTPUT['contracts.cs'] === 'contracts'", FILENAME_TO_OUTPUT['contracts.cs'] === 'contracts');
79
- ok("OUTPUT_PHASE_MAP['spec'] === 'design'", OUTPUT_PHASE_MAP['spec'] === 'design');
80
- ok("OUTPUT_PHASE_MAP['tasks'] === 'tasks'", OUTPUT_PHASE_MAP['tasks'] === 'tasks');
81
- ok("PROTECTED_SPEC_FILES['spec.md'] === 'design'", PROTECTED_SPEC_FILES['spec.md'] === 'design');
82
- ok("PROTECTED_SPEC_FILES['tasks.md'] === 'tasks'", PROTECTED_SPEC_FILES['tasks.md'] === 'tasks');
83
- ok("PROTECTED_SPEC_FILES has no 'proposal.md'", !('proposal.md' in PROTECTED_SPEC_FILES));
84
- ok("getFeatureDir uses forward slashes", !getFeatureDir('x').includes('\\'));
85
- ok("getFeatureDir correct", getFeatureDir('my-feature') === '.morph/features/my-feature');
86
-
87
- // ============================================================================
88
- // 2. state-manager ensureFeature() creates correct paths in state.json
89
- // ============================================================================
90
- section('2. state-manager.js ensureFeature()');
91
-
92
- // Create an isolated temp .morph project
93
- const tempDir = join(tmpdir(), `morph-val-${Date.now()}`);
94
- const morphDir = join(tempDir, '.morph');
95
- const configDir = join(morphDir, 'config');
96
- mkdirSync(configDir, { recursive: true });
97
- mkdirSync(join(morphDir, 'features'), { recursive: true });
98
- mkdirSync(join(morphDir, 'context'), { recursive: true });
99
-
100
- writeFileSync(join(configDir, 'config.json'), JSON.stringify({
101
- framework: 'morph-spec', project: { name: 'test-project' }
102
- }, null, 2));
103
-
104
- const origCwd = process.cwd();
105
- process.chdir(tempDir);
106
-
107
- const { initState, updateFeature, loadState } = await import(toFileUrl(join(ROOT, 'src/core/state/state-manager.js')));
108
- // initState creates state.json; updateFeature calls ensureFeature internally
109
- initState({ name: 'test-project', type: 'test' });
110
- await updateFeature('my-feature', 'status', 'draft');
111
- const state = loadState();
112
- const feat = state.features['my-feature'];
113
-
114
- process.chdir(origCwd);
115
-
116
- ok('ensureFeature creates outputs block', !!feat?.outputs);
117
- ok('outputs has 12 keys', Object.keys(feat?.outputs ?? {}).length === 12);
118
-
119
- let allMatch = true;
120
- const mismatches = [];
121
- for (const [key, { path }] of Object.entries(feat?.outputs ?? {})) {
122
- const expected = getOutputPath('my-feature', key);
123
- if (path !== expected) {
124
- allMatch = false;
125
- mismatches.push(`${key}: got "${path}", expected "${expected}"`);
126
- }
127
- }
128
- ok('ALL output paths match output-schema.js', allMatch, mismatches.join('\n '));
129
-
130
- ok("spec path in state.json",
131
- feat.outputs.spec?.path === '.morph/features/my-feature/1-design/spec.md');
132
- ok("contracts path in state.json",
133
- feat.outputs.contracts?.path === '.morph/features/my-feature/1-design/contracts.cs');
134
- ok("uiDesignSystem path in state.json",
135
- feat.outputs.uiDesignSystem?.path === '.morph/features/my-feature/2-ui/design-system.md');
136
- ok("no backslashes in state.json output paths",
137
- Object.values(feat.outputs).every(({ path }) => !path.includes('\\')));
138
-
139
- // ============================================================================
140
- // 3. v3 → v4 migration uses getAllOutputPaths
141
- // ============================================================================
142
- section('3. v3 → v4 migration');
143
-
144
- // Write a v3.0.0 state in a fresh temp dir
145
- const tempDir2 = join(tmpdir(), `morph-val2-${Date.now()}`);
146
- const morphDir2 = join(tempDir2, '.morph');
147
- const configDir2 = join(morphDir2, 'config');
148
- mkdirSync(configDir2, { recursive: true });
149
- mkdirSync(join(morphDir2, 'features'), { recursive: true });
150
-
151
- const v3State = {
152
- version: '3.0.0',
153
- project: { name: 'legacy', type: 'test' },
154
- features: {
155
- 'legacy-feat': {
156
- status: 'draft', phase: 'design',
157
- outputs: {
158
- spec: { created: true, path: '.morph/features/legacy-feat/spec.md' },
159
- contracts: { created: false, path: '.morph/features/legacy-feat/contracts.cs' },
160
- tasks: { created: false, path: '.morph/features/legacy-feat/tasks.md' },
161
- }
162
- }
163
- },
164
- metadata: { totalFeatures: 1, lastUpdated: new Date().toISOString() }
165
- };
166
- writeFileSync(join(morphDir2, 'state.json'), JSON.stringify(v3State, null, 2));
167
-
168
- process.chdir(tempDir2);
169
- // state-manager is already cached; read the file directly to check migration
170
- // Re-use the already-imported module (ESM cache) — just call loadState directly
171
- const migrated = loadState();
172
- process.chdir(origCwd);
173
-
174
- ok('version migrated to 4.0.0', migrated.version === '4.0.0');
175
- ok('spec path migrated to 1-design subfolder',
176
- migrated.features['legacy-feat'].outputs.spec?.path
177
- === '.morph/features/legacy-feat/1-design/spec.md');
178
- ok('contracts path migrated to 1-design subfolder',
179
- migrated.features['legacy-feat'].outputs.contracts?.path
180
- === '.morph/features/legacy-feat/1-design/contracts.cs');
181
- ok('tasks path migrated to 3-tasks subfolder',
182
- migrated.features['legacy-feat'].outputs.tasks?.path
183
- === '.morph/features/legacy-feat/3-tasks/tasks.md');
184
-
185
- // ============================================================================
186
- // 4. phase-utils.js matches output-schema.js
187
- // ============================================================================
188
- section('4. phase-utils.js constants sync');
189
-
190
- const {
191
- FILENAME_TO_OUTPUT: PU_FTO,
192
- OUTPUT_PHASE_MAP: PU_OPM,
193
- PROTECTED_SPEC_FILES: PU_PSF,
194
- PHASE_DIRS,
195
- } = await import(toFileUrl(join(ROOT, 'framework/hooks/shared/phase-utils.js')));
196
-
197
- ok('FILENAME_TO_OUTPUT matches schema', JSON.stringify(PU_FTO) === JSON.stringify(FILENAME_TO_OUTPUT));
198
- ok('OUTPUT_PHASE_MAP matches schema', JSON.stringify(PU_OPM) === JSON.stringify(OUTPUT_PHASE_MAP));
199
- ok('PROTECTED_SPEC_FILES matches schema', JSON.stringify(PU_PSF) === JSON.stringify(PROTECTED_SPEC_FILES));
200
- ok("PHASE_DIRS['setup'] = '0-proposal' (manual extra)", PHASE_DIRS['setup'] === '0-proposal');
201
- ok("PHASE_DIRS['sync'] = '4-implement' (manual extra)", PHASE_DIRS['sync'] === '4-implement');
202
- ok("PHASE_DIRS['clarify'] = '1-design' (from schema)", PHASE_DIRS['clarify'] === '1-design');
203
-
204
- // ============================================================================
205
- // 5. generate-refs.js --check exits 0
206
- // ============================================================================
207
- section('5. generate-refs.js --check (CI mode)');
208
-
209
- const checkResult = spawnSync(
210
- process.execPath,
211
- [join(ROOT, 'scripts/generate-refs.js'), '--check'],
212
- { encoding: 'utf8' }
213
- );
214
-
215
- ok('exits 0 (no drift)', checkResult.status === 0,
216
- checkResult.status !== 0 ? (checkResult.stdout + checkResult.stderr).trim() : '');
217
- ok('reports all up to date',
218
- (checkResult.stdout || '').includes('OK: All generated refs are in sync'));
219
-
220
- // ============================================================================
221
- // 6. Simulate "add new output type" round-trip
222
- // ============================================================================
223
- section('6. Error handling: invalid output type');
224
-
225
- let threw = false;
226
- try {
227
- getOutputPath('my-feature', 'nonExistentType');
228
- } catch (e) {
229
- threw = e.message.includes('Unknown output type');
230
- }
231
- ok('getOutputPath throws on unknown type', threw);
232
-
233
- let threw2 = false;
234
- try {
235
- getAbsoluteOutputPath('/proj', 'feat', 'bogus');
236
- } catch (e) {
237
- threw2 = e.message.includes('Unknown output type');
238
- }
239
- ok('getAbsoluteOutputPath throws on unknown type', threw2);
240
-
241
- // ============================================================================
242
- // Cleanup + summary
243
- // ============================================================================
244
- try { rmSync(tempDir, { recursive: true, force: true }); } catch {}
245
- try { rmSync(tempDir2, { recursive: true, force: true }); } catch {}
246
-
247
- console.log(`\n${'─'.repeat(52)}`);
248
- console.log(`Results: ${passed} passed, ${failed} failed`);
249
- if (failed === 0) {
250
- console.log('✅ ALL VALIDATIONS PASSED');
251
- process.exit(0);
252
- } else {
253
- console.error('❌ SOME VALIDATIONS FAILED');
254
- process.exit(1);
255
- }
@@ -1,362 +0,0 @@
1
- /**
2
- * MORPH-SPEC Story Creator
3
- * Creates self-contained story files with auto-injected Dev Notes
4
- * Inspired by BMAD Method story-driven development
5
- */
6
-
7
- import fs from 'fs';
8
- import path from 'path';
9
- import yaml from 'yaml';
10
- import ora from 'ora';
11
- import chalk from 'chalk';
12
- import { logger } from '../../utils/logger.js';
13
- import { ensureDir, writeFile } from '../../utils/file-copier.js';
14
- import { getAbsoluteOutputPath } from '../../core/paths/output-schema.js';
15
-
16
- // ============================================================================
17
- // Helper Functions
18
- // ============================================================================
19
-
20
- function resolveTemplatesDir(basePath) {
21
- return path.join(basePath, '.morph', 'framework', 'templates');
22
- }
23
-
24
- function readTemplate(templateName) {
25
- // Try npm-installed package path first (framework templates)
26
- const pkgFrameworkDir = path.join(process.cwd(), 'node_modules/@polymorphism-tech/morph-spec', 'framework', 'templates');
27
- const templatePath = path.join(pkgFrameworkDir, templateName);
28
-
29
- // Fallback to local if in development
30
- if (!fs.existsSync(templatePath)) {
31
- // Check project-local override first, then framework
32
- const localMorphPath = path.join(resolveTemplatesDir(process.cwd()), templateName);
33
- if (fs.existsSync(localMorphPath)) {
34
- return fs.readFileSync(localMorphPath, 'utf-8');
35
- }
36
- throw new Error(`Template not found: ${templateName}`);
37
- }
38
-
39
- return fs.readFileSync(templatePath, 'utf-8');
40
- }
41
-
42
- function readSpec(featureName) {
43
- const specPath = getAbsoluteOutputPath(process.cwd(), featureName, 'spec');
44
- const shardedIndexPath = path.join(process.cwd(), `.morph/features/${featureName}/1-design/spec/index.md`);
45
-
46
- // Try sharded spec first (BMAD pattern)
47
- if (fs.existsSync(shardedIndexPath)) {
48
- return { isSharded: true, indexPath: shardedIndexPath };
49
- }
50
-
51
- // Fallback to monolithic spec
52
- if (fs.existsSync(specPath)) {
53
- return { isSharded: false, content: fs.readFileSync(specPath, 'utf-8') };
54
- }
55
-
56
- throw new Error(`Spec not found for feature: ${featureName}`);
57
- }
58
-
59
- function extractContextFromSpec(specContent, sectionHeading) {
60
- // Extract section content between ## heading and next ##
61
- const regex = new RegExp(`## ${sectionHeading}\\s*([\\s\\S]*?)(?=\\n## |$)`, 'i');
62
- const match = specContent.match(regex);
63
- return match ? match[1].trim() : 'See spec.md for complete context';
64
- }
65
-
66
- function detectPatterns(tasks, specContent) {
67
- const patterns = {
68
- hasEntity: tasks.some(t => /entity|model|domain/i.test(t)),
69
- hasService: tasks.some(t => /service|business|logic/i.test(t)),
70
- hasComponent: tasks.some(t => /component|razor|blazor|ui/i.test(t)),
71
- hasRepository: tasks.some(t => /repository|data|persistence/i.test(t)),
72
- hasJob: tasks.some(t => /job|background|hangfire|scheduled/i.test(t)),
73
- hasAI: tasks.some(t => /agent|ai|llm|semantic|rag/i.test(t)),
74
- hasAzure: tasks.some(t => /bicep|azure|infra|deploy/i.test(t)),
75
- };
76
-
77
- return patterns;
78
- }
79
-
80
- function injectDevNotes(patterns, storyData) {
81
- const notes = [];
82
-
83
- // Entity pattern
84
- if (patterns.hasEntity) {
85
- notes.push('Use Primary Constructor (.NET 10 feature)');
86
- notes.push('Follow entity pattern: .morph/context/coding.md#entity-pattern');
87
- notes.push('Navigation properties: configure in DbContext with Fluent API');
88
- }
89
-
90
- // Service pattern
91
- if (patterns.hasService) {
92
- notes.push('Service layer: implement interface-first (IXService → XService)');
93
- notes.push('Dependency injection: register in Program.cs as Scoped');
94
- notes.push('Error handling: use Result<T> pattern from standards/architecture.md');
95
- }
96
-
97
- // Blazor component
98
- if (patterns.hasComponent) {
99
- notes.push('UI Library: Fluent UI Blazor (see .morph/context/ui.md)');
100
- notes.push('Design System: use CSS variables from wwwroot/css/design-system.css');
101
- notes.push('State management: @inject for services, [Parameter] for props');
102
- }
103
-
104
- // Repository pattern
105
- if (patterns.hasRepository) {
106
- notes.push('Repository pattern: IRepository<T> generic base');
107
- notes.push('EF Core: use AsNoTracking() for read-only queries');
108
- notes.push('Transactions: wrap in DbContext.Database.BeginTransactionAsync()');
109
- }
110
-
111
- // Background job
112
- if (patterns.hasJob) {
113
- notes.push('Hangfire: implement IJob interface, register in HangfireConfig.cs');
114
- notes.push('Retry policy: use [AutomaticRetry(Attempts = 3)]');
115
- notes.push('Logging: inject ILogger<TJob> for monitoring');
116
- }
117
-
118
- // AI/Agent
119
- if (patterns.hasAI) {
120
- notes.push('Microsoft Agent Framework: use AgentBuilder (not Semantic Kernel)');
121
- notes.push('Prompts: store in /prompts/{agent-name}.md');
122
- notes.push('Vector search: use EF Core 10 Vector Search (see standards/backend/database/vector-search-rag.md)');
123
- }
124
-
125
- // Azure/IaC
126
- if (patterns.hasAzure) {
127
- notes.push('Infrastructure as Code: ALWAYS use Bicep (never portal)');
128
- notes.push('Cost validation: run morph-spec cost before commit');
129
- notes.push('Deployment: Azure Container Apps (not App Service)');
130
- }
131
-
132
- // Add spec reference
133
- if (storyData.specShard) {
134
- notes.push(`Spec reference: .morph/features/${storyData.featureName}/1-design/spec/${storyData.specShard}.md`);
135
- } else {
136
- notes.push(`Spec reference: .morph/features/${storyData.featureName}/1-design/spec.md`);
137
- }
138
-
139
- return notes;
140
- }
141
-
142
- function renderStory(template, data) {
143
- // Use Handlebars for rendering instead of manual replacement
144
- // Note: Handlebars helpers like {{titleCase FEATURE_NAME}} are automatically available
145
- // Pre-computed variables like {{FEATURE_NAME_TITLE}} are deprecated
146
- const templateData = {
147
- STORY_ID: data.storyId || 'STORY-XXX',
148
- STORY_TITLE: data.storyTitle || 'Story Title',
149
- FEATURE_NAME: data.featureName || 'feature-name',
150
- EPIC_NAME: data.epicName || 'Epic Name',
151
- DATE: new Date().toISOString().split('T')[0],
152
- STORY_CONTEXT: data.context || 'Context not provided',
153
- SPEC_SHARD: data.specShard || 'spec',
154
- EFFORT: data.effort || '1 day',
155
- CODING_PATTERN: data.codingPattern || 'general',
156
- ARCH_PATTERN: data.archPattern || 'clean-architecture',
157
- STATUS: 'Ready',
158
- CREATED_DATE: new Date().toISOString().split('T')[0],
159
- ADDITIONAL_NOTES: data.additionalNotes || '',
160
- };
161
-
162
- // Import Handlebars at runtime if needed
163
- // For now, use simple replacement but template should use {{titleCase FEATURE_NAME}}
164
- let rendered = template;
165
-
166
- for (const [key, value] of Object.entries(templateData)) {
167
- rendered = rendered.replaceAll(`{{${key}}}`, value);
168
- }
169
-
170
- // Handle arrays (tasks, dev notes, acceptance criteria)
171
- if (data.tasks && data.tasks.length > 0) {
172
- const tasksSection = data.tasks.map(t => `- [ ] ${t}`).join('\n');
173
- rendered = rendered.replace(/{{#TASKS}}[\s\S]*?{{\/TASKS}}/g, tasksSection);
174
- } else {
175
- rendered = rendered.replace(/{{#TASKS}}[\s\S]*?{{\/TASKS}}/g, '- [ ] Task 1\n- [ ] Task 2');
176
- }
177
-
178
- if (data.devNotes && data.devNotes.length > 0) {
179
- const devNotesSection = data.devNotes.map(n => `- ${n}`).join('\n');
180
- rendered = rendered.replace(/{{#DEV_NOTES}}[\s\S]*?{{\/DEV_NOTES}}/g, devNotesSection);
181
- } else {
182
- rendered = rendered.replace(/{{#DEV_NOTES}}[\s\S]*?{{\/DEV_NOTES}}/g, '- Follow standards in .morph/context/');
183
- }
184
-
185
- if (data.acceptanceCriteria && data.acceptanceCriteria.length > 0) {
186
- const acSection = data.acceptanceCriteria.map(ac =>
187
- `- [ ] **GIVEN** ${ac.given} **WHEN** ${ac.when} **THEN** ${ac.then}`
188
- ).join('\n');
189
- rendered = rendered.replace(/{{#ACCEPTANCE_CRITERIA}}[\s\S]*?{{\/ACCEPTANCE_CRITERIA}}/g, acSection);
190
- } else {
191
- rendered = rendered.replace(/{{#ACCEPTANCE_CRITERIA}}[\s\S]*?{{\/ACCEPTANCE_CRITERIA}}/g,
192
- '- [ ] **GIVEN** [condition] **WHEN** [action] **THEN** [result]');
193
- }
194
-
195
- // Clean up remaining Mustache sections (empty arrays)
196
- rendered = rendered.replace(/{{#\w+}}[\s\S]*?{{\/\w+}}/g, '');
197
-
198
- return rendered;
199
- }
200
-
201
- function toTitleCase(str) {
202
- return str
203
- .split('-')
204
- .map(word => word.charAt(0).toUpperCase() + word.slice(1))
205
- .join(' ');
206
- }
207
-
208
- // ============================================================================
209
- // Command Function
210
- // ============================================================================
211
-
212
- export async function createStoryCommand(feature, storyId, options) {
213
- logger.header('MORPH-SPEC Story Creator');
214
- logger.dim(`Feature: ${feature}`);
215
- logger.dim(`Story ID: ${storyId}`);
216
- logger.blank();
217
-
218
- const spinner = ora('Creating story...').start();
219
-
220
- try {
221
- // Read template
222
- const template = readTemplate('story.md');
223
-
224
- // Read spec (detect if sharded)
225
- const spec = readSpec(feature);
226
-
227
- // Build story data
228
- const storyData = {
229
- featureName: feature,
230
- featureNameTitle: toTitleCase(feature),
231
- storyId,
232
- storyTitle: options.title || 'Story Title',
233
- epicName: options.epic || toTitleCase(feature),
234
- context: options.context || (spec.isSharded
235
- ? 'See sharded spec for complete context'
236
- : extractContextFromSpec(spec.content, 'Overview')),
237
- specShard: spec.isSharded ? 'index' : null,
238
- tasks: options.tasks ? options.tasks.split(',').map(t => t.trim()) : ['Task 1', 'Task 2'],
239
- effort: '1 day',
240
- additionalNotes: '',
241
- };
242
-
243
- // Detect patterns and inject Dev Notes
244
- const patterns = detectPatterns(storyData.tasks, spec.content || '');
245
- storyData.devNotes = injectDevNotes(patterns, storyData);
246
-
247
- // Default acceptance criteria
248
- storyData.acceptanceCriteria = [
249
- { given: '[condition]', when: '[action]', then: '[expected result]' },
250
- ];
251
-
252
- // Render story
253
- const renderedStory = renderStory(template, storyData);
254
-
255
- // Output
256
- const outputDir = path.join(process.cwd(), `.morph/features/${feature}/stories`);
257
- const outputPath = path.join(outputDir, `${storyId}.md`);
258
-
259
- if (options.dryRun) {
260
- spinner.info('Dry run - preview only');
261
- logger.blank();
262
- console.log(renderedStory);
263
- logger.blank();
264
- logger.dim(`Would be written to: ${outputPath}`);
265
- } else {
266
- // Ensure directory exists
267
- await ensureDir(outputDir);
268
-
269
- // Write file
270
- await writeFile(outputPath, renderedStory);
271
-
272
- // ============================================================================
273
- // Update sprint-status.yaml (create if doesn't exist)
274
- // ============================================================================
275
- const sprintStatusPath = path.join(process.cwd(), `.morph/features/${feature}/sprint-status.yaml`);
276
- let sprintStatus;
277
-
278
- if (fs.existsSync(sprintStatusPath)) {
279
- // Load existing
280
- const content = fs.readFileSync(sprintStatusPath, 'utf-8');
281
- sprintStatus = yaml.parse(content);
282
- } else {
283
- // Create new
284
- sprintStatus = {
285
- feature: feature,
286
- epic: options.epic || toTitleCase(feature),
287
- created: new Date().toISOString().split('T')[0],
288
- updated: new Date().toISOString().split('T')[0],
289
- stories: [],
290
- metrics: {
291
- total_stories: 0,
292
- ready: 0,
293
- in_progress: 0,
294
- ready_for_qa: 0,
295
- done: 0,
296
- completion_percent: 0
297
- },
298
- current: null,
299
- next: null
300
- };
301
- }
302
-
303
- // Add new story to sprint-status
304
- sprintStatus.stories.push({
305
- id: storyId,
306
- title: storyData.storyTitle,
307
- file: `stories/${storyId}.md`,
308
- status: 'ready',
309
- created: new Date().toISOString().split('T')[0],
310
- assigned: null,
311
- started: null,
312
- completed: null
313
- });
314
-
315
- // Update metrics
316
- sprintStatus.metrics.total_stories = sprintStatus.stories.length;
317
- sprintStatus.metrics.ready = sprintStatus.stories.filter(s => s.status === 'ready').length;
318
- sprintStatus.metrics.in_progress = sprintStatus.stories.filter(s => s.status === 'in_progress').length;
319
- sprintStatus.metrics.ready_for_qa = sprintStatus.stories.filter(s => s.status === 'ready_for_qa').length;
320
- sprintStatus.metrics.done = sprintStatus.stories.filter(s => s.status === 'done').length;
321
- sprintStatus.metrics.completion_percent = sprintStatus.stories.length > 0
322
- ? Math.round((sprintStatus.metrics.done / sprintStatus.stories.length) * 100)
323
- : 0;
324
- sprintStatus.updated = new Date().toISOString().split('T')[0];
325
-
326
- // Set next story if null
327
- if (!sprintStatus.next) {
328
- sprintStatus.next = {
329
- story_id: storyId,
330
- recommendation: `Story ${storyId} is ready for development`
331
- };
332
- }
333
-
334
- // Write sprint-status.yaml
335
- const yamlContent = yaml.stringify(sprintStatus);
336
- fs.writeFileSync(sprintStatusPath, yamlContent);
337
-
338
- spinner.succeed('Story created!');
339
- logger.blank();
340
-
341
- logger.success(`Story file: ${chalk.cyan(outputPath)}`);
342
- logger.success(`Updated: ${chalk.cyan('sprint-status.yaml')}`);
343
- logger.blank();
344
-
345
- logger.header('Dev Notes Auto-Injected:');
346
- storyData.devNotes.forEach(note => logger.dim(` - ${note}`));
347
- logger.blank();
348
-
349
- logger.header('Next Steps:');
350
- logger.dim(' 1. Review and customize story file');
351
- logger.dim(' 2. Run in fresh Claude session: /dev → implement story');
352
- logger.dim(' 3. Dev adds implementation notes');
353
- logger.dim(' 4. QA reviews and adds QA notes');
354
- logger.blank();
355
- }
356
-
357
- } catch (error) {
358
- spinner.fail('Failed to create story');
359
- logger.error(error.message);
360
- process.exit(1);
361
- }
362
- }
@@ -1,6 +0,0 @@
1
- /**
2
- * Feature Management Commands
3
- */
4
- export { createStoryCommand } from './create-story.js';
5
- export { shardSpecCommand } from './shard-spec.js';
6
- export { sprintStatusCommand } from './sprint-status.js';