@polymorphism-tech/morph-spec 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/CLAUDE.md +68 -400
  2. package/README.md +198 -76
  3. package/bin/detect-agents.js +227 -225
  4. package/bin/morph-spec.js +10 -0
  5. package/bin/render-template.js +303 -302
  6. package/bin/semantic-detect-agents.js +247 -246
  7. package/bin/{task-manager.js → task-manager.cjs} +12 -1
  8. package/bin/validate-agents-skills.js +257 -251
  9. package/bin/validate-agents.js +70 -69
  10. package/bin/validate-phase.js +263 -263
  11. package/docs/getting-started.md +3 -3
  12. package/package.json +3 -4
  13. package/scripts/reorganize-skills.cjs +175 -0
  14. package/scripts/validate-agents-structure.cjs +52 -0
  15. package/scripts/validate-skills.cjs +180 -0
  16. package/src/commands/create-story.js +354 -351
  17. package/src/commands/detect-agents.js +13 -2
  18. package/src/commands/detect.js +104 -104
  19. package/src/commands/state.js +334 -333
  20. package/src/commands/sync.js +167 -167
  21. package/src/commands/task.js +1 -1
  22. package/src/commands/update.js +13 -1
  23. package/src/lib/context-generator.js +7 -4
  24. package/{detectors → src/lib/detectors}/config-detector.js +223 -223
  25. package/{detectors → src/lib/detectors}/conversation-analyzer.js +163 -163
  26. package/{detectors → src/lib/detectors}/index.js +84 -84
  27. package/{detectors → src/lib/detectors}/standards-generator.js +275 -275
  28. package/src/lib/hook-executor.js +2 -1
  29. package/src/lib/stack-resolver.js +148 -0
  30. package/src/lib/standards-context-injector.js +4 -3
  31. package/src/lib/state-manager.js +21 -4
  32. package/src/lib/team-orchestrator.js +2 -1
  33. package/src/lib/troubleshoot-grep.js +13 -3
  34. package/src/lib/validation-runner.js +2 -1
  35. package/src/utils/file-copier.js +3 -1
  36. package/{content → stacks/blazor-azure}/.azure/README.md +293 -293
  37. package/{content → stacks/blazor-azure}/.azure/docs/azure-devops-setup.md +454 -454
  38. package/{content → stacks/blazor-azure}/.azure/docs/branch-strategy.md +398 -398
  39. package/{content → stacks/blazor-azure}/.azure/docs/local-development.md +515 -515
  40. package/{content → stacks/blazor-azure}/.azure/pipelines/pipeline-variables.yml +34 -34
  41. package/{content → stacks/blazor-azure}/.azure/pipelines/prod-pipeline.yml +319 -319
  42. package/{content → stacks/blazor-azure}/.azure/pipelines/staging-pipeline.yml +234 -234
  43. package/{content → stacks/blazor-azure}/.azure/pipelines/templates/build-dotnet.yml +75 -75
  44. package/{content → stacks/blazor-azure}/.azure/pipelines/templates/deploy-app-service.yml +94 -94
  45. package/{content → stacks/blazor-azure}/.azure/pipelines/templates/deploy-container-app.yml +120 -120
  46. package/{content → stacks/blazor-azure}/.azure/pipelines/templates/infra-deploy.yml +90 -90
  47. package/{content → stacks/blazor-azure}/.claude/commands/morph-archive.md +79 -79
  48. package/{content → stacks/blazor-azure}/.claude/commands/morph-deploy.md +529 -529
  49. package/{content → stacks/blazor-azure}/.claude/commands/morph-infra.md +209 -209
  50. package/{content → stacks/blazor-azure}/.claude/commands/morph-troubleshoot.md +1 -1
  51. package/{content → stacks/blazor-azure}/.claude/settings.local.json +15 -15
  52. package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-setup.md +1 -1
  53. package/{content/.claude/skills/specialists → stacks/blazor-azure/.claude/skills/level-2-domains/architecture}/prompt-engineer.md +189 -189
  54. package/{content/.claude/skills/specialists → stacks/blazor-azure/.claude/skills/level-2-domains/architecture}/seo-growth-hacker.md +320 -320
  55. package/{content/.claude/skills/infra → stacks/blazor-azure/.claude/skills/level-2-domains/infrastructure}/azure-deploy-specialist.md +699 -699
  56. package/{content → stacks/blazor-azure}/.morph/.morphversion +5 -5
  57. package/{content → stacks/blazor-azure}/.morph/archive/.gitkeep +25 -25
  58. package/{content → stacks/blazor-azure}/.morph/config/agents.json +7 -5
  59. package/{content → stacks/blazor-azure}/.morph/docs/STORY-DRIVEN-DEVELOPMENT.md +392 -392
  60. package/{content → stacks/blazor-azure}/.morph/docs/workflows/enforcement-pipeline.md +3 -3
  61. package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/README.md +241 -241
  62. package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/contracts.ts +307 -307
  63. package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/spec.md +399 -399
  64. package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/tasks.md +168 -168
  65. package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/README.md +125 -125
  66. package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/contracts.cs +358 -358
  67. package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/decisions.md +246 -246
  68. package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/spec.md +236 -236
  69. package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/tasks.md +150 -150
  70. package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/README.md +309 -309
  71. package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/contracts.cs +433 -433
  72. package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/spec.md +479 -479
  73. package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/tasks.md +185 -185
  74. package/{content → stacks/blazor-azure}/.morph/examples/state-v3.json +188 -188
  75. package/{content → stacks/blazor-azure}/.morph/features/.gitkeep +25 -25
  76. package/{content → stacks/blazor-azure}/.morph/hooks/README.md +12 -12
  77. package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-all.sh +48 -48
  78. package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-specs.sh +49 -49
  79. package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-tests.sh +60 -60
  80. package/{content → stacks/blazor-azure}/.morph/project.md +160 -160
  81. package/{content → stacks/blazor-azure}/.morph/schemas/agent.schema.json +296 -296
  82. package/{content → stacks/blazor-azure}/.morph/specs/.gitkeep +20 -20
  83. package/{content → stacks/blazor-azure}/.morph/standards/agent-teams-workflow.md +2 -2
  84. package/{content → stacks/blazor-azure}/.morph/standards/coding.md +377 -377
  85. package/{content → stacks/blazor-azure}/.morph/standards/fluent-ui-setup.md +590 -590
  86. package/{content → stacks/blazor-azure}/.morph/standards/migration-guide.md +514 -514
  87. package/{content → stacks/blazor-azure}/.morph/standards/passkeys-auth.md +423 -423
  88. package/{content → stacks/blazor-azure}/.morph/standards/vector-search-rag.md +536 -536
  89. package/{content → stacks/blazor-azure}/.morph/state.json +17 -17
  90. package/{content → stacks/blazor-azure}/.morph/templates/FluentDesignTheme.cs +149 -149
  91. package/{content → stacks/blazor-azure}/.morph/templates/MudTheme.cs +281 -281
  92. package/{content → stacks/blazor-azure}/.morph/templates/component.razor +239 -239
  93. package/{content → stacks/blazor-azure}/.morph/templates/contracts.cs +217 -217
  94. package/{content → stacks/blazor-azure}/.morph/templates/design-system.css +226 -226
  95. package/{content → stacks/blazor-azure}/.morph/templates/infra/.dockerignore.example +89 -89
  96. package/{content → stacks/blazor-azure}/.morph/templates/infra/Dockerfile.example +82 -82
  97. package/{content → stacks/blazor-azure}/.morph/templates/infra/README.md +286 -286
  98. package/{content → stacks/blazor-azure}/.morph/templates/infra/app-insights.bicep +63 -63
  99. package/{content → stacks/blazor-azure}/.morph/templates/infra/app-service.bicep +164 -164
  100. package/{content → stacks/blazor-azure}/.morph/templates/infra/azure-pipelines-deploy.yml +480 -480
  101. package/{content → stacks/blazor-azure}/.morph/templates/infra/container-app-env.bicep +49 -49
  102. package/{content → stacks/blazor-azure}/.morph/templates/infra/container-app.bicep +156 -156
  103. package/{content → stacks/blazor-azure}/.morph/templates/infra/deploy.ps1 +229 -229
  104. package/{content → stacks/blazor-azure}/.morph/templates/infra/deploy.sh +208 -208
  105. package/{content → stacks/blazor-azure}/.morph/templates/infra/key-vault.bicep +91 -91
  106. package/{content → stacks/blazor-azure}/.morph/templates/infra/main.bicep +189 -189
  107. package/{content → stacks/blazor-azure}/.morph/templates/infra/parameters.dev.json +29 -29
  108. package/{content → stacks/blazor-azure}/.morph/templates/infra/parameters.prod.json +29 -29
  109. package/{content → stacks/blazor-azure}/.morph/templates/infra/parameters.staging.json +29 -29
  110. package/{content → stacks/blazor-azure}/.morph/templates/infra/sql-database.bicep +103 -103
  111. package/{content → stacks/blazor-azure}/.morph/templates/infra/storage.bicep +106 -106
  112. package/{content → stacks/blazor-azure}/.morph/templates/integrations/asaas-client.cs +387 -387
  113. package/{content → stacks/blazor-azure}/.morph/templates/integrations/asaas-webhook.cs +351 -351
  114. package/{content → stacks/blazor-azure}/.morph/templates/integrations/azure-identity-config.cs +288 -288
  115. package/{content → stacks/blazor-azure}/.morph/templates/integrations/clerk-config.cs +258 -258
  116. package/{content → stacks/blazor-azure}/.morph/templates/job.cs +171 -171
  117. package/{content → stacks/blazor-azure}/.morph/templates/migration.cs +83 -83
  118. package/{content → stacks/blazor-azure}/.morph/templates/repository.cs +141 -141
  119. package/{content → stacks/blazor-azure}/.morph/templates/saas/subscription.cs +347 -347
  120. package/{content → stacks/blazor-azure}/.morph/templates/saas/tenant.cs +338 -338
  121. package/{content → stacks/blazor-azure}/.morph/templates/service.cs +139 -139
  122. package/{content → stacks/blazor-azure}/.morph/templates/sprint-status.yaml +68 -68
  123. package/{content → stacks/blazor-azure}/.morph/templates/story.md +143 -143
  124. package/{content → stacks/blazor-azure}/.morph/templates/test.cs +239 -239
  125. package/{content → stacks/blazor-azure}/.morph/templates/ui-design-system.md +286 -286
  126. package/{content → stacks/blazor-azure}/.morph/templates/ui-flows.md +336 -336
  127. package/{content → stacks/blazor-azure}/.morph/templates/ui-mockups.md +133 -133
  128. package/{content → stacks/blazor-azure}/.morph/test-infra/example.bicep +59 -59
  129. package/{content → stacks/blazor-azure}/README.md +79 -79
  130. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/backend/dotnet-supabase.md +244 -0
  131. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/frontend/nextjs-supabase.md +335 -0
  132. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/infrastructure/easypanel-deployer.md +189 -0
  133. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/integrations/supabase-expert.md +170 -0
  134. package/stacks/nextjs-supabase/.morph/config/agents.json +345 -0
  135. package/stacks/nextjs-supabase/.morph/config/config.template.json +92 -0
  136. package/stacks/nextjs-supabase/.morph/docs/easypanel-setup.md +169 -0
  137. package/stacks/nextjs-supabase/.morph/docs/supabase-mcp-setup.md +247 -0
  138. package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/README.md +697 -0
  139. package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/spec.md +85 -0
  140. package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/tasks.md +86 -0
  141. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/README.md +498 -0
  142. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/decisions.md +121 -0
  143. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/spec.md +138 -0
  144. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/tasks.md +162 -0
  145. package/stacks/nextjs-supabase/.morph/project.md +168 -0
  146. package/stacks/nextjs-supabase/.morph/standards/easypanel-deploy.md +191 -0
  147. package/stacks/nextjs-supabase/.morph/standards/nextjs-patterns.md +193 -0
  148. package/stacks/nextjs-supabase/.morph/standards/supabase-auth.md +171 -0
  149. package/stacks/nextjs-supabase/.morph/standards/supabase-pgvector.md +164 -0
  150. package/stacks/nextjs-supabase/.morph/standards/supabase-rls.md +179 -0
  151. package/stacks/nextjs-supabase/.morph/standards/supabase-storage.md +148 -0
  152. package/stacks/nextjs-supabase/.morph/templates/contracts.cs +173 -0
  153. package/stacks/nextjs-supabase/.morph/templates/contracts.ts +168 -0
  154. package/stacks/nextjs-supabase/.morph/templates/decisions.md +115 -0
  155. package/stacks/nextjs-supabase/.morph/templates/dockerfile-api.dockerfile +38 -0
  156. package/stacks/nextjs-supabase/.morph/templates/dockerfile-web.dockerfile +48 -0
  157. package/stacks/nextjs-supabase/.morph/templates/proposal.md +145 -0
  158. package/stacks/nextjs-supabase/.morph/templates/recap.md +134 -0
  159. package/stacks/nextjs-supabase/.morph/templates/rls-policy.sql +57 -0
  160. package/stacks/nextjs-supabase/.morph/templates/spec.md +231 -0
  161. package/stacks/nextjs-supabase/.morph/templates/supabase-migration.sql +100 -0
  162. package/stacks/nextjs-supabase/.morph/templates/tasks.md +257 -0
  163. package/stacks/nextjs-supabase/CLAUDE.md +149 -0
  164. package/stacks/nextjs-supabase/README.md +112 -0
  165. /package/{detectors → src/lib/detectors}/structure-detector.js +0 -0
  166. /package/{content → stacks/blazor-azure}/.claude/commands/morph-apply.md +0 -0
  167. /package/{content → stacks/blazor-azure}/.claude/commands/morph-preflight.md +0 -0
  168. /package/{content → stacks/blazor-azure}/.claude/commands/morph-proposal.md +0 -0
  169. /package/{content → stacks/blazor-azure}/.claude/commands/morph-status.md +0 -0
  170. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/README.md +0 -0
  171. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/code-review.md +0 -0
  172. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/morph-checklist.md +0 -0
  173. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/simulation-checklist.md +0 -0
  174. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/README.md +0 -0
  175. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/morph-replicate.md +0 -0
  176. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-clarify.md +0 -0
  177. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-design.md +0 -0
  178. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-tasks.md +0 -0
  179. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-uiux.md +0 -0
  180. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/README.md +0 -0
  181. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/ai-agents/ai-system-architect.md +0 -0
  182. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/architecture/po-pm-advisor.md +0 -0
  183. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/architecture/standards-architect.md +0 -0
  184. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/dotnet-senior.md +0 -0
  185. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/ef-modeler.md +0 -0
  186. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/hangfire-orchestrator.md +0 -0
  187. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/ms-agent-expert.md +0 -0
  188. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/frontend/blazor-builder.md +0 -0
  189. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/frontend/nextjs-expert.md +0 -0
  190. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/frontend/ui-ux-designer.md +0 -0
  191. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/azure-architect.md +0 -0
  192. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/bicep-architect.md +0 -0
  193. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/container-specialist.md +0 -0
  194. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/devops-engineer.md +0 -0
  195. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/asaas-financial.md +0 -0
  196. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/azure-identity.md +0 -0
  197. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/clerk-auth.md +0 -0
  198. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/resend-email.md +0 -0
  199. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/quality/code-analyzer.md +0 -0
  200. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/quality/testing-specialist.md +0 -0
  201. /package/{content → stacks/blazor-azure}/.claude/skills/level-3-technologies/README.md +0 -0
  202. /package/{content → stacks/blazor-azure}/.claude/skills/level-4-patterns/README.md +0 -0
  203. /package/{content → stacks/blazor-azure}/.morph/config/config.template.json +0 -0
  204. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/design-impl.md +0 -0
  205. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/fast-track.md +0 -0
  206. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/full-morph.md +0 -0
  207. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/standard.md +0 -0
  208. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/ui-refresh.md +0 -0
  209. /package/{content → stacks/blazor-azure}/.morph/examples/scheduled-reports/decisions.md +0 -0
  210. /package/{content → stacks/blazor-azure}/.morph/examples/scheduled-reports/proposal.md +0 -0
  211. /package/{content → stacks/blazor-azure}/.morph/examples/scheduled-reports/spec.md +0 -0
  212. /package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-agents.sh +0 -0
  213. /package/{content → stacks/blazor-azure}/.morph/hooks/task-completed.js +0 -0
  214. /package/{content → stacks/blazor-azure}/.morph/hooks/teammate-idle.js +0 -0
  215. /package/{content → stacks/blazor-azure}/.morph/schemas/tasks.schema.json +0 -0
  216. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-blazor-ui.md +0 -0
  217. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-production.md +0 -0
  218. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-setup.md +0 -0
  219. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-workflows.md +0 -0
  220. /package/{content → stacks/blazor-azure}/.morph/standards/architecture.md +0 -0
  221. /package/{content → stacks/blazor-azure}/.morph/standards/azure.md +0 -0
  222. /package/{content → stacks/blazor-azure}/.morph/standards/dotnet10-migration.md +0 -0
  223. /package/{content → stacks/blazor-azure}/.morph/templates/CONTEXT-FEATURE.md +0 -0
  224. /package/{content → stacks/blazor-azure}/.morph/templates/CONTEXT.md +0 -0
  225. /package/{content → stacks/blazor-azure}/.morph/templates/agent.cs +0 -0
  226. /package/{content → stacks/blazor-azure}/.morph/templates/clarify-questions.md +0 -0
  227. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/Commands.cs +0 -0
  228. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/Entities.cs +0 -0
  229. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/Queries.cs +0 -0
  230. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/README.md +0 -0
  231. /package/{content → stacks/blazor-azure}/.morph/templates/decisions.md +0 -0
  232. /package/{content → stacks/blazor-azure}/.morph/templates/infra/deploy-checklist.md +0 -0
  233. /package/{content → stacks/blazor-azure}/.morph/templates/proposal.md +0 -0
  234. /package/{content → stacks/blazor-azure}/.morph/templates/recap.md +0 -0
  235. /package/{content → stacks/blazor-azure}/.morph/templates/simulation.md +0 -0
  236. /package/{content → stacks/blazor-azure}/.morph/templates/spec.md +0 -0
  237. /package/{content → stacks/blazor-azure}/.morph/templates/state.template.json +0 -0
  238. /package/{content → stacks/blazor-azure}/.morph/templates/tasks.md +0 -0
  239. /package/{content → stacks/blazor-azure}/.morph/templates/ui-components.md +0 -0
  240. /package/{content → stacks/blazor-azure}/CLAUDE.md +0 -0
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Stack Resolver - Centralized stack path resolution for multi-stack support.
3
+ *
4
+ * Detects the active stack and resolves all stack-relative paths.
5
+ * Resolution order: explicit > config.json > state.json > auto-detect > fallback
6
+ *
7
+ * @module stack-resolver
8
+ */
9
+
10
+ import { readFileSync, existsSync, readdirSync } from 'fs';
11
+ import { join } from 'path';
12
+
13
+ const STACK_TYPE_TO_DIR = {
14
+ 'blazor-server': 'blazor-azure',
15
+ 'blazor-azure': 'blazor-azure',
16
+ 'nextjs-supabase': 'nextjs-supabase',
17
+ };
18
+
19
+ // Module-level override set by CLI --stack flag via setGlobalStack()
20
+ let _globalStackOverride = null;
21
+
22
+ /**
23
+ * Set a global stack override (called by CLI --stack flag).
24
+ * Once set, all resolveStackId() calls use this value unless
25
+ * an explicit parameter is provided.
26
+ * @param {string} stackId - Stack identifier
27
+ */
28
+ export function setGlobalStack(stackId) {
29
+ _globalStackOverride = stackId;
30
+ }
31
+
32
+ /**
33
+ * Detect which stack directory to use.
34
+ *
35
+ * Resolution order:
36
+ * 1. explicitStack parameter (from CLI --stack flag)
37
+ * 2. .morph/config/config.json → project.type
38
+ * 3. .morph/state.json → project.type
39
+ * 4. Auto-detect: scan stacks/ for existing directories
40
+ * 5. Fallback: 'blazor-azure'
41
+ *
42
+ * @param {string} projectPath - Absolute path to project root
43
+ * @param {string} [explicitStack] - Override from CLI --stack flag
44
+ * @returns {string} Stack directory name (e.g., 'blazor-azure', 'nextjs-supabase')
45
+ */
46
+ export function resolveStackId(projectPath, explicitStack) {
47
+ // 1. Explicit parameter override
48
+ if (explicitStack) {
49
+ return STACK_TYPE_TO_DIR[explicitStack] || explicitStack;
50
+ }
51
+
52
+ // 1b. Global CLI --stack override
53
+ if (_globalStackOverride) {
54
+ return STACK_TYPE_TO_DIR[_globalStackOverride] || _globalStackOverride;
55
+ }
56
+
57
+ // 2. config.json → project.type
58
+ try {
59
+ const configPath = join(projectPath, '.morph/config/config.json');
60
+ if (existsSync(configPath)) {
61
+ const config = JSON.parse(readFileSync(configPath, 'utf8'));
62
+ const projectType = config?.project?.type;
63
+ if (projectType && STACK_TYPE_TO_DIR[projectType]) {
64
+ return STACK_TYPE_TO_DIR[projectType];
65
+ }
66
+ }
67
+ } catch { /* continue to next source */ }
68
+
69
+ // 3. state.json → project.type
70
+ try {
71
+ const statePath = join(projectPath, '.morph/state.json');
72
+ if (existsSync(statePath)) {
73
+ const state = JSON.parse(readFileSync(statePath, 'utf8'));
74
+ const projectType = state?.project?.type;
75
+ if (projectType && STACK_TYPE_TO_DIR[projectType]) {
76
+ return STACK_TYPE_TO_DIR[projectType];
77
+ }
78
+ }
79
+ } catch { /* continue to next source */ }
80
+
81
+ // 4. Auto-detect: first directory in stacks/
82
+ try {
83
+ const stacksDir = join(projectPath, 'stacks');
84
+ if (existsSync(stacksDir)) {
85
+ const dirs = readdirSync(stacksDir, { withFileTypes: true })
86
+ .filter(d => d.isDirectory())
87
+ .map(d => d.name);
88
+ if (dirs.length === 1) {
89
+ return dirs[0];
90
+ }
91
+ }
92
+ } catch { /* continue to fallback */ }
93
+
94
+ // 5. Fallback
95
+ return 'blazor-azure';
96
+ }
97
+
98
+ /**
99
+ * Get absolute path to the active stack's root directory.
100
+ * @param {string} projectPath
101
+ * @param {string} [explicitStack]
102
+ * @returns {string}
103
+ */
104
+ export function resolveStackPath(projectPath, explicitStack) {
105
+ return join(projectPath, 'stacks', resolveStackId(projectPath, explicitStack));
106
+ }
107
+
108
+ /**
109
+ * Get absolute path to the active stack's agents.json.
110
+ * @param {string} projectPath
111
+ * @param {string} [explicitStack]
112
+ * @returns {string}
113
+ */
114
+ export function resolveAgentsConfigPath(projectPath, explicitStack) {
115
+ return join(resolveStackPath(projectPath, explicitStack), '.morph/config/agents.json');
116
+ }
117
+
118
+ /**
119
+ * Get absolute path to the active stack's standards directory.
120
+ * @param {string} projectPath
121
+ * @param {string} [explicitStack]
122
+ * @returns {string}
123
+ */
124
+ export function resolveStandardsDir(projectPath, explicitStack) {
125
+ return join(resolveStackPath(projectPath, explicitStack), '.morph/standards');
126
+ }
127
+
128
+ /**
129
+ * Get absolute path to the active stack's templates directory.
130
+ * @param {string} projectPath
131
+ * @param {string} [explicitStack]
132
+ * @returns {string}
133
+ */
134
+ export function resolveTemplatesDir(projectPath, explicitStack) {
135
+ return join(resolveStackPath(projectPath, explicitStack), '.morph/templates');
136
+ }
137
+
138
+ /**
139
+ * Get absolute path to the active stack's config directory.
140
+ * @param {string} projectPath
141
+ * @param {string} [explicitStack]
142
+ * @returns {string}
143
+ */
144
+ export function resolveConfigDir(projectPath, explicitStack) {
145
+ return join(resolveStackPath(projectPath, explicitStack), '.morph/config');
146
+ }
147
+
148
+ export { STACK_TYPE_TO_DIR };
@@ -9,6 +9,7 @@
9
9
 
10
10
  import { readFileSync, existsSync } from 'fs';
11
11
  import { join } from 'path';
12
+ import { resolveStandardsDir } from './stack-resolver.js';
12
13
 
13
14
  /**
14
15
  * Agent → Standards mapping
@@ -191,8 +192,8 @@ function loadStandard(standardName, projectPath) {
191
192
  const locations = [
192
193
  // 1. Project override
193
194
  join(projectPath, '.morph/project/standards', `${standardName}.md`),
194
- // 2. Content standards (AI/Agent Framework, Azure, etc.)
195
- join(projectPath, 'content/.morph/standards', `${standardName}.md`),
195
+ // 2. Stack standards (resolved dynamically based on project type)
196
+ join(resolveStandardsDir(projectPath), `${standardName}.md`),
196
197
  // 3. Framework standards (Blazor, CSS, .NET)
197
198
  join(projectPath, 'framework/standards', `${standardName}.md`)
198
199
  ];
@@ -273,7 +274,7 @@ export function getStandardsListForAgent(agentId) {
273
274
  export function checkStandardExists(standardName, projectPath = '.') {
274
275
  const locations = [
275
276
  { type: 'project', path: join(projectPath, '.morph/project/standards', `${standardName}.md`) },
276
- { type: 'content', path: join(projectPath, 'content/.morph/standards', `${standardName}.md`) },
277
+ { type: 'stack', path: join(resolveStandardsDir(projectPath), `${standardName}.md`) },
277
278
  { type: 'framework', path: join(projectPath, 'framework/standards', `${standardName}.md`) }
278
279
  ];
279
280
 
@@ -291,6 +291,21 @@ export function removeAgent(featureName, agentId) {
291
291
  return false;
292
292
  }
293
293
 
294
+ /**
295
+ * Normalize output type from kebab-case to camelCase for UI types (BUG #12 fix)
296
+ * @param {string} type - Output type (e.g., 'ui-design-system' or 'uiDesignSystem')
297
+ * @returns {string} Normalized type in camelCase
298
+ */
299
+ function normalizeOutputType(type) {
300
+ const kebabMap = {
301
+ 'ui-design-system': 'uiDesignSystem',
302
+ 'ui-mockups': 'uiMockups',
303
+ 'ui-components': 'uiComponents',
304
+ 'ui-flows': 'uiFlows'
305
+ };
306
+ return kebabMap[type] || type;
307
+ }
308
+
294
309
  /**
295
310
  * Mark output as created
296
311
  * @param {string} featureName - Feature name
@@ -300,15 +315,17 @@ export function markOutput(featureName, outputType) {
300
315
  ensureFeature(featureName);
301
316
  const state = loadState();
302
317
 
303
- if (!state.features[featureName].outputs[outputType]) {
304
- throw new Error(`Output type '${outputType}' not valid. Valid types: proposal, spec, contracts, tasks, uiDesignSystem, uiMockups, uiComponents, uiFlows, decisions, recap`);
318
+ const normalized = normalizeOutputType(outputType);
319
+
320
+ if (!state.features[featureName].outputs[normalized]) {
321
+ throw new Error(`Output type '${outputType}' not valid. Valid types: proposal, spec, contracts, tasks, uiDesignSystem (or ui-design-system), uiMockups (or ui-mockups), uiComponents (or ui-components), uiFlows (or ui-flows), decisions, recap`);
305
322
  }
306
323
 
307
- state.features[featureName].outputs[outputType].created = true;
324
+ state.features[featureName].outputs[normalized].created = true;
308
325
  state.features[featureName].updatedAt = new Date().toISOString();
309
326
 
310
327
  // If marking tasks output, try to sync task count from state tasks array
311
- if (outputType === 'tasks') {
328
+ if (normalized === 'tasks') {
312
329
  syncTasksCount(state.features[featureName]);
313
330
  }
314
331
 
@@ -13,6 +13,7 @@
13
13
  import fs from 'fs/promises';
14
14
  import path from 'path';
15
15
  import { fileURLToPath } from 'url';
16
+ import { resolveAgentsConfigPath } from './stack-resolver.js';
16
17
 
17
18
  const __filename = fileURLToPath(import.meta.url);
18
19
  const __dirname = path.dirname(__filename);
@@ -23,7 +24,7 @@ const __dirname = path.dirname(__filename);
23
24
  * @returns {Promise<Object>} Parsed agents configuration
24
25
  */
25
26
  async function loadAgentsConfig(projectPath) {
26
- const agentsPath = path.join(projectPath, 'content/.morph/config/agents.json');
27
+ const agentsPath = resolveAgentsConfigPath(projectPath);
27
28
  const content = await fs.readFile(agentsPath, 'utf8');
28
29
  return JSON.parse(content);
29
30
  }
@@ -6,17 +6,27 @@
6
6
  import { readFileSync, readdirSync, existsSync } from 'fs';
7
7
  import { join, dirname, basename } from 'path';
8
8
  import { fileURLToPath } from 'url';
9
+ import { resolveStandardsDir } from './stack-resolver.js';
9
10
 
10
11
  const __filename = fileURLToPath(import.meta.url);
11
12
  const __dirname = dirname(__filename);
13
+ const frameworkRoot = join(__dirname, '..', '..');
12
14
 
13
- // Directories to search
15
+ // Directories to search (stack standards resolved dynamically)
14
16
  const SEARCH_PATHS = [
15
17
  'framework/standards',
16
- 'content/.morph/standards',
17
18
  '.wiki'
18
19
  ];
19
20
 
21
+ function getSearchPaths(basePath) {
22
+ const paths = [...SEARCH_PATHS];
23
+ // Insert resolved stack standards path
24
+ const stackStandards = resolveStandardsDir(basePath || frameworkRoot);
25
+ const relativePath = stackStandards.replace(basePath || frameworkRoot, '').replace(/^[\\/]/, '');
26
+ paths.splice(1, 0, relativePath);
27
+ return paths;
28
+ }
29
+
20
30
  /**
21
31
  * Get all markdown files from search paths
22
32
  * @param {string} basePath - Base path of the project
@@ -25,7 +35,7 @@ const SEARCH_PATHS = [
25
35
  function getMarkdownFiles(basePath) {
26
36
  const files = [];
27
37
 
28
- for (const searchPath of SEARCH_PATHS) {
38
+ for (const searchPath of getSearchPaths(basePath)) {
29
39
  const fullPath = join(basePath, searchPath);
30
40
 
31
41
  if (!existsSync(fullPath)) {
@@ -12,6 +12,7 @@ import { join } from 'path';
12
12
  import chalk from 'chalk';
13
13
  import { loadState } from './state-manager.js';
14
14
  import { loadConstraints } from './decision-constraint-loader.js';
15
+ import { resolveAgentsConfigPath } from './stack-resolver.js';
15
16
 
16
17
  /**
17
18
  * Load agent → validators map from agents.json (data-driven)
@@ -20,7 +21,7 @@ import { loadConstraints } from './decision-constraint-loader.js';
20
21
  */
21
22
  function loadAgentValidatorMap(projectPath) {
22
23
  try {
23
- const agentsPath = join(projectPath, 'content/.morph/config/agents.json');
24
+ const agentsPath = resolveAgentsConfigPath(projectPath);
24
25
  const agentsConfig = JSON.parse(readFileSync(agentsPath, 'utf8'));
25
26
 
26
27
  const map = {};
@@ -1,15 +1,17 @@
1
1
  import fs from 'fs-extra';
2
2
  import { join, dirname, resolve } from 'path';
3
3
  import { fileURLToPath } from 'url';
4
+ import { resolveStackPath } from '../lib/stack-resolver.js';
4
5
 
5
6
  const __dirname = dirname(fileURLToPath(import.meta.url));
7
+ const frameworkRoot = join(__dirname, '..', '..');
6
8
 
7
9
  function isSamePath(a, b) {
8
10
  return resolve(a) === resolve(b);
9
11
  }
10
12
 
11
13
  export function getContentDir() {
12
- return join(__dirname, '..', '..', 'content');
14
+ return resolveStackPath(frameworkRoot);
13
15
  }
14
16
 
15
17
  export async function copyDirectory(src, dest, options = {}) {