@polymorphism-tech/morph-spec 3.0.1 → 3.2.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 (316) hide show
  1. package/CLAUDE.md +561 -63
  2. package/LICENSE +72 -72
  3. package/README.md +275 -79
  4. package/bin/detect-agents.js +3 -1
  5. package/bin/morph-spec.js +60 -1
  6. package/bin/render-template.js +61 -14
  7. package/bin/semantic-detect-agents.js +2 -1
  8. package/bin/{task-manager.js → task-manager.cjs} +113 -8
  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/cli-auto-detection.md +219 -0
  25. package/docs/examples.md +328 -328
  26. package/docs/getting-started.md +3 -3
  27. package/docs/llm-interaction-config.md +735 -0
  28. package/docs/templates.md +418 -418
  29. package/docs/troubleshooting.md +269 -0
  30. package/package.json +7 -3
  31. package/scripts/postinstall.js +132 -132
  32. package/scripts/reorganize-skills.cjs +1 -1
  33. package/scripts/validate-agents-structure.cjs +1 -1
  34. package/scripts/validate-skills.cjs +2 -2
  35. package/src/commands/advance-phase.js +93 -2
  36. package/src/commands/analyze-blazor-concurrency.js +193 -193
  37. package/src/commands/approve.js +221 -0
  38. package/src/commands/capture-pattern.js +121 -0
  39. package/src/commands/create-story.js +5 -2
  40. package/src/commands/deploy.js +780 -780
  41. package/src/commands/detect-agents.js +4 -2
  42. package/src/commands/generate.js +276 -149
  43. package/src/commands/init.js +37 -0
  44. package/src/commands/lint-fluent.js +352 -352
  45. package/src/commands/migrate-state.js +158 -0
  46. package/src/commands/rollback-phase.js +185 -185
  47. package/src/commands/search-patterns.js +126 -0
  48. package/src/commands/session-summary.js +291 -291
  49. package/src/commands/shard-spec.js +224 -224
  50. package/src/commands/spawn-team.js +172 -0
  51. package/src/commands/sprint-status.js +250 -250
  52. package/src/commands/task.js +3 -3
  53. package/src/commands/troubleshoot.js +222 -222
  54. package/src/commands/update.js +36 -0
  55. package/src/commands/upgrade.js +346 -0
  56. package/src/commands/validate-blazor-state.js +210 -210
  57. package/src/commands/validate-blazor.js +156 -156
  58. package/src/commands/validate-css.js +84 -84
  59. package/src/commands/validate-phase.js +221 -221
  60. package/src/generator/.gitkeep +0 -0
  61. package/src/generator/config-generator.js +206 -0
  62. package/src/generator/templates/config.json.template +40 -0
  63. package/src/generator/templates/project.md.template +67 -0
  64. package/src/lib/blazor-concurrency-analyzer.js +288 -288
  65. package/src/lib/blazor-state-validator.js +291 -291
  66. package/src/lib/blazor-validator.js +374 -374
  67. package/src/lib/checkpoint-hooks.js +258 -0
  68. package/src/lib/context-generator.js +7 -4
  69. package/src/lib/css-validator.js +352 -352
  70. package/src/lib/design-system-generator.js +298 -298
  71. package/src/lib/hook-executor.js +2 -1
  72. package/src/lib/learning-system.js +520 -520
  73. package/src/lib/metadata-extractor.js +380 -0
  74. package/src/lib/mockup-generator.js +366 -366
  75. package/src/lib/phase-state-machine.js +214 -0
  76. package/src/lib/stack-resolver.js +148 -0
  77. package/src/lib/standards-context-injector.js +4 -3
  78. package/src/lib/state-manager.js +120 -0
  79. package/src/lib/team-orchestrator.js +2 -1
  80. package/src/lib/template-data-sources.js +325 -0
  81. package/src/lib/troubleshoot-grep.js +204 -194
  82. package/src/lib/troubleshoot-index.js +144 -144
  83. package/src/lib/ui-detector.js +350 -350
  84. package/src/lib/validation-runner.js +2 -1
  85. package/src/lib/validators/architecture-validator.js +387 -387
  86. package/src/lib/validators/content-validator.js +351 -0
  87. package/src/lib/validators/package-validator.js +360 -360
  88. package/src/lib/validators/ui-contrast-validator.js +422 -422
  89. package/src/llm/.gitkeep +0 -0
  90. package/src/llm/analyzer.js +215 -0
  91. package/src/llm/environment-detector.js +43 -0
  92. package/src/llm/few-shot-examples.js +216 -0
  93. package/src/llm/project-config-schema.json +188 -0
  94. package/src/llm/prompt-builder.js +96 -0
  95. package/src/llm/schema-validator.js +121 -0
  96. package/src/orchestrator.js +206 -0
  97. package/src/sanitizer/.gitkeep +0 -0
  98. package/src/sanitizer/context-sanitizer.js +221 -0
  99. package/src/sanitizer/patterns.js +163 -0
  100. package/src/scanner/.gitkeep +0 -0
  101. package/src/scanner/project-scanner.js +242 -0
  102. package/src/types/index.js +477 -0
  103. package/src/ui/.gitkeep +0 -0
  104. package/src/ui/diff-display.js +91 -0
  105. package/src/ui/interactive-wizard.js +96 -0
  106. package/src/ui/user-review.js +211 -0
  107. package/src/ui/wizard-questions.js +190 -0
  108. package/src/utils/file-copier.js +3 -1
  109. package/src/utils/logger.js +32 -32
  110. package/src/utils/version-checker.js +175 -175
  111. package/src/writer/.gitkeep +0 -0
  112. package/src/writer/file-writer.js +86 -0
  113. package/{content → stacks/blazor-azure}/.azure/README.md +2 -2
  114. package/{content → stacks/blazor-azure}/.azure/pipelines/pipeline-variables.yml +1 -1
  115. package/{content → stacks/blazor-azure}/.azure/pipelines/prod-pipeline.yml +1 -1
  116. package/{content → stacks/blazor-azure}/.azure/pipelines/staging-pipeline.yml +1 -1
  117. package/{content → stacks/blazor-azure}/.claude/commands/morph-preflight.md +227 -227
  118. package/{content → stacks/blazor-azure}/.claude/commands/morph-troubleshoot.md +122 -122
  119. package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-setup.md +1 -1
  120. package/{content → stacks/blazor-azure}/.morph/docs/workflows/enforcement-pipeline.md +3 -3
  121. package/{content → stacks/blazor-azure}/.morph/hooks/README.md +12 -12
  122. package/{content → stacks/blazor-azure}/.morph/standards/agent-teams-workflow.md +2 -2
  123. package/{content → stacks/blazor-azure}/.morph/standards/migration-guide.md +2 -2
  124. package/{content → stacks/blazor-azure}/.morph/templates/infra/deploy-checklist.md +426 -426
  125. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/backend/dotnet-supabase.md +244 -0
  126. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/frontend/nextjs-supabase.md +335 -0
  127. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/infrastructure/easypanel-deployer.md +189 -0
  128. package/stacks/nextjs-supabase/.claude/skills/level-2-domains/integrations/supabase-expert.md +170 -0
  129. package/stacks/nextjs-supabase/.morph/config/agents.json +345 -0
  130. package/stacks/nextjs-supabase/.morph/config/config.template.json +92 -0
  131. package/stacks/nextjs-supabase/.morph/docs/easypanel-setup.md +169 -0
  132. package/stacks/nextjs-supabase/.morph/docs/supabase-mcp-setup.md +247 -0
  133. package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/README.md +697 -0
  134. package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/spec.md +85 -0
  135. package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/tasks.md +86 -0
  136. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/README.md +498 -0
  137. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/decisions.md +121 -0
  138. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/spec.md +138 -0
  139. package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/tasks.md +162 -0
  140. package/stacks/nextjs-supabase/.morph/project.md +168 -0
  141. package/stacks/nextjs-supabase/.morph/standards/easypanel-deploy.md +191 -0
  142. package/stacks/nextjs-supabase/.morph/standards/nextjs-patterns.md +193 -0
  143. package/stacks/nextjs-supabase/.morph/standards/supabase-auth.md +171 -0
  144. package/stacks/nextjs-supabase/.morph/standards/supabase-pgvector.md +164 -0
  145. package/stacks/nextjs-supabase/.morph/standards/supabase-rls.md +179 -0
  146. package/stacks/nextjs-supabase/.morph/standards/supabase-storage.md +148 -0
  147. package/stacks/nextjs-supabase/.morph/templates/contracts.cs +173 -0
  148. package/stacks/nextjs-supabase/.morph/templates/contracts.ts +168 -0
  149. package/stacks/nextjs-supabase/.morph/templates/decisions.md +115 -0
  150. package/stacks/nextjs-supabase/.morph/templates/dockerfile-api.dockerfile +38 -0
  151. package/stacks/nextjs-supabase/.morph/templates/dockerfile-web.dockerfile +48 -0
  152. package/stacks/nextjs-supabase/.morph/templates/proposal.md +145 -0
  153. package/stacks/nextjs-supabase/.morph/templates/recap.md +134 -0
  154. package/stacks/nextjs-supabase/.morph/templates/rls-policy.sql +57 -0
  155. package/stacks/nextjs-supabase/.morph/templates/spec.md +231 -0
  156. package/stacks/nextjs-supabase/.morph/templates/supabase-migration.sql +100 -0
  157. package/stacks/nextjs-supabase/.morph/templates/tasks.md +257 -0
  158. package/stacks/nextjs-supabase/CLAUDE.md +149 -0
  159. package/stacks/nextjs-supabase/README.md +112 -0
  160. /package/{content → stacks/blazor-azure}/.azure/docs/azure-devops-setup.md +0 -0
  161. /package/{content → stacks/blazor-azure}/.azure/docs/branch-strategy.md +0 -0
  162. /package/{content → stacks/blazor-azure}/.azure/docs/local-development.md +0 -0
  163. /package/{content → stacks/blazor-azure}/.azure/pipelines/templates/build-dotnet.yml +0 -0
  164. /package/{content → stacks/blazor-azure}/.azure/pipelines/templates/deploy-app-service.yml +0 -0
  165. /package/{content → stacks/blazor-azure}/.azure/pipelines/templates/deploy-container-app.yml +0 -0
  166. /package/{content → stacks/blazor-azure}/.azure/pipelines/templates/infra-deploy.yml +0 -0
  167. /package/{content → stacks/blazor-azure}/.claude/commands/morph-apply.md +0 -0
  168. /package/{content → stacks/blazor-azure}/.claude/commands/morph-archive.md +0 -0
  169. /package/{content → stacks/blazor-azure}/.claude/commands/morph-deploy.md +0 -0
  170. /package/{content → stacks/blazor-azure}/.claude/commands/morph-infra.md +0 -0
  171. /package/{content → stacks/blazor-azure}/.claude/commands/morph-proposal.md +0 -0
  172. /package/{content → stacks/blazor-azure}/.claude/commands/morph-status.md +0 -0
  173. /package/{content → stacks/blazor-azure}/.claude/settings.local.json +0 -0
  174. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/README.md +0 -0
  175. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/code-review.md +0 -0
  176. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/morph-checklist.md +0 -0
  177. /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/simulation-checklist.md +0 -0
  178. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/README.md +0 -0
  179. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/morph-replicate.md +0 -0
  180. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-clarify.md +0 -0
  181. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-design.md +0 -0
  182. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-tasks.md +0 -0
  183. /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-uiux.md +0 -0
  184. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/README.md +0 -0
  185. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/ai-agents/ai-system-architect.md +0 -0
  186. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/architecture/po-pm-advisor.md +0 -0
  187. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/architecture/prompt-engineer.md +0 -0
  188. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/architecture/seo-growth-hacker.md +0 -0
  189. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/architecture/standards-architect.md +0 -0
  190. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/dotnet-senior.md +0 -0
  191. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/ef-modeler.md +0 -0
  192. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/hangfire-orchestrator.md +0 -0
  193. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/ms-agent-expert.md +0 -0
  194. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/frontend/blazor-builder.md +0 -0
  195. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/frontend/nextjs-expert.md +0 -0
  196. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/frontend/ui-ux-designer.md +0 -0
  197. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/azure-architect.md +0 -0
  198. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/azure-deploy-specialist.md +0 -0
  199. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/bicep-architect.md +0 -0
  200. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/container-specialist.md +0 -0
  201. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/devops-engineer.md +0 -0
  202. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/asaas-financial.md +0 -0
  203. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/azure-identity.md +0 -0
  204. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/clerk-auth.md +0 -0
  205. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/resend-email.md +0 -0
  206. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/quality/code-analyzer.md +0 -0
  207. /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/quality/testing-specialist.md +0 -0
  208. /package/{content → stacks/blazor-azure}/.claude/skills/level-3-technologies/README.md +0 -0
  209. /package/{content → stacks/blazor-azure}/.claude/skills/level-4-patterns/README.md +0 -0
  210. /package/{content → stacks/blazor-azure}/.morph/.morphversion +0 -0
  211. /package/{content → stacks/blazor-azure}/.morph/archive/.gitkeep +0 -0
  212. /package/{content → stacks/blazor-azure}/.morph/config/agents.json +0 -0
  213. /package/{content → stacks/blazor-azure}/.morph/config/config.template.json +0 -0
  214. /package/{content → stacks/blazor-azure}/.morph/docs/STORY-DRIVEN-DEVELOPMENT.md +0 -0
  215. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/design-impl.md +0 -0
  216. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/fast-track.md +0 -0
  217. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/full-morph.md +0 -0
  218. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/standard.md +0 -0
  219. /package/{content → stacks/blazor-azure}/.morph/docs/workflows/ui-refresh.md +0 -0
  220. /package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/README.md +0 -0
  221. /package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/contracts.ts +0 -0
  222. /package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/spec.md +0 -0
  223. /package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/tasks.md +0 -0
  224. /package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/README.md +0 -0
  225. /package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/contracts.cs +0 -0
  226. /package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/decisions.md +0 -0
  227. /package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/spec.md +0 -0
  228. /package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/tasks.md +0 -0
  229. /package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/README.md +0 -0
  230. /package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/contracts.cs +0 -0
  231. /package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/spec.md +0 -0
  232. /package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/tasks.md +0 -0
  233. /package/{content → stacks/blazor-azure}/.morph/examples/scheduled-reports/decisions.md +0 -0
  234. /package/{content → stacks/blazor-azure}/.morph/examples/scheduled-reports/proposal.md +0 -0
  235. /package/{content → stacks/blazor-azure}/.morph/examples/scheduled-reports/spec.md +0 -0
  236. /package/{content → stacks/blazor-azure}/.morph/examples/state-v3.json +0 -0
  237. /package/{content → stacks/blazor-azure}/.morph/features/.gitkeep +0 -0
  238. /package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-agents.sh +0 -0
  239. /package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-all.sh +0 -0
  240. /package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-specs.sh +0 -0
  241. /package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-tests.sh +0 -0
  242. /package/{content → stacks/blazor-azure}/.morph/hooks/task-completed.js +0 -0
  243. /package/{content → stacks/blazor-azure}/.morph/hooks/teammate-idle.js +0 -0
  244. /package/{content → stacks/blazor-azure}/.morph/project.md +0 -0
  245. /package/{content → stacks/blazor-azure}/.morph/schemas/agent.schema.json +0 -0
  246. /package/{content → stacks/blazor-azure}/.morph/schemas/tasks.schema.json +0 -0
  247. /package/{content → stacks/blazor-azure}/.morph/specs/.gitkeep +0 -0
  248. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-blazor-ui.md +0 -0
  249. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-production.md +0 -0
  250. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-setup.md +0 -0
  251. /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-workflows.md +0 -0
  252. /package/{content → stacks/blazor-azure}/.morph/standards/architecture.md +0 -0
  253. /package/{content → stacks/blazor-azure}/.morph/standards/azure.md +0 -0
  254. /package/{content → stacks/blazor-azure}/.morph/standards/coding.md +0 -0
  255. /package/{content → stacks/blazor-azure}/.morph/standards/dotnet10-migration.md +0 -0
  256. /package/{content → stacks/blazor-azure}/.morph/standards/fluent-ui-setup.md +0 -0
  257. /package/{content → stacks/blazor-azure}/.morph/standards/passkeys-auth.md +0 -0
  258. /package/{content → stacks/blazor-azure}/.morph/standards/vector-search-rag.md +0 -0
  259. /package/{content → stacks/blazor-azure}/.morph/state.json +0 -0
  260. /package/{content → stacks/blazor-azure}/.morph/templates/CONTEXT-FEATURE.md +0 -0
  261. /package/{content → stacks/blazor-azure}/.morph/templates/CONTEXT.md +0 -0
  262. /package/{content → stacks/blazor-azure}/.morph/templates/FluentDesignTheme.cs +0 -0
  263. /package/{content → stacks/blazor-azure}/.morph/templates/MudTheme.cs +0 -0
  264. /package/{content → stacks/blazor-azure}/.morph/templates/agent.cs +0 -0
  265. /package/{content → stacks/blazor-azure}/.morph/templates/clarify-questions.md +0 -0
  266. /package/{content → stacks/blazor-azure}/.morph/templates/component.razor +0 -0
  267. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/Commands.cs +0 -0
  268. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/Entities.cs +0 -0
  269. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/Queries.cs +0 -0
  270. /package/{content → stacks/blazor-azure}/.morph/templates/contracts/README.md +0 -0
  271. /package/{content → stacks/blazor-azure}/.morph/templates/contracts.cs +0 -0
  272. /package/{content → stacks/blazor-azure}/.morph/templates/decisions.md +0 -0
  273. /package/{content → stacks/blazor-azure}/.morph/templates/design-system.css +0 -0
  274. /package/{content → stacks/blazor-azure}/.morph/templates/infra/.dockerignore.example +0 -0
  275. /package/{content → stacks/blazor-azure}/.morph/templates/infra/Dockerfile.example +0 -0
  276. /package/{content → stacks/blazor-azure}/.morph/templates/infra/README.md +0 -0
  277. /package/{content → stacks/blazor-azure}/.morph/templates/infra/app-insights.bicep +0 -0
  278. /package/{content → stacks/blazor-azure}/.morph/templates/infra/app-service.bicep +0 -0
  279. /package/{content → stacks/blazor-azure}/.morph/templates/infra/azure-pipelines-deploy.yml +0 -0
  280. /package/{content → stacks/blazor-azure}/.morph/templates/infra/container-app-env.bicep +0 -0
  281. /package/{content → stacks/blazor-azure}/.morph/templates/infra/container-app.bicep +0 -0
  282. /package/{content → stacks/blazor-azure}/.morph/templates/infra/deploy.ps1 +0 -0
  283. /package/{content → stacks/blazor-azure}/.morph/templates/infra/deploy.sh +0 -0
  284. /package/{content → stacks/blazor-azure}/.morph/templates/infra/key-vault.bicep +0 -0
  285. /package/{content → stacks/blazor-azure}/.morph/templates/infra/main.bicep +0 -0
  286. /package/{content → stacks/blazor-azure}/.morph/templates/infra/parameters.dev.json +0 -0
  287. /package/{content → stacks/blazor-azure}/.morph/templates/infra/parameters.prod.json +0 -0
  288. /package/{content → stacks/blazor-azure}/.morph/templates/infra/parameters.staging.json +0 -0
  289. /package/{content → stacks/blazor-azure}/.morph/templates/infra/sql-database.bicep +0 -0
  290. /package/{content → stacks/blazor-azure}/.morph/templates/infra/storage.bicep +0 -0
  291. /package/{content → stacks/blazor-azure}/.morph/templates/integrations/asaas-client.cs +0 -0
  292. /package/{content → stacks/blazor-azure}/.morph/templates/integrations/asaas-webhook.cs +0 -0
  293. /package/{content → stacks/blazor-azure}/.morph/templates/integrations/azure-identity-config.cs +0 -0
  294. /package/{content → stacks/blazor-azure}/.morph/templates/integrations/clerk-config.cs +0 -0
  295. /package/{content → stacks/blazor-azure}/.morph/templates/job.cs +0 -0
  296. /package/{content → stacks/blazor-azure}/.morph/templates/migration.cs +0 -0
  297. /package/{content → stacks/blazor-azure}/.morph/templates/proposal.md +0 -0
  298. /package/{content → stacks/blazor-azure}/.morph/templates/recap.md +0 -0
  299. /package/{content → stacks/blazor-azure}/.morph/templates/repository.cs +0 -0
  300. /package/{content → stacks/blazor-azure}/.morph/templates/saas/subscription.cs +0 -0
  301. /package/{content → stacks/blazor-azure}/.morph/templates/saas/tenant.cs +0 -0
  302. /package/{content → stacks/blazor-azure}/.morph/templates/service.cs +0 -0
  303. /package/{content → stacks/blazor-azure}/.morph/templates/simulation.md +0 -0
  304. /package/{content → stacks/blazor-azure}/.morph/templates/spec.md +0 -0
  305. /package/{content → stacks/blazor-azure}/.morph/templates/sprint-status.yaml +0 -0
  306. /package/{content → stacks/blazor-azure}/.morph/templates/state.template.json +0 -0
  307. /package/{content → stacks/blazor-azure}/.morph/templates/story.md +0 -0
  308. /package/{content → stacks/blazor-azure}/.morph/templates/tasks.md +0 -0
  309. /package/{content → stacks/blazor-azure}/.morph/templates/test.cs +0 -0
  310. /package/{content → stacks/blazor-azure}/.morph/templates/ui-components.md +0 -0
  311. /package/{content → stacks/blazor-azure}/.morph/templates/ui-design-system.md +0 -0
  312. /package/{content → stacks/blazor-azure}/.morph/templates/ui-flows.md +0 -0
  313. /package/{content → stacks/blazor-azure}/.morph/templates/ui-mockups.md +0 -0
  314. /package/{content → stacks/blazor-azure}/.morph/test-infra/example.bicep +0 -0
  315. /package/{content → stacks/blazor-azure}/CLAUDE.md +0 -0
  316. /package/{content → stacks/blazor-azure}/README.md +0 -0
@@ -1,350 +1,350 @@
1
- /**
2
- * UI Feature Detector
3
- *
4
- * Analyzes spec.md to detect UI needs automatically.
5
- * Auto-triggers FASE 1.5: UI/UX when entities + CRUD are detected.
6
- *
7
- * MORPH-SPEC 3.0
8
- */
9
-
10
- /**
11
- * Detect UI needs from spec content
12
- * @param {string} specContent - Content of spec.md
13
- * @returns {Object} UI needs analysis
14
- */
15
- export function detectUINeeds(specContent) {
16
- const entities = parseEntities(specContent);
17
- const crudOperations = detectCRUD(specContent);
18
- const uiKeywords = detectUIKeywords(specContent);
19
-
20
- const uiNeeds = [];
21
-
22
- // Auto-detect CRUD UI needs
23
- for (const entity of entities) {
24
- if (crudOperations.create) {
25
- uiNeeds.push({
26
- type: 'form',
27
- entity: entity.name,
28
- operation: 'create',
29
- fields: entity.properties,
30
- priority: 'high'
31
- });
32
- }
33
-
34
- if (crudOperations.read || crudOperations.list) {
35
- uiNeeds.push({
36
- type: 'list',
37
- entity: entity.name,
38
- fields: entity.properties.filter(p => p.displayInList !== false),
39
- features: detectListFeatures(specContent),
40
- priority: 'high'
41
- });
42
- }
43
-
44
- if (crudOperations.update) {
45
- uiNeeds.push({
46
- type: 'form',
47
- entity: entity.name,
48
- operation: 'edit',
49
- fields: entity.properties,
50
- priority: 'medium'
51
- });
52
- }
53
-
54
- if (crudOperations.delete) {
55
- uiNeeds.push({
56
- type: 'confirm-dialog',
57
- entity: entity.name,
58
- operation: 'delete',
59
- priority: 'medium'
60
- });
61
- }
62
- }
63
-
64
- // Detect special UI components from keywords
65
- if (uiKeywords.wizard) {
66
- uiNeeds.push({
67
- type: 'wizard',
68
- steps: extractWizardSteps(specContent),
69
- priority: 'high'
70
- });
71
- }
72
-
73
- if (uiKeywords.dashboard) {
74
- uiNeeds.push({
75
- type: 'dashboard',
76
- widgets: extractDashboardWidgets(specContent),
77
- priority: 'high'
78
- });
79
- }
80
-
81
- if (uiKeywords.upload) {
82
- uiNeeds.push({
83
- type: 'file-upload',
84
- maxSize: extractMaxFileSize(specContent),
85
- allowedTypes: extractAllowedFileTypes(specContent),
86
- priority: 'high'
87
- });
88
- }
89
-
90
- const shouldTriggerUIPhase = uiNeeds.length > 0 ||
91
- entities.length > 0 ||
92
- uiKeywords.hasUIKeywords;
93
-
94
- return {
95
- shouldTrigger: shouldTriggerUIPhase,
96
- entities,
97
- crudOperations,
98
- uiNeeds,
99
- keywords: uiKeywords,
100
- confidence: calculateConfidence(entities, crudOperations, uiKeywords)
101
- };
102
- }
103
-
104
- /**
105
- * Parse entities from spec
106
- */
107
- function parseEntities(specContent) {
108
- const entities = [];
109
-
110
- // Match pseudo-code entity definitions
111
- const entityPattern = /(?:class|entity|table)\s+(\w+)\s*{([^}]+)}/gi;
112
- let match;
113
-
114
- while ((match = entityPattern.exec(specContent)) !== null) {
115
- const entityName = match[1];
116
- const body = match[2];
117
-
118
- const properties = parseProperties(body);
119
-
120
- entities.push({
121
- name: entityName,
122
- properties,
123
- hasId: properties.some(p => p.name.toLowerCase() === 'id'),
124
- hasTimestamps: properties.some(p =>
125
- p.name.toLowerCase().includes('createdat') ||
126
- p.name.toLowerCase().includes('updatedat')
127
- )
128
- });
129
- }
130
-
131
- return entities;
132
- }
133
-
134
- /**
135
- * Parse properties from entity body
136
- */
137
- function parseProperties(body) {
138
- const properties = [];
139
- const lines = body.split('\n').map(l => l.trim()).filter(l => l);
140
-
141
- for (const line of lines) {
142
- // Match: Type PropertyName or PropertyName: Type
143
- const match = line.match(/(?:(\w+)\s+(\w+)|(\w+)\s*:\s*(\w+))/);
144
- if (!match) continue;
145
-
146
- const type = match[1] || match[4];
147
- const name = match[2] || match[3];
148
-
149
- if (!type || !name) continue;
150
-
151
- properties.push({
152
- name,
153
- type,
154
- isRequired: !line.includes('?') && !line.includes('optional'),
155
- isNullable: line.includes('?'),
156
- displayInList: !isInternalProperty(name),
157
- isEnum: type.endsWith('Status') || type.endsWith('Type') || type.endsWith('Kind')
158
- });
159
- }
160
-
161
- return properties;
162
- }
163
-
164
- /**
165
- * Check if property is internal (not for display)
166
- */
167
- function isInternalProperty(name) {
168
- const internalNames = ['id', 'createdat', 'updatedat', 'deletedat', 'version', 'rowversion'];
169
- return internalNames.includes(name.toLowerCase());
170
- }
171
-
172
- /**
173
- * Detect CRUD operations from spec
174
- */
175
- function detectCRUD(specContent) {
176
- const lower = specContent.toLowerCase();
177
-
178
- return {
179
- create: /\b(create|add|new|insert|register|upload)\b/i.test(lower),
180
- read: /\b(read|get|view|show|display|retrieve|fetch)\b/i.test(lower),
181
- update: /\b(update|edit|modify|change)\b/i.test(lower),
182
- delete: /\b(delete|remove|destroy)\b/i.test(lower),
183
- list: /\b(list|index|all|search|filter|query)\b/i.test(lower)
184
- };
185
- }
186
-
187
- /**
188
- * Detect UI-specific keywords
189
- */
190
- function detectUIKeywords(specContent) {
191
- const lower = specContent.toLowerCase();
192
-
193
- return {
194
- wizard: /\b(wizard|step|multi-?step|flow)\b/i.test(lower),
195
- dashboard: /\b(dashboard|overview|summary|stats|metrics)\b/i.test(lower),
196
- chart: /\b(chart|graph|visualization|plot)\b/i.test(lower),
197
- upload: /\b(upload|file|photo|image|document|attachment)\b/i.test(lower),
198
- modal: /\b(modal|dialog|popup|overlay)\b/i.test(lower),
199
- form: /\b(form|input|field|validation)\b/i.test(lower),
200
- table: /\b(table|grid|list|datagrid)\b/i.test(lower),
201
- hasUIKeywords: /\b(wizard|dashboard|chart|upload|modal|form|table|ui|ux|screen|page|component)\b/i.test(lower)
202
- };
203
- }
204
-
205
- /**
206
- * Detect list features (pagination, filters, etc.)
207
- */
208
- function detectListFeatures(specContent) {
209
- const lower = specContent.toLowerCase();
210
-
211
- return {
212
- pagination: /\b(paginat|page|per.?page|offset|limit)\b/i.test(lower),
213
- sorting: /\b(sort|order|asc|desc)\b/i.test(lower),
214
- filtering: /\b(filter|search|query|where)\b/i.test(lower),
215
- selection: /\b(select|check|multi.?select|bulk)\b/i.test(lower),
216
- actions: /\b(action|edit|delete|view|export)\b/i.test(lower)
217
- };
218
- }
219
-
220
- /**
221
- * Extract wizard steps from spec
222
- */
223
- function extractWizardSteps(specContent) {
224
- const steps = [];
225
- const stepPattern = /step\s+(\d+):\s*([^\n]+)/gi;
226
- let match;
227
-
228
- while ((match = stepPattern.exec(specContent)) !== null) {
229
- steps.push({
230
- number: parseInt(match[1]),
231
- title: match[2].trim()
232
- });
233
- }
234
-
235
- return steps.length > 0 ? steps : [
236
- { number: 1, title: 'Information' },
237
- { number: 2, title: 'Confirmation' }
238
- ];
239
- }
240
-
241
- /**
242
- * Extract dashboard widgets from spec
243
- */
244
- function extractDashboardWidgets(specContent) {
245
- const widgets = [];
246
-
247
- if (/\b(stat|metric|kpi|count)\b/i.test(specContent)) {
248
- widgets.push({ type: 'stat-card', count: 3 });
249
- }
250
-
251
- if (/\b(chart|graph|visualization)\b/i.test(specContent)) {
252
- widgets.push({ type: 'chart', chartType: 'line' });
253
- }
254
-
255
- if (/\b(table|grid|list|recent)\b/i.test(specContent)) {
256
- widgets.push({ type: 'data-table', showActions: true });
257
- }
258
-
259
- return widgets;
260
- }
261
-
262
- /**
263
- * Extract max file size from spec
264
- */
265
- function extractMaxFileSize(specContent) {
266
- const match = specContent.match(/(\d+)\s*(mb|gb|kb)/i);
267
- if (!match) return '10MB';
268
-
269
- const size = parseInt(match[1]);
270
- const unit = match[2].toLowerCase();
271
-
272
- return `${size}${unit.toUpperCase()}`;
273
- }
274
-
275
- /**
276
- * Extract allowed file types from spec
277
- */
278
- function extractAllowedFileTypes(specContent) {
279
- const match = specContent.match(/\.(jpg|jpeg|png|pdf|doc|docx|xls|xlsx|csv|txt|zip)(?:\s*,\s*\.|\s+)/gi);
280
- if (!match) return ['.jpg', '.jpeg', '.png'];
281
-
282
- return match.map(m => m.trim().replace(/\s*,\s*$/, ''));
283
- }
284
-
285
- /**
286
- * Calculate confidence score
287
- */
288
- function calculateConfidence(entities, crudOperations, uiKeywords) {
289
- let score = 0;
290
-
291
- // Entities detected
292
- if (entities.length > 0) score += 30;
293
- if (entities.length > 2) score += 10;
294
-
295
- // CRUD operations
296
- const crudCount = Object.values(crudOperations).filter(v => v).length;
297
- score += crudCount * 10;
298
-
299
- // UI keywords
300
- if (uiKeywords.hasUIKeywords) score += 20;
301
- if (uiKeywords.wizard) score += 15;
302
- if (uiKeywords.dashboard) score += 15;
303
-
304
- return Math.min(100, score);
305
- }
306
-
307
- /**
308
- * Generate UI phase trigger message
309
- */
310
- export function generateUITriggerMessage(analysis) {
311
- if (!analysis.shouldTrigger) {
312
- return null;
313
- }
314
-
315
- const { entities, crudOperations, uiNeeds, confidence } = analysis;
316
-
317
- const parts = [];
318
-
319
- parts.push(`🎨 **UI/UX Auto-Detection** (${confidence}% confidence)`);
320
- parts.push('');
321
-
322
- if (entities.length > 0) {
323
- parts.push(`**Entities Detected:** ${entities.map(e => e.name).join(', ')}`);
324
- }
325
-
326
- if (Object.values(crudOperations).some(v => v)) {
327
- const ops = Object.entries(crudOperations)
328
- .filter(([k, v]) => v)
329
- .map(([k]) => k.toUpperCase());
330
- parts.push(`**CRUD Operations:** ${ops.join(', ')}`);
331
- }
332
-
333
- if (uiNeeds.length > 0) {
334
- parts.push('');
335
- parts.push('**UI Needs Detected:**');
336
- uiNeeds.forEach((need, i) => {
337
- const icon = need.type === 'form' ? '📝' :
338
- need.type === 'list' ? '📋' :
339
- need.type === 'wizard' ? '🧙' :
340
- need.type === 'dashboard' ? '📊' : '🔧';
341
- parts.push(`${i + 1}. ${icon} ${need.type.toUpperCase()}: ${need.entity || need.operation || 'Generic'}`);
342
- });
343
- }
344
-
345
- parts.push('');
346
- parts.push('**➡️ Auto-triggering FASE 1.5: UI/UX Design**');
347
- parts.push('Generating wireframes, component specs, and design system...');
348
-
349
- return parts.join('\n');
350
- }
1
+ /**
2
+ * UI Feature Detector
3
+ *
4
+ * Analyzes spec.md to detect UI needs automatically.
5
+ * Auto-triggers FASE 1.5: UI/UX when entities + CRUD are detected.
6
+ *
7
+ * MORPH-SPEC 3.0
8
+ */
9
+
10
+ /**
11
+ * Detect UI needs from spec content
12
+ * @param {string} specContent - Content of spec.md
13
+ * @returns {Object} UI needs analysis
14
+ */
15
+ export function detectUINeeds(specContent) {
16
+ const entities = parseEntities(specContent);
17
+ const crudOperations = detectCRUD(specContent);
18
+ const uiKeywords = detectUIKeywords(specContent);
19
+
20
+ const uiNeeds = [];
21
+
22
+ // Auto-detect CRUD UI needs
23
+ for (const entity of entities) {
24
+ if (crudOperations.create) {
25
+ uiNeeds.push({
26
+ type: 'form',
27
+ entity: entity.name,
28
+ operation: 'create',
29
+ fields: entity.properties,
30
+ priority: 'high'
31
+ });
32
+ }
33
+
34
+ if (crudOperations.read || crudOperations.list) {
35
+ uiNeeds.push({
36
+ type: 'list',
37
+ entity: entity.name,
38
+ fields: entity.properties.filter(p => p.displayInList !== false),
39
+ features: detectListFeatures(specContent),
40
+ priority: 'high'
41
+ });
42
+ }
43
+
44
+ if (crudOperations.update) {
45
+ uiNeeds.push({
46
+ type: 'form',
47
+ entity: entity.name,
48
+ operation: 'edit',
49
+ fields: entity.properties,
50
+ priority: 'medium'
51
+ });
52
+ }
53
+
54
+ if (crudOperations.delete) {
55
+ uiNeeds.push({
56
+ type: 'confirm-dialog',
57
+ entity: entity.name,
58
+ operation: 'delete',
59
+ priority: 'medium'
60
+ });
61
+ }
62
+ }
63
+
64
+ // Detect special UI components from keywords
65
+ if (uiKeywords.wizard) {
66
+ uiNeeds.push({
67
+ type: 'wizard',
68
+ steps: extractWizardSteps(specContent),
69
+ priority: 'high'
70
+ });
71
+ }
72
+
73
+ if (uiKeywords.dashboard) {
74
+ uiNeeds.push({
75
+ type: 'dashboard',
76
+ widgets: extractDashboardWidgets(specContent),
77
+ priority: 'high'
78
+ });
79
+ }
80
+
81
+ if (uiKeywords.upload) {
82
+ uiNeeds.push({
83
+ type: 'file-upload',
84
+ maxSize: extractMaxFileSize(specContent),
85
+ allowedTypes: extractAllowedFileTypes(specContent),
86
+ priority: 'high'
87
+ });
88
+ }
89
+
90
+ const shouldTriggerUIPhase = uiNeeds.length > 0 ||
91
+ entities.length > 0 ||
92
+ uiKeywords.hasUIKeywords;
93
+
94
+ return {
95
+ shouldTrigger: shouldTriggerUIPhase,
96
+ entities,
97
+ crudOperations,
98
+ uiNeeds,
99
+ keywords: uiKeywords,
100
+ confidence: calculateConfidence(entities, crudOperations, uiKeywords)
101
+ };
102
+ }
103
+
104
+ /**
105
+ * Parse entities from spec
106
+ */
107
+ function parseEntities(specContent) {
108
+ const entities = [];
109
+
110
+ // Match pseudo-code entity definitions
111
+ const entityPattern = /(?:class|entity|table)\s+(\w+)\s*{([^}]+)}/gi;
112
+ let match;
113
+
114
+ while ((match = entityPattern.exec(specContent)) !== null) {
115
+ const entityName = match[1];
116
+ const body = match[2];
117
+
118
+ const properties = parseProperties(body);
119
+
120
+ entities.push({
121
+ name: entityName,
122
+ properties,
123
+ hasId: properties.some(p => p.name.toLowerCase() === 'id'),
124
+ hasTimestamps: properties.some(p =>
125
+ p.name.toLowerCase().includes('createdat') ||
126
+ p.name.toLowerCase().includes('updatedat')
127
+ )
128
+ });
129
+ }
130
+
131
+ return entities;
132
+ }
133
+
134
+ /**
135
+ * Parse properties from entity body
136
+ */
137
+ function parseProperties(body) {
138
+ const properties = [];
139
+ const lines = body.split('\n').map(l => l.trim()).filter(l => l);
140
+
141
+ for (const line of lines) {
142
+ // Match: Type PropertyName or PropertyName: Type
143
+ const match = line.match(/(?:(\w+)\s+(\w+)|(\w+)\s*:\s*(\w+))/);
144
+ if (!match) continue;
145
+
146
+ const type = match[1] || match[4];
147
+ const name = match[2] || match[3];
148
+
149
+ if (!type || !name) continue;
150
+
151
+ properties.push({
152
+ name,
153
+ type,
154
+ isRequired: !line.includes('?') && !line.includes('optional'),
155
+ isNullable: line.includes('?'),
156
+ displayInList: !isInternalProperty(name),
157
+ isEnum: type.endsWith('Status') || type.endsWith('Type') || type.endsWith('Kind')
158
+ });
159
+ }
160
+
161
+ return properties;
162
+ }
163
+
164
+ /**
165
+ * Check if property is internal (not for display)
166
+ */
167
+ function isInternalProperty(name) {
168
+ const internalNames = ['id', 'createdat', 'updatedat', 'deletedat', 'version', 'rowversion'];
169
+ return internalNames.includes(name.toLowerCase());
170
+ }
171
+
172
+ /**
173
+ * Detect CRUD operations from spec
174
+ */
175
+ function detectCRUD(specContent) {
176
+ const lower = specContent.toLowerCase();
177
+
178
+ return {
179
+ create: /\b(create|add|new|insert|register|upload)\b/i.test(lower),
180
+ read: /\b(read|get|view|show|display|retrieve|fetch)\b/i.test(lower),
181
+ update: /\b(update|edit|modify|change)\b/i.test(lower),
182
+ delete: /\b(delete|remove|destroy)\b/i.test(lower),
183
+ list: /\b(list|index|all|search|filter|query)\b/i.test(lower)
184
+ };
185
+ }
186
+
187
+ /**
188
+ * Detect UI-specific keywords
189
+ */
190
+ function detectUIKeywords(specContent) {
191
+ const lower = specContent.toLowerCase();
192
+
193
+ return {
194
+ wizard: /\b(wizard|step|multi-?step|flow)\b/i.test(lower),
195
+ dashboard: /\b(dashboard|overview|summary|stats|metrics)\b/i.test(lower),
196
+ chart: /\b(chart|graph|visualization|plot)\b/i.test(lower),
197
+ upload: /\b(upload|file|photo|image|document|attachment)\b/i.test(lower),
198
+ modal: /\b(modal|dialog|popup|overlay)\b/i.test(lower),
199
+ form: /\b(form|input|field|validation)\b/i.test(lower),
200
+ table: /\b(table|grid|list|datagrid)\b/i.test(lower),
201
+ hasUIKeywords: /\b(wizard|dashboard|chart|upload|modal|form|table|ui|ux|screen|page|component)\b/i.test(lower)
202
+ };
203
+ }
204
+
205
+ /**
206
+ * Detect list features (pagination, filters, etc.)
207
+ */
208
+ function detectListFeatures(specContent) {
209
+ const lower = specContent.toLowerCase();
210
+
211
+ return {
212
+ pagination: /\b(paginat|page|per.?page|offset|limit)\b/i.test(lower),
213
+ sorting: /\b(sort|order|asc|desc)\b/i.test(lower),
214
+ filtering: /\b(filter|search|query|where)\b/i.test(lower),
215
+ selection: /\b(select|check|multi.?select|bulk)\b/i.test(lower),
216
+ actions: /\b(action|edit|delete|view|export)\b/i.test(lower)
217
+ };
218
+ }
219
+
220
+ /**
221
+ * Extract wizard steps from spec
222
+ */
223
+ function extractWizardSteps(specContent) {
224
+ const steps = [];
225
+ const stepPattern = /step\s+(\d+):\s*([^\n]+)/gi;
226
+ let match;
227
+
228
+ while ((match = stepPattern.exec(specContent)) !== null) {
229
+ steps.push({
230
+ number: parseInt(match[1]),
231
+ title: match[2].trim()
232
+ });
233
+ }
234
+
235
+ return steps.length > 0 ? steps : [
236
+ { number: 1, title: 'Information' },
237
+ { number: 2, title: 'Confirmation' }
238
+ ];
239
+ }
240
+
241
+ /**
242
+ * Extract dashboard widgets from spec
243
+ */
244
+ function extractDashboardWidgets(specContent) {
245
+ const widgets = [];
246
+
247
+ if (/\b(stat|metric|kpi|count)\b/i.test(specContent)) {
248
+ widgets.push({ type: 'stat-card', count: 3 });
249
+ }
250
+
251
+ if (/\b(chart|graph|visualization)\b/i.test(specContent)) {
252
+ widgets.push({ type: 'chart', chartType: 'line' });
253
+ }
254
+
255
+ if (/\b(table|grid|list|recent)\b/i.test(specContent)) {
256
+ widgets.push({ type: 'data-table', showActions: true });
257
+ }
258
+
259
+ return widgets;
260
+ }
261
+
262
+ /**
263
+ * Extract max file size from spec
264
+ */
265
+ function extractMaxFileSize(specContent) {
266
+ const match = specContent.match(/(\d+)\s*(mb|gb|kb)/i);
267
+ if (!match) return '10MB';
268
+
269
+ const size = parseInt(match[1]);
270
+ const unit = match[2].toLowerCase();
271
+
272
+ return `${size}${unit.toUpperCase()}`;
273
+ }
274
+
275
+ /**
276
+ * Extract allowed file types from spec
277
+ */
278
+ function extractAllowedFileTypes(specContent) {
279
+ const match = specContent.match(/\.(jpg|jpeg|png|pdf|doc|docx|xls|xlsx|csv|txt|zip)(?:\s*,\s*\.|\s+)/gi);
280
+ if (!match) return ['.jpg', '.jpeg', '.png'];
281
+
282
+ return match.map(m => m.trim().replace(/\s*,\s*$/, ''));
283
+ }
284
+
285
+ /**
286
+ * Calculate confidence score
287
+ */
288
+ function calculateConfidence(entities, crudOperations, uiKeywords) {
289
+ let score = 0;
290
+
291
+ // Entities detected
292
+ if (entities.length > 0) score += 30;
293
+ if (entities.length > 2) score += 10;
294
+
295
+ // CRUD operations
296
+ const crudCount = Object.values(crudOperations).filter(v => v).length;
297
+ score += crudCount * 10;
298
+
299
+ // UI keywords
300
+ if (uiKeywords.hasUIKeywords) score += 20;
301
+ if (uiKeywords.wizard) score += 15;
302
+ if (uiKeywords.dashboard) score += 15;
303
+
304
+ return Math.min(100, score);
305
+ }
306
+
307
+ /**
308
+ * Generate UI phase trigger message
309
+ */
310
+ export function generateUITriggerMessage(analysis) {
311
+ if (!analysis.shouldTrigger) {
312
+ return null;
313
+ }
314
+
315
+ const { entities, crudOperations, uiNeeds, confidence } = analysis;
316
+
317
+ const parts = [];
318
+
319
+ parts.push(`🎨 **UI/UX Auto-Detection** (${confidence}% confidence)`);
320
+ parts.push('');
321
+
322
+ if (entities.length > 0) {
323
+ parts.push(`**Entities Detected:** ${entities.map(e => e.name).join(', ')}`);
324
+ }
325
+
326
+ if (Object.values(crudOperations).some(v => v)) {
327
+ const ops = Object.entries(crudOperations)
328
+ .filter(([k, v]) => v)
329
+ .map(([k]) => k.toUpperCase());
330
+ parts.push(`**CRUD Operations:** ${ops.join(', ')}`);
331
+ }
332
+
333
+ if (uiNeeds.length > 0) {
334
+ parts.push('');
335
+ parts.push('**UI Needs Detected:**');
336
+ uiNeeds.forEach((need, i) => {
337
+ const icon = need.type === 'form' ? '📝' :
338
+ need.type === 'list' ? '📋' :
339
+ need.type === 'wizard' ? '🧙' :
340
+ need.type === 'dashboard' ? '📊' : '🔧';
341
+ parts.push(`${i + 1}. ${icon} ${need.type.toUpperCase()}: ${need.entity || need.operation || 'Generic'}`);
342
+ });
343
+ }
344
+
345
+ parts.push('');
346
+ parts.push('**➡️ Auto-triggering FASE 1.5: UI/UX Design**');
347
+ parts.push('Generating wireframes, component specs, and design system...');
348
+
349
+ return parts.join('\n');
350
+ }