@polymorphism-tech/morph-spec 3.0.1 → 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 (273) hide show
  1. package/CLAUDE.md +52 -88
  2. package/LICENSE +72 -72
  3. package/README.md +198 -76
  4. package/bin/detect-agents.js +3 -1
  5. package/bin/morph-spec.js +10 -0
  6. package/bin/render-template.js +5 -4
  7. package/bin/semantic-detect-agents.js +2 -1
  8. package/bin/{task-manager.js → task-manager.cjs} +12 -1
  9. package/bin/validate-agents-skills.js +10 -4
  10. package/bin/validate-agents.js +4 -3
  11. package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +977 -977
  12. package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1048 -1048
  13. package/docs/api/scripts/collapse.js +38 -38
  14. package/docs/api/scripts/commonNav.js +28 -28
  15. package/docs/api/scripts/linenumber.js +25 -25
  16. package/docs/api/scripts/nav.js +12 -12
  17. package/docs/api/scripts/polyfill.js +3 -3
  18. package/docs/api/scripts/prettify/Apache-License-2.0.txt +202 -202
  19. package/docs/api/scripts/prettify/lang-css.js +2 -2
  20. package/docs/api/scripts/prettify/prettify.js +28 -28
  21. package/docs/api/scripts/search.js +98 -98
  22. package/docs/api/styles/jsdoc.css +776 -776
  23. package/docs/api/styles/prettify.css +80 -80
  24. package/docs/examples.md +328 -328
  25. package/docs/getting-started.md +3 -3
  26. package/docs/templates.md +418 -418
  27. package/package.json +3 -3
  28. package/scripts/postinstall.js +132 -132
  29. package/scripts/reorganize-skills.cjs +1 -1
  30. package/scripts/validate-agents-structure.cjs +1 -1
  31. package/scripts/validate-skills.cjs +2 -2
  32. package/src/commands/analyze-blazor-concurrency.js +193 -193
  33. package/src/commands/create-story.js +5 -2
  34. package/src/commands/deploy.js +780 -780
  35. package/src/commands/detect-agents.js +4 -2
  36. package/src/commands/generate.js +149 -149
  37. package/src/commands/lint-fluent.js +352 -352
  38. package/src/commands/rollback-phase.js +185 -185
  39. package/src/commands/session-summary.js +291 -291
  40. package/src/commands/shard-spec.js +224 -224
  41. package/src/commands/sprint-status.js +250 -250
  42. package/src/commands/task.js +1 -1
  43. package/src/commands/troubleshoot.js +222 -222
  44. package/src/commands/validate-blazor-state.js +210 -210
  45. package/src/commands/validate-blazor.js +156 -156
  46. package/src/commands/validate-css.js +84 -84
  47. package/src/commands/validate-phase.js +221 -221
  48. package/src/lib/blazor-concurrency-analyzer.js +288 -288
  49. package/src/lib/blazor-state-validator.js +291 -291
  50. package/src/lib/blazor-validator.js +374 -374
  51. package/src/lib/context-generator.js +7 -4
  52. package/src/lib/css-validator.js +352 -352
  53. package/src/lib/design-system-generator.js +298 -298
  54. package/src/lib/hook-executor.js +2 -1
  55. package/src/lib/learning-system.js +520 -520
  56. package/src/lib/mockup-generator.js +366 -366
  57. package/src/lib/stack-resolver.js +148 -0
  58. package/src/lib/standards-context-injector.js +4 -3
  59. package/src/lib/team-orchestrator.js +2 -1
  60. package/src/lib/troubleshoot-grep.js +204 -194
  61. package/src/lib/troubleshoot-index.js +144 -144
  62. package/src/lib/ui-detector.js +350 -350
  63. package/src/lib/validation-runner.js +2 -1
  64. package/src/lib/validators/architecture-validator.js +387 -387
  65. package/src/lib/validators/package-validator.js +360 -360
  66. package/src/lib/validators/ui-contrast-validator.js +422 -422
  67. package/src/utils/file-copier.js +3 -1
  68. package/src/utils/logger.js +32 -32
  69. package/src/utils/version-checker.js +175 -175
  70. package/{content → stacks/blazor-azure}/.azure/README.md +2 -2
  71. package/{content → stacks/blazor-azure}/.azure/pipelines/pipeline-variables.yml +1 -1
  72. package/{content → stacks/blazor-azure}/.azure/pipelines/prod-pipeline.yml +1 -1
  73. package/{content → stacks/blazor-azure}/.azure/pipelines/staging-pipeline.yml +1 -1
  74. package/{content → stacks/blazor-azure}/.claude/commands/morph-preflight.md +227 -227
  75. package/{content → stacks/blazor-azure}/.claude/commands/morph-troubleshoot.md +122 -122
  76. package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-setup.md +1 -1
  77. package/{content → stacks/blazor-azure}/.morph/docs/workflows/enforcement-pipeline.md +3 -3
  78. package/{content → stacks/blazor-azure}/.morph/hooks/README.md +12 -12
  79. package/{content → stacks/blazor-azure}/.morph/standards/agent-teams-workflow.md +2 -2
  80. package/{content → stacks/blazor-azure}/.morph/standards/migration-guide.md +2 -2
  81. package/{content → stacks/blazor-azure}/.morph/templates/infra/deploy-checklist.md +426 -426
  82. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/backend/dotnet-supabase.md +244 -0
  83. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/frontend/nextjs-supabase.md +335 -0
  84. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/infrastructure/easypanel-deployer.md +189 -0
  85. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/integrations/supabase-expert.md +170 -0
  86. package/stacks/nextjs-supabase/.morph/config/agents.json +345 -0
  87. package/stacks/nextjs-supabase/.morph/config/config.template.json +92 -0
  88. package/stacks/nextjs-supabase/.morph/docs/easypanel-setup.md +169 -0
  89. package/stacks/nextjs-supabase/.morph/docs/supabase-mcp-setup.md +247 -0
  90. package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/README.md +697 -0
  91. package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/spec.md +85 -0
  92. package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/tasks.md +86 -0
  93. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/README.md +498 -0
  94. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/decisions.md +121 -0
  95. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/spec.md +138 -0
  96. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/tasks.md +162 -0
  97. package/stacks/nextjs-supabase/.morph/project.md +168 -0
  98. package/stacks/nextjs-supabase/.morph/standards/easypanel-deploy.md +191 -0
  99. package/stacks/nextjs-supabase/.morph/standards/nextjs-patterns.md +193 -0
  100. package/stacks/nextjs-supabase/.morph/standards/supabase-auth.md +171 -0
  101. package/stacks/nextjs-supabase/.morph/standards/supabase-pgvector.md +164 -0
  102. package/stacks/nextjs-supabase/.morph/standards/supabase-rls.md +179 -0
  103. package/stacks/nextjs-supabase/.morph/standards/supabase-storage.md +148 -0
  104. package/stacks/nextjs-supabase/.morph/templates/contracts.cs +173 -0
  105. package/stacks/nextjs-supabase/.morph/templates/contracts.ts +168 -0
  106. package/stacks/nextjs-supabase/.morph/templates/decisions.md +115 -0
  107. package/stacks/nextjs-supabase/.morph/templates/dockerfile-api.dockerfile +38 -0
  108. package/stacks/nextjs-supabase/.morph/templates/dockerfile-web.dockerfile +48 -0
  109. package/stacks/nextjs-supabase/.morph/templates/proposal.md +145 -0
  110. package/stacks/nextjs-supabase/.morph/templates/recap.md +134 -0
  111. package/stacks/nextjs-supabase/.morph/templates/rls-policy.sql +57 -0
  112. package/stacks/nextjs-supabase/.morph/templates/spec.md +231 -0
  113. package/stacks/nextjs-supabase/.morph/templates/supabase-migration.sql +100 -0
  114. package/stacks/nextjs-supabase/.morph/templates/tasks.md +257 -0
  115. package/stacks/nextjs-supabase/CLAUDE.md +149 -0
  116. package/stacks/nextjs-supabase/README.md +112 -0
  117. /package/{content → stacks/blazor-azure}/.azure/docs/azure-devops-setup.md +0 -0
  118. /package/{content → stacks/blazor-azure}/.azure/docs/branch-strategy.md +0 -0
  119. /package/{content → stacks/blazor-azure}/.azure/docs/local-development.md +0 -0
  120. /package/{content → stacks/blazor-azure}/.azure/pipelines/templates/build-dotnet.yml +0 -0
  121. /package/{content → stacks/blazor-azure}/.azure/pipelines/templates/deploy-app-service.yml +0 -0
  122. /package/{content → stacks/blazor-azure}/.azure/pipelines/templates/deploy-container-app.yml +0 -0
  123. /package/{content → stacks/blazor-azure}/.azure/pipelines/templates/infra-deploy.yml +0 -0
  124. /package/{content → stacks/blazor-azure}/.claude/commands/morph-apply.md +0 -0
  125. /package/{content → stacks/blazor-azure}/.claude/commands/morph-archive.md +0 -0
  126. /package/{content → stacks/blazor-azure}/.claude/commands/morph-deploy.md +0 -0
  127. /package/{content → stacks/blazor-azure}/.claude/commands/morph-infra.md +0 -0
  128. /package/{content → stacks/blazor-azure}/.claude/commands/morph-proposal.md +0 -0
  129. /package/{content → stacks/blazor-azure}/.claude/commands/morph-status.md +0 -0
  130. /package/{content → stacks/blazor-azure}/.claude/settings.local.json +0 -0
  131. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/README.md +0 -0
  132. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/code-review.md +0 -0
  133. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/morph-checklist.md +0 -0
  134. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/simulation-checklist.md +0 -0
  135. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/README.md +0 -0
  136. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/morph-replicate.md +0 -0
  137. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-clarify.md +0 -0
  138. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-design.md +0 -0
  139. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-tasks.md +0 -0
  140. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-uiux.md +0 -0
  141. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/README.md +0 -0
  142. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/ai-agents/ai-system-architect.md +0 -0
  143. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/architecture/po-pm-advisor.md +0 -0
  144. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/architecture/prompt-engineer.md +0 -0
  145. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/architecture/seo-growth-hacker.md +0 -0
  146. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/architecture/standards-architect.md +0 -0
  147. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/dotnet-senior.md +0 -0
  148. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/ef-modeler.md +0 -0
  149. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/hangfire-orchestrator.md +0 -0
  150. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/ms-agent-expert.md +0 -0
  151. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/frontend/blazor-builder.md +0 -0
  152. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/frontend/nextjs-expert.md +0 -0
  153. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/frontend/ui-ux-designer.md +0 -0
  154. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/azure-architect.md +0 -0
  155. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/azure-deploy-specialist.md +0 -0
  156. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/bicep-architect.md +0 -0
  157. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/container-specialist.md +0 -0
  158. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/devops-engineer.md +0 -0
  159. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/asaas-financial.md +0 -0
  160. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/azure-identity.md +0 -0
  161. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/clerk-auth.md +0 -0
  162. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/resend-email.md +0 -0
  163. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/quality/code-analyzer.md +0 -0
  164. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/quality/testing-specialist.md +0 -0
  165. /package/{content → stacks/blazor-azure}/.claude/skills/level-3-technologies/README.md +0 -0
  166. /package/{content → stacks/blazor-azure}/.claude/skills/level-4-patterns/README.md +0 -0
  167. /package/{content → stacks/blazor-azure}/.morph/.morphversion +0 -0
  168. /package/{content → stacks/blazor-azure}/.morph/archive/.gitkeep +0 -0
  169. /package/{content → stacks/blazor-azure}/.morph/config/agents.json +0 -0
  170. /package/{content → stacks/blazor-azure}/.morph/config/config.template.json +0 -0
  171. /package/{content → stacks/blazor-azure}/.morph/docs/STORY-DRIVEN-DEVELOPMENT.md +0 -0
  172. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/design-impl.md +0 -0
  173. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/fast-track.md +0 -0
  174. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/full-morph.md +0 -0
  175. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/standard.md +0 -0
  176. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/ui-refresh.md +0 -0
  177. /package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/README.md +0 -0
  178. /package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/contracts.ts +0 -0
  179. /package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/spec.md +0 -0
  180. /package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/tasks.md +0 -0
  181. /package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/README.md +0 -0
  182. /package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/contracts.cs +0 -0
  183. /package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/decisions.md +0 -0
  184. /package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/spec.md +0 -0
  185. /package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/tasks.md +0 -0
  186. /package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/README.md +0 -0
  187. /package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/contracts.cs +0 -0
  188. /package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/spec.md +0 -0
  189. /package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/tasks.md +0 -0
  190. /package/{content → stacks/blazor-azure}/.morph/examples/scheduled-reports/decisions.md +0 -0
  191. /package/{content → stacks/blazor-azure}/.morph/examples/scheduled-reports/proposal.md +0 -0
  192. /package/{content → stacks/blazor-azure}/.morph/examples/scheduled-reports/spec.md +0 -0
  193. /package/{content → stacks/blazor-azure}/.morph/examples/state-v3.json +0 -0
  194. /package/{content → stacks/blazor-azure}/.morph/features/.gitkeep +0 -0
  195. /package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-agents.sh +0 -0
  196. /package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-all.sh +0 -0
  197. /package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-specs.sh +0 -0
  198. /package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-tests.sh +0 -0
  199. /package/{content → stacks/blazor-azure}/.morph/hooks/task-completed.js +0 -0
  200. /package/{content → stacks/blazor-azure}/.morph/hooks/teammate-idle.js +0 -0
  201. /package/{content → stacks/blazor-azure}/.morph/project.md +0 -0
  202. /package/{content → stacks/blazor-azure}/.morph/schemas/agent.schema.json +0 -0
  203. /package/{content → stacks/blazor-azure}/.morph/schemas/tasks.schema.json +0 -0
  204. /package/{content → stacks/blazor-azure}/.morph/specs/.gitkeep +0 -0
  205. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-blazor-ui.md +0 -0
  206. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-production.md +0 -0
  207. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-setup.md +0 -0
  208. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-workflows.md +0 -0
  209. /package/{content → stacks/blazor-azure}/.morph/standards/architecture.md +0 -0
  210. /package/{content → stacks/blazor-azure}/.morph/standards/azure.md +0 -0
  211. /package/{content → stacks/blazor-azure}/.morph/standards/coding.md +0 -0
  212. /package/{content → stacks/blazor-azure}/.morph/standards/dotnet10-migration.md +0 -0
  213. /package/{content → stacks/blazor-azure}/.morph/standards/fluent-ui-setup.md +0 -0
  214. /package/{content → stacks/blazor-azure}/.morph/standards/passkeys-auth.md +0 -0
  215. /package/{content → stacks/blazor-azure}/.morph/standards/vector-search-rag.md +0 -0
  216. /package/{content → stacks/blazor-azure}/.morph/state.json +0 -0
  217. /package/{content → stacks/blazor-azure}/.morph/templates/CONTEXT-FEATURE.md +0 -0
  218. /package/{content → stacks/blazor-azure}/.morph/templates/CONTEXT.md +0 -0
  219. /package/{content → stacks/blazor-azure}/.morph/templates/FluentDesignTheme.cs +0 -0
  220. /package/{content → stacks/blazor-azure}/.morph/templates/MudTheme.cs +0 -0
  221. /package/{content → stacks/blazor-azure}/.morph/templates/agent.cs +0 -0
  222. /package/{content → stacks/blazor-azure}/.morph/templates/clarify-questions.md +0 -0
  223. /package/{content → stacks/blazor-azure}/.morph/templates/component.razor +0 -0
  224. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/Commands.cs +0 -0
  225. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/Entities.cs +0 -0
  226. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/Queries.cs +0 -0
  227. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/README.md +0 -0
  228. /package/{content → stacks/blazor-azure}/.morph/templates/contracts.cs +0 -0
  229. /package/{content → stacks/blazor-azure}/.morph/templates/decisions.md +0 -0
  230. /package/{content → stacks/blazor-azure}/.morph/templates/design-system.css +0 -0
  231. /package/{content → stacks/blazor-azure}/.morph/templates/infra/.dockerignore.example +0 -0
  232. /package/{content → stacks/blazor-azure}/.morph/templates/infra/Dockerfile.example +0 -0
  233. /package/{content → stacks/blazor-azure}/.morph/templates/infra/README.md +0 -0
  234. /package/{content → stacks/blazor-azure}/.morph/templates/infra/app-insights.bicep +0 -0
  235. /package/{content → stacks/blazor-azure}/.morph/templates/infra/app-service.bicep +0 -0
  236. /package/{content → stacks/blazor-azure}/.morph/templates/infra/azure-pipelines-deploy.yml +0 -0
  237. /package/{content → stacks/blazor-azure}/.morph/templates/infra/container-app-env.bicep +0 -0
  238. /package/{content → stacks/blazor-azure}/.morph/templates/infra/container-app.bicep +0 -0
  239. /package/{content → stacks/blazor-azure}/.morph/templates/infra/deploy.ps1 +0 -0
  240. /package/{content → stacks/blazor-azure}/.morph/templates/infra/deploy.sh +0 -0
  241. /package/{content → stacks/blazor-azure}/.morph/templates/infra/key-vault.bicep +0 -0
  242. /package/{content → stacks/blazor-azure}/.morph/templates/infra/main.bicep +0 -0
  243. /package/{content → stacks/blazor-azure}/.morph/templates/infra/parameters.dev.json +0 -0
  244. /package/{content → stacks/blazor-azure}/.morph/templates/infra/parameters.prod.json +0 -0
  245. /package/{content → stacks/blazor-azure}/.morph/templates/infra/parameters.staging.json +0 -0
  246. /package/{content → stacks/blazor-azure}/.morph/templates/infra/sql-database.bicep +0 -0
  247. /package/{content → stacks/blazor-azure}/.morph/templates/infra/storage.bicep +0 -0
  248. /package/{content → stacks/blazor-azure}/.morph/templates/integrations/asaas-client.cs +0 -0
  249. /package/{content → stacks/blazor-azure}/.morph/templates/integrations/asaas-webhook.cs +0 -0
  250. /package/{content → stacks/blazor-azure}/.morph/templates/integrations/azure-identity-config.cs +0 -0
  251. /package/{content → stacks/blazor-azure}/.morph/templates/integrations/clerk-config.cs +0 -0
  252. /package/{content → stacks/blazor-azure}/.morph/templates/job.cs +0 -0
  253. /package/{content → stacks/blazor-azure}/.morph/templates/migration.cs +0 -0
  254. /package/{content → stacks/blazor-azure}/.morph/templates/proposal.md +0 -0
  255. /package/{content → stacks/blazor-azure}/.morph/templates/recap.md +0 -0
  256. /package/{content → stacks/blazor-azure}/.morph/templates/repository.cs +0 -0
  257. /package/{content → stacks/blazor-azure}/.morph/templates/saas/subscription.cs +0 -0
  258. /package/{content → stacks/blazor-azure}/.morph/templates/saas/tenant.cs +0 -0
  259. /package/{content → stacks/blazor-azure}/.morph/templates/service.cs +0 -0
  260. /package/{content → stacks/blazor-azure}/.morph/templates/simulation.md +0 -0
  261. /package/{content → stacks/blazor-azure}/.morph/templates/spec.md +0 -0
  262. /package/{content → stacks/blazor-azure}/.morph/templates/sprint-status.yaml +0 -0
  263. /package/{content → stacks/blazor-azure}/.morph/templates/state.template.json +0 -0
  264. /package/{content → stacks/blazor-azure}/.morph/templates/story.md +0 -0
  265. /package/{content → stacks/blazor-azure}/.morph/templates/tasks.md +0 -0
  266. /package/{content → stacks/blazor-azure}/.morph/templates/test.cs +0 -0
  267. /package/{content → stacks/blazor-azure}/.morph/templates/ui-components.md +0 -0
  268. /package/{content → stacks/blazor-azure}/.morph/templates/ui-design-system.md +0 -0
  269. /package/{content → stacks/blazor-azure}/.morph/templates/ui-flows.md +0 -0
  270. /package/{content → stacks/blazor-azure}/.morph/templates/ui-mockups.md +0 -0
  271. /package/{content → stacks/blazor-azure}/.morph/test-infra/example.bicep +0 -0
  272. /package/{content → stacks/blazor-azure}/CLAUDE.md +0 -0
  273. /package/{content → stacks/blazor-azure}/README.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
 
@@ -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
  }
@@ -1,194 +1,204 @@
1
- /**
2
- * Troubleshoot Grep Fallback
3
- * Searches markdown files for matching content when index doesn't find results
4
- */
5
-
6
- import { readFileSync, readdirSync, existsSync } from 'fs';
7
- import { join, dirname, basename } from 'path';
8
- import { fileURLToPath } from 'url';
9
-
10
- const __filename = fileURLToPath(import.meta.url);
11
- const __dirname = dirname(__filename);
12
-
13
- // Directories to search
14
- const SEARCH_PATHS = [
15
- 'framework/standards',
16
- 'content/.morph/standards',
17
- '.wiki'
18
- ];
19
-
20
- /**
21
- * Get all markdown files from search paths
22
- * @param {string} basePath - Base path of the project
23
- * @returns {string[]} Array of file paths
24
- */
25
- function getMarkdownFiles(basePath) {
26
- const files = [];
27
-
28
- for (const searchPath of SEARCH_PATHS) {
29
- const fullPath = join(basePath, searchPath);
30
-
31
- if (!existsSync(fullPath)) {
32
- continue;
33
- }
34
-
35
- try {
36
- const entries = readdirSync(fullPath, { withFileTypes: true });
37
-
38
- for (const entry of entries) {
39
- if (entry.isFile() && entry.name.endsWith('.md')) {
40
- files.push(join(fullPath, entry.name));
41
- }
42
- }
43
- } catch (error) {
44
- // Skip directories we can't read
45
- }
46
- }
47
-
48
- return files;
49
- }
50
-
51
- /**
52
- * Extract section containing the match
53
- * @param {string} content - File content
54
- * @param {number} matchIndex - Index of the match
55
- * @returns {Object} Section object with title and content
56
- */
57
- function extractSection(content, matchIndex) {
58
- const lines = content.split('\n');
59
- let charCount = 0;
60
- let matchLineIndex = 0;
61
-
62
- // Find the line containing the match
63
- for (let i = 0; i < lines.length; i++) {
64
- charCount += lines[i].length + 1; // +1 for newline
65
- if (charCount > matchIndex) {
66
- matchLineIndex = i;
67
- break;
68
- }
69
- }
70
-
71
- // Find the section header (## heading) above the match
72
- let sectionTitle = 'Unknown Section';
73
- let sectionStart = 0;
74
-
75
- for (let i = matchLineIndex; i >= 0; i--) {
76
- if (lines[i].startsWith('## ')) {
77
- sectionTitle = lines[i].replace('## ', '').trim();
78
- sectionStart = i;
79
- break;
80
- }
81
- }
82
-
83
- // Find the end of the section (next ## or end of file)
84
- let sectionEnd = lines.length;
85
- for (let i = sectionStart + 1; i < lines.length; i++) {
86
- if (lines[i].startsWith('## ')) {
87
- sectionEnd = i;
88
- break;
89
- }
90
- }
91
-
92
- // Extract section content (limit to ~20 lines around match)
93
- const contextStart = Math.max(sectionStart, matchLineIndex - 10);
94
- const contextEnd = Math.min(sectionEnd, matchLineIndex + 10);
95
- const sectionContent = lines.slice(contextStart, contextEnd).join('\n');
96
-
97
- return {
98
- title: sectionTitle,
99
- content: sectionContent,
100
- lineNumber: matchLineIndex + 1
101
- };
102
- }
103
-
104
- /**
105
- * Search a file for keywords
106
- * @param {string} filePath - Path to the file
107
- * @param {string[]} keywords - Keywords to search for
108
- * @returns {Object[]} Array of matches
109
- */
110
- function searchFile(filePath, keywords) {
111
- const matches = [];
112
-
113
- try {
114
- const content = readFileSync(filePath, 'utf-8');
115
- const contentLower = content.toLowerCase();
116
-
117
- for (const keyword of keywords) {
118
- const keywordLower = keyword.toLowerCase();
119
- let index = contentLower.indexOf(keywordLower);
120
-
121
- while (index !== -1) {
122
- const section = extractSection(content, index);
123
-
124
- // Check if we already have a match for this section
125
- const existingMatch = matches.find(m => m.section === section.title);
126
-
127
- if (existingMatch) {
128
- existingMatch.matchCount++;
129
- existingMatch.keywords.add(keyword);
130
- } else {
131
- matches.push({
132
- file: filePath,
133
- fileName: basename(filePath),
134
- section: section.title,
135
- content: section.content,
136
- lineNumber: section.lineNumber,
137
- matchCount: 1,
138
- keywords: new Set([keyword])
139
- });
140
- }
141
-
142
- index = contentLower.indexOf(keywordLower, index + 1);
143
- }
144
- }
145
- } catch (error) {
146
- // Skip files we can't read
147
- }
148
-
149
- return matches;
150
- }
151
-
152
- /**
153
- * Search all markdown files for keywords
154
- * @param {string[]} keywords - Keywords to search for
155
- * @param {Object} options - Search options
156
- * @returns {Object[]} Array of matches sorted by relevance
157
- */
158
- export function searchGrep(keywords, options = {}) {
159
- // Determine base path
160
- const basePath = options.basePath || join(__dirname, '../..');
161
-
162
- const files = getMarkdownFiles(basePath);
163
- let allMatches = [];
164
-
165
- for (const file of files) {
166
- const matches = searchFile(file, keywords);
167
- allMatches = allMatches.concat(matches);
168
- }
169
-
170
- // Convert keywords Set to Array and calculate score
171
- const results = allMatches.map(match => ({
172
- ...match,
173
- keywords: Array.from(match.keywords),
174
- score: match.matchCount * 5 + match.keywords.size * 3,
175
- source: 'grep'
176
- }));
177
-
178
- // Sort by score (higher is better) and deduplicate
179
- const seen = new Set();
180
- const uniqueResults = results
181
- .sort((a, b) => b.score - a.score)
182
- .filter(r => {
183
- const key = `${r.file}:${r.section}`;
184
- if (seen.has(key)) return false;
185
- seen.add(key);
186
- return true;
187
- });
188
-
189
- return uniqueResults.slice(0, 10); // Limit to top 10
190
- }
191
-
192
- export default {
193
- searchGrep
194
- };
1
+ /**
2
+ * Troubleshoot Grep Fallback
3
+ * Searches markdown files for matching content when index doesn't find results
4
+ */
5
+
6
+ import { readFileSync, readdirSync, existsSync } from 'fs';
7
+ import { join, dirname, basename } from 'path';
8
+ import { fileURLToPath } from 'url';
9
+ import { resolveStandardsDir } from './stack-resolver.js';
10
+
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = dirname(__filename);
13
+ const frameworkRoot = join(__dirname, '..', '..');
14
+
15
+ // Directories to search (stack standards resolved dynamically)
16
+ const SEARCH_PATHS = [
17
+ 'framework/standards',
18
+ '.wiki'
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
+
30
+ /**
31
+ * Get all markdown files from search paths
32
+ * @param {string} basePath - Base path of the project
33
+ * @returns {string[]} Array of file paths
34
+ */
35
+ function getMarkdownFiles(basePath) {
36
+ const files = [];
37
+
38
+ for (const searchPath of getSearchPaths(basePath)) {
39
+ const fullPath = join(basePath, searchPath);
40
+
41
+ if (!existsSync(fullPath)) {
42
+ continue;
43
+ }
44
+
45
+ try {
46
+ const entries = readdirSync(fullPath, { withFileTypes: true });
47
+
48
+ for (const entry of entries) {
49
+ if (entry.isFile() && entry.name.endsWith('.md')) {
50
+ files.push(join(fullPath, entry.name));
51
+ }
52
+ }
53
+ } catch (error) {
54
+ // Skip directories we can't read
55
+ }
56
+ }
57
+
58
+ return files;
59
+ }
60
+
61
+ /**
62
+ * Extract section containing the match
63
+ * @param {string} content - File content
64
+ * @param {number} matchIndex - Index of the match
65
+ * @returns {Object} Section object with title and content
66
+ */
67
+ function extractSection(content, matchIndex) {
68
+ const lines = content.split('\n');
69
+ let charCount = 0;
70
+ let matchLineIndex = 0;
71
+
72
+ // Find the line containing the match
73
+ for (let i = 0; i < lines.length; i++) {
74
+ charCount += lines[i].length + 1; // +1 for newline
75
+ if (charCount > matchIndex) {
76
+ matchLineIndex = i;
77
+ break;
78
+ }
79
+ }
80
+
81
+ // Find the section header (## heading) above the match
82
+ let sectionTitle = 'Unknown Section';
83
+ let sectionStart = 0;
84
+
85
+ for (let i = matchLineIndex; i >= 0; i--) {
86
+ if (lines[i].startsWith('## ')) {
87
+ sectionTitle = lines[i].replace('## ', '').trim();
88
+ sectionStart = i;
89
+ break;
90
+ }
91
+ }
92
+
93
+ // Find the end of the section (next ## or end of file)
94
+ let sectionEnd = lines.length;
95
+ for (let i = sectionStart + 1; i < lines.length; i++) {
96
+ if (lines[i].startsWith('## ')) {
97
+ sectionEnd = i;
98
+ break;
99
+ }
100
+ }
101
+
102
+ // Extract section content (limit to ~20 lines around match)
103
+ const contextStart = Math.max(sectionStart, matchLineIndex - 10);
104
+ const contextEnd = Math.min(sectionEnd, matchLineIndex + 10);
105
+ const sectionContent = lines.slice(contextStart, contextEnd).join('\n');
106
+
107
+ return {
108
+ title: sectionTitle,
109
+ content: sectionContent,
110
+ lineNumber: matchLineIndex + 1
111
+ };
112
+ }
113
+
114
+ /**
115
+ * Search a file for keywords
116
+ * @param {string} filePath - Path to the file
117
+ * @param {string[]} keywords - Keywords to search for
118
+ * @returns {Object[]} Array of matches
119
+ */
120
+ function searchFile(filePath, keywords) {
121
+ const matches = [];
122
+
123
+ try {
124
+ const content = readFileSync(filePath, 'utf-8');
125
+ const contentLower = content.toLowerCase();
126
+
127
+ for (const keyword of keywords) {
128
+ const keywordLower = keyword.toLowerCase();
129
+ let index = contentLower.indexOf(keywordLower);
130
+
131
+ while (index !== -1) {
132
+ const section = extractSection(content, index);
133
+
134
+ // Check if we already have a match for this section
135
+ const existingMatch = matches.find(m => m.section === section.title);
136
+
137
+ if (existingMatch) {
138
+ existingMatch.matchCount++;
139
+ existingMatch.keywords.add(keyword);
140
+ } else {
141
+ matches.push({
142
+ file: filePath,
143
+ fileName: basename(filePath),
144
+ section: section.title,
145
+ content: section.content,
146
+ lineNumber: section.lineNumber,
147
+ matchCount: 1,
148
+ keywords: new Set([keyword])
149
+ });
150
+ }
151
+
152
+ index = contentLower.indexOf(keywordLower, index + 1);
153
+ }
154
+ }
155
+ } catch (error) {
156
+ // Skip files we can't read
157
+ }
158
+
159
+ return matches;
160
+ }
161
+
162
+ /**
163
+ * Search all markdown files for keywords
164
+ * @param {string[]} keywords - Keywords to search for
165
+ * @param {Object} options - Search options
166
+ * @returns {Object[]} Array of matches sorted by relevance
167
+ */
168
+ export function searchGrep(keywords, options = {}) {
169
+ // Determine base path
170
+ const basePath = options.basePath || join(__dirname, '../..');
171
+
172
+ const files = getMarkdownFiles(basePath);
173
+ let allMatches = [];
174
+
175
+ for (const file of files) {
176
+ const matches = searchFile(file, keywords);
177
+ allMatches = allMatches.concat(matches);
178
+ }
179
+
180
+ // Convert keywords Set to Array and calculate score
181
+ const results = allMatches.map(match => ({
182
+ ...match,
183
+ keywords: Array.from(match.keywords),
184
+ score: match.matchCount * 5 + match.keywords.size * 3,
185
+ source: 'grep'
186
+ }));
187
+
188
+ // Sort by score (higher is better) and deduplicate
189
+ const seen = new Set();
190
+ const uniqueResults = results
191
+ .sort((a, b) => b.score - a.score)
192
+ .filter(r => {
193
+ const key = `${r.file}:${r.section}`;
194
+ if (seen.has(key)) return false;
195
+ seen.add(key);
196
+ return true;
197
+ });
198
+
199
+ return uniqueResults.slice(0, 10); // Limit to top 10
200
+ }
201
+
202
+ export default {
203
+ searchGrep
204
+ };