@polymorphism-tech/morph-spec 8.34.2 → 8.35.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (328) hide show
  1. package/CLAUDE.md +22 -5
  2. package/README.md +2 -2
  3. package/bin/morph-spec.js +18 -4
  4. package/bin/validate.js +379 -379
  5. package/claude-plugin.json +1 -1
  6. package/docs/CHEATSHEET.md +5 -4
  7. package/docs/QUICKSTART.md +1 -1
  8. package/framework/MORPH.md +16 -17
  9. package/framework/agents.json +197 -44
  10. package/framework/ai-pin.json +22 -0
  11. package/framework/commands/morph-media.md +45 -0
  12. package/framework/docs/CLI.md +236 -11
  13. package/framework/evals/proof-rubrics/README.md +76 -0
  14. package/framework/evals/proof-rubrics/eval-de-modelo.md +64 -0
  15. package/framework/evals/proof-rubrics/fiacao.md +54 -0
  16. package/framework/evals/proof-rubrics/guard-cego.md +52 -0
  17. package/framework/evals/proof-rubrics/media-claims.md +109 -0
  18. package/framework/evals/proof-rubrics/mutation-proof.md +77 -0
  19. package/framework/evals/proof-rubrics/observabilidade-genai.md +119 -0
  20. package/framework/evals/proof-rubrics/verde-nao-e-coberto.md +48 -0
  21. package/framework/evals/rubrics/architecture.md +30 -0
  22. package/framework/evals/rubrics/code-quality.md +26 -0
  23. package/framework/evals/rubrics/test-coverage.md +20 -0
  24. package/framework/hooks/claude-code/core/protect-spec-files.js +41 -4
  25. package/framework/hooks/claude-code/core/worktree-env-inject.js +43 -0
  26. package/framework/hooks/claude-code/statusline.sh +11 -11
  27. package/framework/hooks/git/commit-msg/conventional-commits.sh +33 -33
  28. package/framework/hooks/git/pre-commit/agents.sh +25 -25
  29. package/framework/hooks/git/pre-commit/orchestrator.sh +64 -64
  30. package/framework/hooks/git/pre-commit/specs.sh +50 -50
  31. package/framework/hooks/git/pre-push/run-tests.sh +44 -44
  32. package/framework/hooks/shared/e2e-check.js +135 -22
  33. package/framework/hooks/shared/payload-utils.js +15 -2
  34. package/framework/hooks/shared/stdin-reader.js +26 -26
  35. package/framework/rules/ai-agents-standards.md +14 -2
  36. package/framework/schemas/ai-pin.schema.json +97 -0
  37. package/framework/schemas/config.schema.json +107 -0
  38. package/framework/schemas/feature.schema.json +23 -4
  39. package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
  40. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
  41. package/framework/skills/core/morph-apply/SKILL.md +26 -5
  42. package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
  43. package/framework/skills/core/morph-eval/SKILL.md +1 -1
  44. package/framework/skills/core/morph-hotfix/SKILL.md +2 -2
  45. package/framework/skills/core/morph-implement/SKILL.md +18 -2
  46. package/framework/skills/core/morph-media/SKILL.md +215 -0
  47. package/framework/skills/core/morph-plan/SKILL.md +33 -2
  48. package/framework/skills/core/morph-proposal/SKILL.md +1 -1
  49. package/framework/skills/core/morph-review/SKILL.md +166 -9
  50. package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
  51. package/framework/skills/core/morph-standards/SKILL.md +1 -1
  52. package/framework/skills/core/morph-uiux/SKILL.md +1 -1
  53. package/framework/standards/PROVENANCE.json +81 -3
  54. package/framework/standards/STANDARDS.json +1483 -839
  55. package/framework/standards/ai-agents/agent-archetypes.md +160 -0
  56. package/framework/standards/ai-agents/agent-session.md +164 -68
  57. package/framework/standards/ai-agents/agent-spec.md +196 -0
  58. package/framework/standards/ai-agents/batching.md +61 -37
  59. package/framework/standards/ai-agents/context-providers.md +97 -24
  60. package/framework/standards/ai-agents/conversational-agent-with-phases.md +239 -0
  61. package/framework/standards/ai-agents/cost-and-budget.md +256 -0
  62. package/framework/standards/ai-agents/durable-workflows-hitl.md +98 -5
  63. package/framework/standards/ai-agents/evals-with-cache.md +289 -0
  64. package/framework/standards/ai-agents/guardrails.md +222 -0
  65. package/framework/standards/ai-agents/llm-runtime-defaults.md +226 -0
  66. package/framework/standards/ai-agents/mcp-server.md +119 -18
  67. package/framework/standards/ai-agents/mcp-tools.md +85 -32
  68. package/framework/standards/ai-agents/media-pipeline.md +352 -0
  69. package/framework/standards/ai-agents/media-video.md +267 -0
  70. package/framework/standards/ai-agents/middleware-patterns.md +39 -5
  71. package/framework/standards/ai-agents/modalities-image-gen.md +354 -105
  72. package/framework/standards/ai-agents/modalities-speech-to-text.md +8 -2
  73. package/framework/standards/ai-agents/modalities-text-to-speech.md +10 -2
  74. package/framework/standards/ai-agents/modalities-vision.md +6 -2
  75. package/framework/standards/ai-agents/multi-agent-patterns.md +61 -5
  76. package/framework/standards/ai-agents/observability-patterns.md +227 -17
  77. package/framework/standards/ai-agents/production.md +38 -9
  78. package/framework/standards/ai-agents/prompt-sources.md +389 -0
  79. package/framework/standards/ai-agents/providers/model-registry.md +174 -39
  80. package/framework/standards/ai-agents/rag-custom-pgvector.md +69 -4
  81. package/framework/standards/ai-agents/service-tier-flex.md +27 -19
  82. package/framework/standards/ai-agents/setup.md +166 -50
  83. package/framework/standards/ai-agents/structured-output.md +34 -3
  84. package/framework/standards/ai-agents/sweet-spot.md +23 -3
  85. package/framework/standards/ai-agents/testing-ai.md +236 -0
  86. package/framework/standards/ai-agents/vector-data-extensions.md +50 -20
  87. package/framework/standards/ai-agents/workflows.md +27 -7
  88. package/framework/standards/frontend/design-system/ai-image-generation.md +12 -0
  89. package/framework/standards/frontend/design-system/ai-video-generation.md +13 -0
  90. package/framework/standards/infrastructure/docker/local-compose-isolation.md +3 -1
  91. package/framework/templates/.idea/morph-templates.xml +92 -0
  92. package/framework/templates/.vscode/morph-templates.code-snippets +186 -0
  93. package/framework/templates/IDE-SNIPPETS.md +262 -262
  94. package/framework/templates/REGISTRY.json +13 -0
  95. package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
  96. package/framework/templates/code/dotnet/ai-agents/AgentBootstrap.cs.template +39 -39
  97. package/framework/templates/code/dotnet/ai-agents/EmbeddingService.cs.template +68 -68
  98. package/framework/templates/code/dotnet/ai-agents/ModelRegistry.cs.template +117 -117
  99. package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +1 -1
  100. package/framework/templates/code/dotnet/ai-agents/ResilientToolMiddleware.cs.template +61 -61
  101. package/framework/templates/code/dotnet/ai-agents/VectorSearchTool.cs.template +107 -107
  102. package/framework/templates/code/dotnet/ai-agents/model-registry.json.template +58 -58
  103. package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +281 -281
  104. package/framework/templates/code/dotnet/database/migration.cs +83 -83
  105. package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +21 -21
  106. package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -4
  107. package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -4
  108. package/framework/templates/code/dotnet/feature/validator.cs.hbs +15 -15
  109. package/framework/templates/code/sql/ai-agents/agent-prompts-migration.sql.template +1 -1
  110. package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -91
  111. package/framework/templates/code/typescript/contracts.ts +167 -167
  112. package/framework/templates/docs/clarifications.md +253 -253
  113. package/framework/templates/docs/schema-analysis.md +119 -119
  114. package/framework/templates/docs/ui-components.md +52 -52
  115. package/framework/templates/docs/ui-design-system.md +76 -76
  116. package/framework/templates/docs/ui-flows.md +167 -167
  117. package/framework/templates/docs/ui-mockups.md +98 -98
  118. package/framework/templates/dotnet/ai-kit/Directory.Build.props +25 -0
  119. package/framework/templates/dotnet/ai-kit/Directory.Packages.props +26 -0
  120. package/framework/templates/dotnet/ai-kit/Morph.AiKit.sln +56 -0
  121. package/framework/templates/dotnet/ai-kit/NuGet.config +12 -0
  122. package/framework/templates/dotnet/ai-kit/README.md +128 -0
  123. package/framework/templates/dotnet/ai-kit/global.json +9 -0
  124. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentApi.cs +65 -0
  125. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactory.cs +289 -0
  126. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactoryOptions.cs +91 -0
  127. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpec.cs +91 -0
  128. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpecOptions.cs +181 -0
  129. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/AiKitAssemblyMarker.cs +14 -0
  130. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/ConversationStore.cs +174 -0
  131. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/IConversationStore.cs +54 -0
  132. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/InMemoryConversationStore.cs +75 -0
  133. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/CountingChatClient.cs +71 -0
  134. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalAssertion.cs +246 -0
  135. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheMissException.cs +57 -0
  136. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheOptions.cs +78 -0
  137. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheStamp.cs +225 -0
  138. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalFixture.cs +463 -0
  139. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalMode.cs +32 -0
  140. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalQualityEvaluators.cs +49 -0
  141. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalScenario.cs +214 -0
  142. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalSummary.cs +168 -0
  143. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/OfflineChatClient.cs +142 -0
  144. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/ShortPathResponseCache.cs +349 -0
  145. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaGenerator.cs +42 -0
  146. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaProvider.cs +77 -0
  147. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaArtifact.cs +28 -0
  148. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaDisclosure.cs +107 -0
  149. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaGenerator.cs +253 -0
  150. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaIdempotencyKey.cs +103 -0
  151. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJob.cs +259 -0
  152. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobId.cs +21 -0
  153. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobState.cs +47 -0
  154. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaPricing.cs +102 -0
  155. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaProvenance.cs +44 -0
  156. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaRequest.cs +192 -0
  157. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaResult.cs +94 -0
  158. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaReview.cs +99 -0
  159. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaSeams.cs +97 -0
  160. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaStore.cs +133 -0
  161. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MorphMedia.cs +93 -0
  162. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/GoogleImageProvider.cs +112 -0
  163. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/OpenAIImageProvider.cs +288 -0
  164. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/VeoVideoProvider.cs +158 -0
  165. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/IUsageCostSink.cs +29 -0
  166. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostMiddleware.cs +208 -0
  167. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostRecord.cs +95 -0
  168. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Morph.AiKit.csproj +38 -0
  169. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphOpenTelemetryExtensions.cs +119 -0
  170. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphTelemetryOptions.cs +82 -0
  171. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/IProviderClientFactory.cs +33 -0
  172. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelAlias.cs +267 -0
  173. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelRegistry.cs +474 -0
  174. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/model-registry.v2.json +87 -0
  175. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs +169 -0
  176. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaPlan.cs +49 -0
  177. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentFactoryTests.cs +495 -0
  178. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentSpecTests.cs +260 -0
  179. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ConversationStoreTests.cs +405 -0
  180. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/DeltaIngestTests.cs +379 -0
  181. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalAssertionTests.cs +197 -0
  182. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheMissTests.cs +139 -0
  183. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheStampTests.cs +157 -0
  184. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFailuresTests.cs +178 -0
  185. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFixtureTests.cs +153 -0
  186. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalRefreshTests.cs +194 -0
  187. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalWorkspace.cs +86 -0
  188. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/KitEvals.cs +213 -0
  189. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/OfflineChatClientTests.cs +95 -0
  190. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClient.cs +225 -0
  191. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClientTests.cs +215 -0
  192. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeClock.cs +33 -0
  193. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeMediaProvider.cs +89 -0
  194. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeProviderClientFactory.cs +55 -0
  195. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeUsageCostSink.cs +60 -0
  196. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/InMemoryMediaStore.cs +131 -0
  197. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAccessibilityTests.cs +133 -0
  198. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAliasIsNotAnAgentTests.cs +127 -0
  199. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +216 -0
  200. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaGeneratorTests.cs +264 -0
  201. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaIdempotencyKeyTests.cs +148 -0
  202. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaJobStateTests.cs +184 -0
  203. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaReviewTests.cs +89 -0
  204. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaStoreTests.cs +98 -0
  205. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ModelRegistryTests.cs +451 -0
  206. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Morph.AiKit.Tests.csproj +76 -0
  207. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/SkeletonSmokeTests.cs +33 -0
  208. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/TelemetryTests.cs +261 -0
  209. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/UsageCostMiddlewareTests.cs +374 -0
  210. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/.morph-eval-cache.json +12 -0
  211. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/contents.data +13 -0
  212. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/entry.json +7 -0
  213. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/contents.data +13 -0
  214. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/entry.json +7 -0
  215. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/contents.data +13 -0
  216. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/entry.json +7 -0
  217. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/contents.data +13 -0
  218. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/entry.json +7 -0
  219. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/orcamento/acme/a-resposta-estruturada.json +24 -0
  220. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/a-saudacao.json +23 -0
  221. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/b-escalonamento.json +24 -0
  222. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/globex/a-saudacao.json +23 -0
  223. package/framework/templates/feature/decisions.md +122 -122
  224. package/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +43 -43
  225. package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
  226. package/framework/templates/frontend/nextjs/env.mjs.hbs +32 -32
  227. package/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -56
  228. package/framework/templates/frontend/nextjs/page.tsx.hbs +22 -22
  229. package/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -26
  230. package/framework/templates/frontend/nextjs/use-feature.ts.hbs +54 -54
  231. package/framework/templates/infrastructure/docker/Dockerfile.template +58 -58
  232. package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
  233. package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
  234. package/framework/templates/infrastructure/github/README.md +56 -56
  235. package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -45
  236. package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -27
  237. package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -59
  238. package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -39
  239. package/framework/templates/integrations/asaas-client.cs +387 -387
  240. package/framework/templates/integrations/asaas-webhook.cs +351 -351
  241. package/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -76
  242. package/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -100
  243. package/framework/templates/meta-prompts/validators/pre-commit-validator.md +95 -95
  244. package/framework/templates/project/validate.js +120 -120
  245. package/framework/templates/state.template.json +17 -17
  246. package/framework/templates/ui/design-system.css +226 -226
  247. package/package.json +3 -3
  248. package/src/commands/dashboard/dashboard.js +53 -53
  249. package/src/commands/e2e/e2e.js +15 -2
  250. package/src/commands/index.js +13 -13
  251. package/src/commands/project/checkpoint.js +209 -209
  252. package/src/commands/project/doctor.js +148 -6
  253. package/src/commands/project/update.js +469 -153
  254. package/src/commands/project/worktree.js +76 -4
  255. package/src/commands/state/advance.js +24 -2
  256. package/src/commands/state/approve.js +33 -1
  257. package/src/commands/state/create.js +72 -11
  258. package/src/commands/state/finish.js +379 -24
  259. package/src/commands/state/gate-check.js +190 -6
  260. package/src/commands/state/score.js +36 -1
  261. package/src/commands/validation/verify.js +134 -25
  262. package/src/core/state/phase-state-machine.js +197 -197
  263. package/src/core/state/state-manager.js +9 -1
  264. package/src/core/templates/template-renderer.js +477 -477
  265. package/src/dashboard/app/components/DetailPanel.jsx +11 -11
  266. package/src/dashboard/app/components/FlowGraph.jsx +17 -17
  267. package/src/dashboard/app/components/SearchFilter.jsx +22 -22
  268. package/src/dashboard/app/hooks/useDetailPanel.js +15 -15
  269. package/src/dashboard/app/main.jsx +13 -13
  270. package/src/dashboard/app/pages/AgentMap.jsx +370 -370
  271. package/src/dashboard/app/pages/PhasePipeline.jsx +408 -408
  272. package/src/dashboard/app/pages/RulesMap.jsx +273 -273
  273. package/src/dashboard/app/pages/SkillsLibrary.jsx +366 -366
  274. package/src/dashboard/app/pages/Standards.jsx +332 -332
  275. package/src/dashboard/app/styles/index.css +47 -47
  276. package/src/dashboard/index.html +12 -12
  277. package/src/dashboard/package.json +24 -24
  278. package/src/dashboard/scanner/phases-scanner.js +15 -15
  279. package/src/dashboard/scanner/rubrics-scanner.js +12 -12
  280. package/src/dashboard/scanner/rules-scanner.js +37 -37
  281. package/src/dashboard/scanner/skills-scanner.js +43 -43
  282. package/src/dashboard/scanner/squads-scanner.js +13 -13
  283. package/src/dashboard/vite-plugin-morph-data.js +17 -17
  284. package/src/dashboard/vite.config.js +24 -24
  285. package/src/lib/ai/ai-checks.js +182 -0
  286. package/src/lib/ai/ai-project-scan.js +347 -0
  287. package/src/lib/ai/code-audit.js +181 -0
  288. package/src/lib/ai/comment-stripper.js +184 -0
  289. package/src/lib/ai/pin-drift.js +138 -0
  290. package/src/lib/ai/registry-audit.js +285 -0
  291. package/src/lib/detectors/design-system-detector.js +188 -188
  292. package/src/lib/detectors/index.js +217 -217
  293. package/src/lib/e2e/compose-env.js +50 -4
  294. package/src/lib/evaluator-report.js +269 -15
  295. package/src/lib/generators/design-system-generator.js +508 -508
  296. package/src/lib/generators/settings-generator.js +209 -209
  297. package/src/lib/git/default-branch.js +92 -4
  298. package/src/lib/git/pr-files.js +56 -0
  299. package/src/lib/hooks/hook-executor.js +167 -167
  300. package/src/lib/installers/effects.js +193 -0
  301. package/src/lib/installers/mcp-installer.js +719 -719
  302. package/src/lib/installers/templates-reconcile.js +3 -3
  303. package/src/lib/risk-detector.js +284 -0
  304. package/src/lib/standards/verified-against.js +276 -0
  305. package/src/lib/tasks/eval-node.js +485 -0
  306. package/src/lib/tasks/linux-runner.js +297 -0
  307. package/src/lib/tasks/task-classifier.js +30 -30
  308. package/src/lib/tasks/task-parser.js +209 -209
  309. package/src/lib/tasks/test-nodes.js +486 -0
  310. package/src/lib/tasks/test-runner.js +410 -33
  311. package/src/lib/validators/checkpoint-persistence.js +39 -39
  312. package/src/lib/validators/css/css-validator.js +340 -340
  313. package/src/lib/validators/shared/emit-validator-dispatch.js +14 -14
  314. package/src/lib/validators/shared/issue-counter.js +14 -14
  315. package/src/lib/validators/verify-runner.js +583 -28
  316. package/src/lib/worktree/docker-audit.js +287 -0
  317. package/src/lib/worktree/env-allocator.js +24 -0
  318. package/src/lib/worktree/worktree-audit.js +30 -1
  319. package/src/scripts/setup-infra.js +24 -11
  320. package/src/utils/agent-id-mapper.js +11 -11
  321. package/src/utils/agents-installer.js +18 -8
  322. package/src/utils/claude-md-injector.js +10 -5
  323. package/src/utils/claude-settings-manager.js +300 -300
  324. package/src/utils/file-copier.js +11 -4
  325. package/src/utils/hooks-installer.js +29 -26
  326. package/src/utils/skills-installer.js +36 -29
  327. package/src/utils/version-checker.js +68 -3
  328. package/framework/standards/ai-agents/prompts-in-db.md +0 -214
@@ -322,10 +322,29 @@ export function deleteStamp(gitCommonDir, projectName) {
322
322
  /**
323
323
  * Does this stack serve the working tree directly?
324
324
  *
325
- * A service that bind-mounts the project into the container reads source from
326
- * disk on every request, so a rebuild can never make it fresher — it is
327
- * already serving whatever is on disk. This is the ONE case where reuse is
328
- * unconditionally safe.
325
+ * The question is right; the answer used to be wrong. The predicate used to be
326
+ * "does ANY service mount ANYTHING under cwd" — which a Playwright sidecar
327
+ * mounting `./e2e` answers yes to. `decideReuse()` then short-circuited BEFORE
328
+ * the stamp comparison and printed "source is bind-mounted" about a stack whose
329
+ * application is a compiled image: a true statement about the sidecar, used as
330
+ * a false statement about the code under test, and the stamp — the only real
331
+ * proof of freshness — never got a say.
332
+ *
333
+ * The honest predicate looks only at services that are BUILT here, because only
334
+ * those carry code a rebuild could refresh:
335
+ *
336
+ * - no service declares `build:` → false. Nothing is compiled from this
337
+ * tree, so "a rebuild cannot make it fresher" says nothing about it, and
338
+ * the stamp decides.
339
+ * - EVERY built service mounts the project ROOT → true. Each reads source
340
+ * from disk on every request, so a running stack is current by
341
+ * construction — the ONE case where reuse is unconditionally safe.
342
+ * - anything else → false. One built service serving an image is one service
343
+ * that can be stale.
344
+ *
345
+ * A subdirectory mount is deliberately not enough: a service that mounts only
346
+ * `./e2e` still runs whatever was baked into its image. Uncertainty answers
347
+ * false, which costs one cheap layer-cached rebuild — see bringUpStack().
329
348
  *
330
349
  * @param {object} composeConfig - parsed `docker compose config --format json`
331
350
  * @param {string} cwd
@@ -335,18 +354,46 @@ export function usesBindMount(composeConfig, cwd) {
335
354
  const services = composeConfig?.services;
336
355
  if (!services || typeof services !== 'object') return false;
337
356
 
338
- const normalizedCwd = cwd.replace(/\\/g, '/').replace(/\/+$/, '');
339
-
340
- return Object.values(services).some((service) => {
341
- const volumes = Array.isArray(service?.volumes) ? service.volumes : [];
342
- return volumes.some((vol) => {
343
- // Long syntax: { type: 'bind', source: '...' }. Short syntax is a string
344
- // "src:dst" that compose has already expanded to an absolute path.
345
- const source = typeof vol === 'string' ? vol.split(':')[0] : vol?.source;
346
- if (!source) return false;
347
- const normalized = String(source).replace(/\\/g, '/').replace(/\/+$/, '');
348
- return normalized === normalizedCwd || normalized.startsWith(`${normalizedCwd}/`);
349
- });
357
+ const normalizedCwd = normalizeMountPath(cwd);
358
+ const built = Object.values(services).filter(
359
+ (service) => service && service.build !== undefined && service.build !== null,
360
+ );
361
+ if (built.length === 0) return false;
362
+
363
+ return built.every((service) => mountsProjectRoot(service, normalizedCwd));
364
+ }
365
+
366
+ /** One spelling per path, so two spellings of the same directory compare equal. */
367
+ function normalizeMountPath(path) {
368
+ return String(path ?? '')
369
+ .replace(/\\/g, '/')
370
+ .replace(/\/+$/, '');
371
+ }
372
+
373
+ /**
374
+ * Source half of a short-syntax volume ("src:dst[:mode]").
375
+ *
376
+ * Splitting on the FIRST ':' loses on Windows, where compose expands the source
377
+ * to `C:\path`. The target is always an absolute container path, so anchoring on
378
+ * the ':' that precedes it is the split that survives both platforms.
379
+ */
380
+ function shortVolumeSource(spec) {
381
+ const match = /^(.+):(\/[^:]*)(:[A-Za-z,]+)?$/.exec(spec);
382
+ return match ? match[1] : null;
383
+ }
384
+
385
+ /**
386
+ * Does this service bind-mount the project ROOT? A subdirectory does not count:
387
+ * only the root makes the whole service read its code from disk.
388
+ */
389
+ function mountsProjectRoot(service, normalizedCwd) {
390
+ const volumes = Array.isArray(service?.volumes) ? service.volumes : [];
391
+ return volumes.some((vol) => {
392
+ // Long syntax: { type: 'bind', source: '...' }; short syntax is a string.
393
+ if (typeof vol !== 'string' && vol?.type && vol.type !== 'bind') return false;
394
+ const source = typeof vol === 'string' ? shortVolumeSource(vol) : vol?.source;
395
+ if (!source) return false;
396
+ return normalizeMountPath(source) === normalizedCwd;
350
397
  });
351
398
  }
352
399
 
@@ -513,6 +560,19 @@ export function bringUpStack(
513
560
  return { status: 'pass', reused: true, output: '', reason: decision.reason };
514
561
  }
515
562
 
563
+ // "Fresh" is a promise about the DATA, not only about the image. Adding
564
+ // `--build` alone rebuilds the container and leaves the postgres volume
565
+ // standing, so the next suite talks to the previous run's database — the
566
+ // stale rows survive the very flag asked to get rid of them. The named
567
+ // volumes go first, and the stamp goes with them: a stamp that outlives the
568
+ // stack it described would let the next `up` reuse something that no longer
569
+ // exists. Teardown is best-effort by construction (tearDownStack never
570
+ // throws), so a stack that was not up costs nothing here.
571
+ if (forceFresh) {
572
+ tearDownStack(cwd, { composeFile, projectName, env, volumes: true }, exec);
573
+ deleteStamp(gitCommonDir, projectName);
574
+ }
575
+
516
576
  const upArgs = [...base, 'up', '-d', '--wait'];
517
577
  if (decision.rebuild) upArgs.push('--build');
518
578
 
@@ -555,7 +615,11 @@ function decideReuse({ cwd, base, env, stamp, status, gitCommonDir, projectName,
555
615
  if (!status.up || !status.healthy) return { reuse: false, rebuild: true };
556
616
 
557
617
  // Bind-mounted source is served from disk, so a running stack is current by
558
- // construction — the only unconditionally safe reuse.
618
+ // construction — the only unconditionally safe reuse. usesBindMount() answers
619
+ // this for the services that are BUILT here; when it says no, control falls
620
+ // through to the stamp, which is the real proof. The two reasons below stay
621
+ // distinct on purpose: whoever reads "reused warm stack" has to be able to
622
+ // tell which fact bought the reuse.
559
623
  const configJson = exec('docker', [...base, 'config', '--format', 'json'], { cwd, env });
560
624
  if (configJson.code === 0) {
561
625
  try {
@@ -666,13 +730,37 @@ export function loadEnvFile(path) {
666
730
  * screen would quietly end up with no e2e at all. Missing auth CONFIG is a
667
731
  * planning gap (Gate 2); broken auth at runtime is a real failure.
668
732
  *
669
- * @returns {{ status: 'pass'|'fail'|'skip', reason: string|null }}
733
+ * The same rule applied one level up is why `warning` exists: a config that
734
+ * declares `seedCommand` but leaves `mode` absent (or "none") used to return
735
+ * `skip` on the first line and run nothing at all. The seed was configured, the
736
+ * code knew how to execute it, and `mode` switched it off without a word — the
737
+ * silence is what made a working seedCommand look like dead configuration.
738
+ *
739
+ * @param {object} [options]
740
+ * @param {boolean} [options.forceSeed] - `--fresh-e2e`: the database was just
741
+ * dropped, so a storageState captured against it is a session for rows that
742
+ * no longer exist. Refuses the "file exists → reuse" shortcut.
743
+ * @returns {{ status: 'pass'|'fail'|'skip', reason: string|null, warning?: string }}
670
744
  */
671
- export function prepareAuth(cwd, { config, env, timeout = 60_000 } = {}, exec = defaultExec) {
745
+ export function prepareAuth(
746
+ cwd,
747
+ { config, env, timeout = 60_000, forceSeed = false } = {},
748
+ exec = defaultExec,
749
+ ) {
672
750
  const auth = config?.e2e?.auth;
673
751
  const mode = auth?.mode ?? 'none';
674
752
 
675
753
  if (mode === 'none') {
754
+ if (auth?.seedCommand) {
755
+ const declared = auth.mode == null ? 'absent' : `"${auth.mode}"`;
756
+ return {
757
+ status: 'skip',
758
+ reason: null,
759
+ warning:
760
+ `e2e.auth.seedCommand is configured but e2e.auth.mode is ${declared} — ` +
761
+ 'the seed never runs (set e2e.auth.mode to "seed" or "storageState")',
762
+ };
763
+ }
676
764
  return { status: 'skip', reason: null };
677
765
  }
678
766
 
@@ -685,10 +773,25 @@ export function prepareAuth(cwd, { config, env, timeout = 60_000 } = {}, exec =
685
773
  const statePath = auth.storageStatePath
686
774
  ? join(cwd, auth.storageStatePath)
687
775
  : null;
688
- if (statePath && existsSync(statePath)) {
776
+ const stateExists = Boolean(statePath && existsSync(statePath));
777
+
778
+ // The file's existence is not its freshness. After `--fresh-e2e` dropped
779
+ // the volumes, a storageState captured against the old database
780
+ // authenticates a user that is no longer there: every request comes back
781
+ // 403 and the failure looks like a broken app. forceSeed refuses the
782
+ // shortcut and re-establishes the session against the new database.
783
+ if (stateExists && !forceSeed) {
689
784
  return { status: 'pass', reason: 'reused stored auth session' };
690
785
  }
691
786
  if (!auth.seedCommand) {
787
+ if (stateExists) {
788
+ // Nothing to refresh it with — reusing is the only option left, and
789
+ // saying so is the difference between a reuse and a silent one.
790
+ return {
791
+ status: 'pass',
792
+ reason: 'reused stored auth session (no e2e.auth.seedCommand to refresh it)',
793
+ };
794
+ }
692
795
  return {
693
796
  status: 'fail',
694
797
  reason:
@@ -715,7 +818,12 @@ export function prepareAuth(cwd, { config, env, timeout = 60_000 } = {}, exec =
715
818
  reason: `e2e auth setup failed (${auth.seedCommand}): ${firstLine(result.output)}`,
716
819
  };
717
820
  }
718
- return { status: 'pass', reason: 'auth seeded for the e2e environment' };
821
+ return {
822
+ status: 'pass',
823
+ reason: forceSeed
824
+ ? 'auth re-seeded against the fresh stack'
825
+ : 'auth seeded for the e2e environment',
826
+ };
719
827
  }
720
828
 
721
829
  // ============================================================================
@@ -818,7 +926,12 @@ export function runE2eCheck(cwd, options = {}) {
818
926
  }
819
927
 
820
928
  try {
821
- const auth = prepareAuth(cwd, { config, env: composeEnv }, exec);
929
+ // forceSeed rides on forceFresh: the same flag that dropped the database is
930
+ // the one that invalidates any session captured against it.
931
+ const auth = prepareAuth(cwd, { config, env: composeEnv, forceSeed: forceFresh }, exec);
932
+ // A configured seed that never runs is a finding, not a detail — it travels
933
+ // to warnings[] so verify turns it into a "[e2e] warning: …" feedback line.
934
+ if (auth.warning) warnings.push(auth.warning);
822
935
  if (auth.status === 'fail') {
823
936
  return { status: 'fail', command: null, output: '', reason: auth.reason, warnings };
824
937
  }
@@ -5,6 +5,7 @@
5
5
  * normalizing between Write (content, file_path) and Edit (new_string, old_string, file_path).
6
6
  */
7
7
 
8
+ import { createHash } from 'crypto';
8
9
  import { existsSync } from 'fs';
9
10
  import { dirname, join, isAbsolute } from 'path';
10
11
 
@@ -165,7 +166,7 @@ const BASH_SIGNATURE_MAX = 120;
165
166
 
166
167
  /**
167
168
  * Build a normalized signature for loop detection.
168
- * - Edit/Write: "Edit:normalized/file/path"
169
+ * - Edit/Write: "Edit:normalized/file/path#<sha1[0:8] do conteúdo>" ("Edit:path" sem conteúdo)
169
170
  * - Bash: "Bash:<normalized command, truncated>"
170
171
  * - Every other tool WITH input: "Tool:<truncated JSON of tool_input>"
171
172
  * - No tool_input at all: just the tool name
@@ -201,7 +202,19 @@ export function getCommandSignature(payload) {
201
202
 
202
203
  if (tool === 'Edit' || tool === 'Write') {
203
204
  const path = (input.file_path || input.path || '').replace(/\\/g, '/');
204
- return path ? `${tool}:${path}` : tool;
205
+ if (!path) return tool;
206
+ // O caminho sozinho confundia TRABALHO com LOOP: editar regiões diferentes
207
+ // de dois arquivos (a forma normal de uma correção que cruza teste e
208
+ // fonte) dava só duas assinaturas e disparava o aviso. O conteúdo da
209
+ // edição entra na assinatura; repetir a MESMA edição continua casando, e o
210
+ // ping-pong A→B / B→A continua dando duas assinaturas — loop de verdade.
211
+ const body = tool === 'Write'
212
+ ? input.content
213
+ : (input.old_string !== undefined || input.new_string !== undefined)
214
+ ? `${input.old_string ?? ''}\0${input.new_string ?? ''}\0${input.replace_all ? 1 : 0}`
215
+ : undefined;
216
+ if (body === undefined || body === null) return `${tool}:${path}`;
217
+ return `${tool}:${path}#${createHash('sha1').update(String(body)).digest('hex').slice(0, 8)}`;
205
218
  }
206
219
 
207
220
  if (tool === 'Bash') {
@@ -1,26 +1,26 @@
1
- /**
2
- * Shared stdin reader for Claude Code hooks.
3
- *
4
- * Reads JSON payload from stdin (provided by Claude Code to hooks).
5
- * Returns parsed object or null on failure.
6
- */
7
-
8
- /**
9
- * Read and parse JSON from stdin
10
- * @returns {Promise<Object|null>} Parsed JSON or null
11
- */
12
- export function readStdin() {
13
- return new Promise((resolve) => {
14
- let input = '';
15
- process.stdin.setEncoding('utf-8');
16
- process.stdin.on('data', (chunk) => { input += chunk; });
17
- process.stdin.on('end', () => {
18
- try {
19
- resolve(JSON.parse(input || '{}'));
20
- } catch {
21
- resolve(null);
22
- }
23
- });
24
- process.stdin.on('error', () => resolve(null));
25
- });
26
- }
1
+ /**
2
+ * Shared stdin reader for Claude Code hooks.
3
+ *
4
+ * Reads JSON payload from stdin (provided by Claude Code to hooks).
5
+ * Returns parsed object or null on failure.
6
+ */
7
+
8
+ /**
9
+ * Read and parse JSON from stdin
10
+ * @returns {Promise<Object|null>} Parsed JSON or null
11
+ */
12
+ export function readStdin() {
13
+ return new Promise((resolve) => {
14
+ let input = '';
15
+ process.stdin.setEncoding('utf-8');
16
+ process.stdin.on('data', (chunk) => { input += chunk; });
17
+ process.stdin.on('end', () => {
18
+ try {
19
+ resolve(JSON.parse(input || '{}'));
20
+ } catch {
21
+ resolve(null);
22
+ }
23
+ });
24
+ process.stdin.on('error', () => resolve(null));
25
+ });
26
+ }
@@ -17,7 +17,7 @@ stacks:
17
17
  @.morph/framework/standards/ai-agents/providers/model-registry.md
18
18
  @.morph/framework/standards/ai-agents/structured-output.md
19
19
  @.morph/framework/standards/ai-agents/multi-agent-patterns.md
20
- @.morph/framework/standards/ai-agents/prompts-in-db.md
20
+ @.morph/framework/standards/ai-agents/prompt-sources.md
21
21
  @.morph/framework/standards/ai-agents/rag-custom-pgvector.md
22
22
  @.morph/framework/standards/ai-agents/middleware-patterns.md
23
23
  @.morph/framework/standards/ai-agents/observability-patterns.md
@@ -34,7 +34,9 @@ stacks:
34
34
  | Standard | Carregue quando a feature envolve |
35
35
  |----------|-----------------------------------|
36
36
  | `ai-agents/modalities-vision.md` | imagem → texto (OCR, análise de documento, visão) |
37
- | `ai-agents/modalities-image-gen.md` | texto → imagem (geração de mockups, posts, assets) |
37
+ | `ai-agents/modalities-image-gen.md` | gerar/editar imagem em runtime: catálogo, marketing, variação de produto — aliases pinados, custo por chamada, deprecações |
38
+ | `ai-agents/media-video.md` | gerar vídeo em runtime: Veo via `Google.GenAI`, provedores só-HTTP, custo por segundo, o arquivo que expira |
39
+ | `ai-agents/media-pipeline.md` | **qualquer** feature que gere mídia: a regra dura (nunca no turno de conversa), estados, revisão humana, proveniência, marcação (AI Act art. 50) |
38
40
  | `ai-agents/modalities-speech-to-text.md` | áudio → texto (transcrição, legendagem) |
39
41
  | `ai-agents/modalities-text-to-speech.md` | texto → áudio (síntese de voz) |
40
42
  | `ai-agents/batching.md` | processar N prompts independentes em lote (Batch API) |
@@ -43,4 +45,14 @@ stacks:
43
45
  | `ai-agents/context-providers.md` | injeção dinâmica de contexto (`AIContextProvider`) |
44
46
  | `ai-agents/mcp-tools.md` | agente MAF consome um MCP server externo |
45
47
  | `ai-agents/mcp-server.md` | projeto expõe capacidades como MCP server |
48
+ | `ai-agents/agent-archetypes.md` | escolher a FORMA do agente na fase de plano (conversa com fases, one-shot em lote, visão + structured output) |
49
+ | `ai-agents/agent-spec.md` | o agente como DADO — um `AgentSpec` imutável por agente, catálogo e defaults |
50
+ | `ai-agents/conversational-agent-with-phases.md` | conversa com fases no turno — allow-list de tools, `ChatToolMode`, teto de tool calls |
51
+ | `ai-agents/guardrails.md` | regra proibida vira código — guard de tool, pertinência, argumento não confiável, fail-open |
52
+ | `ai-agents/testing-ai.md` | testar agente sem rede — `IChatClient` fake, harness de turno, golden de prompt |
53
+ | `ai-agents/evals-with-cache.md` | eval de modelo/prompt no CI **sem credencial e sem rede**: cache de respostas commitada, dataset versionado, o que entra na chave de cache, troca de modelo e regressão de prompt |
54
+ | `ai-agents/cost-and-budget.md` | custo em dinheiro — `UsageCostMiddleware`, tarifa por token, teto de orçamento |
55
+ | `ai-agents/llm-runtime-defaults.md` | knobs de runtime da chamada — timeout, retry, `strict` JSON schema, temperatura/reasoning |
56
+ | `ai-agents/durable-workflows-hitl.md` | workflow durável e human-in-the-loop — checkpoint, `RequestPort`, aprovação de tool |
57
+ | `ai-agents/vector-data-extensions.md` | abstração `Microsoft.Extensions.VectorData` e conectores (pgvector, ingestão) |
46
58
  | `integration/mcp/mcp-tools.md` | integração MCP cross-domain (fora do escopo MAF) |
@@ -0,0 +1,97 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "$id": "https://polymorphism.com.br/morph-spec/schemas/ai-pin.schema.json",
4
+ "title": "morph-spec AI package pin",
5
+ "description": "Shape of framework/ai-pin.json — the single source of truth for the AI package versions the framework commits to. Written by a human after checking api.nuget.org; read by scripts/generate-ai-pin-props.js (Central Package Management + global.json) and by src/lib/standards/verified-against.js (age of ai-agents standards against pinnedAt). Every version is exact SemVer: a range here would restore floating versions in the generated .props, which is the defect this file exists to remove.",
6
+ "type": "object",
7
+ "required": ["pinnedAt", "source", "targetFramework", "sdk", "packages", "toolchain"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "$schema": {
11
+ "type": "string",
12
+ "description": "Relative path to this schema, so an editor validates the pin while it is edited."
13
+ },
14
+ "pinnedAt": {
15
+ "type": "string",
16
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
17
+ "description": "ISO date on which a human checked these versions against the registry. It is the anchor of the ai-agents freshness window — NOT derived from `published`: `published` is a registry fact, `pinnedAt` is the framework's commitment. A date in the future is a pin error, never a fresh standard."
18
+ },
19
+ "source": {
20
+ "type": "string",
21
+ "pattern": "^https://",
22
+ "description": "The registry endpoint the versions were read from, so the check is reproducible."
23
+ },
24
+ "targetFramework": {
25
+ "type": "string",
26
+ "pattern": "^net\\d+\\.\\d+$",
27
+ "description": "TFM the kit compiles against — the TFM the pinned Microsoft.Agents.AI declares."
28
+ },
29
+ "sdk": {
30
+ "type": "string",
31
+ "pattern": "^\\d+\\.\\d+\\.\\d+$",
32
+ "description": "SDK band written into the kit's global.json and read by actions/setup-dotnet."
33
+ },
34
+ "packages": {
35
+ "type": "object",
36
+ "description": "The AI packages the framework commits to. The SET is closed HERE, by `required` plus `maxProperties` — issue #92 pinned five, and issue #97 added the three Evaluation packages that make `verify` able to run evals from a committed response cache. `patternProperties` still carries the per-entry SHAPE, because JSON Schema cannot name a closed set of keys and repeat their shape without writing it once per key; test/framework/ai-pin.test.js reads THIS `required` list rather than a literal of its own, so the pin and its ruler can never name different sets.",
37
+ "required": [
38
+ "Microsoft.Agents.AI",
39
+ "Microsoft.Extensions.AI",
40
+ "OpenAI",
41
+ "Google.GenAI",
42
+ "ModelContextProtocol",
43
+ "Microsoft.Extensions.AI.Evaluation",
44
+ "Microsoft.Extensions.AI.Evaluation.Quality",
45
+ "Microsoft.Extensions.AI.Evaluation.Reporting"
46
+ ],
47
+ "minProperties": 8,
48
+ "maxProperties": 8,
49
+ "additionalProperties": false,
50
+ "patternProperties": {
51
+ "^[A-Za-z0-9_.-]+$": {
52
+ "type": "object",
53
+ "required": ["version", "published", "role"],
54
+ "additionalProperties": false,
55
+ "properties": {
56
+ "version": {
57
+ "type": "string",
58
+ "pattern": "^\\d+\\.\\d+\\.\\d+$",
59
+ "description": "Exact SemVer. No range, no wildcard, no floating version."
60
+ },
61
+ "published": {
62
+ "type": "string",
63
+ "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
64
+ "description": "ISO publication date of that exact version in the registry."
65
+ },
66
+ "role": {
67
+ "type": "string",
68
+ "pattern": "^[a-z0-9-]+$",
69
+ "description": "Human-readable label (maf-core, provider, mcp, ...). Documentation, not code semantics."
70
+ }
71
+ }
72
+ }
73
+ }
74
+ },
75
+ "toolchain": {
76
+ "type": "object",
77
+ "description": "Build/test packages. They live in the SAME file because the generator writes a single Directory.Packages.props; splitting them would produce two version files and the very second-truth problem the pin removes.",
78
+ "minProperties": 3,
79
+ "maxProperties": 3,
80
+ "additionalProperties": false,
81
+ "patternProperties": {
82
+ "^[A-Za-z0-9_.-]+$": {
83
+ "type": "object",
84
+ "required": ["version"],
85
+ "additionalProperties": false,
86
+ "properties": {
87
+ "version": {
88
+ "type": "string",
89
+ "pattern": "^\\d+\\.\\d+\\.\\d+$",
90
+ "description": "Exact SemVer, same rule as `packages`."
91
+ }
92
+ }
93
+ }
94
+ }
95
+ }
96
+ }
97
+ }
@@ -0,0 +1,107 @@
1
+ {
2
+ "$schema": "http://json-schema.org/draft-07/schema#",
3
+ "title": "MORPH-SPEC .morph/config/config.json",
4
+ "description": "Describes ONLY project.tests[] — the plural declaration of the project's test suites. Everything else in config.json is deliberately left open (additionalProperties: true) so that configs already in the field never break on a key this schema has not heard of. The authority at runtime is validateTestNodes() in src/lib/tasks/test-nodes.js: a schema nothing calls is decoration.",
5
+ "type": "object",
6
+ "additionalProperties": true,
7
+ "properties": {
8
+ "project": {
9
+ "type": "object",
10
+ "additionalProperties": true,
11
+ "properties": {
12
+ "tests": {
13
+ "type": "array",
14
+ "description": "One entry per test suite. Absent (not empty) means the four-step fallback of resolveTestPlan() decides — every project created before this key existed keeps working. An empty array is an explicit declaration of 'no test suites'.",
15
+ "items": {
16
+ "type": "object",
17
+ "additionalProperties": false,
18
+ "required": ["id", "command"],
19
+ "properties": {
20
+ "id": {
21
+ "type": "string",
22
+ "pattern": "^[a-z0-9][a-z0-9-]*$",
23
+ "description": "Unique within the array. What `verify --filter` matches and the key of nodes.tests.runs[]. A duplicate id is a config error, not a silent tie."
24
+ },
25
+ "command": {
26
+ "type": "string",
27
+ "minLength": 1,
28
+ "description": "Literal command, executed by the shell from `cwd`."
29
+ },
30
+ "cwd": {
31
+ "type": "string",
32
+ "minLength": 1,
33
+ "default": ".",
34
+ "description": "Relative to the project root. A path that resolves outside the root is refused: it addresses another tree."
35
+ },
36
+ "runner": {
37
+ "type": "string",
38
+ "enum": ["dotnet", "vitest", "jest", "node-test", "playwright", "none", "evals"],
39
+ "description": "Chooses the test-count extractor and whether a prebuild applies. Inferred from `command` when omitted; `none` means the count is UNKNOWN, never zero. `evals` is the ONLY value that is never inferred - it is a declaration that this suite reads a committed response cache, and it REQUIRES the `evals` block below."
40
+ },
41
+ "expectedCount": {
42
+ "type": "integer",
43
+ "minimum": 0,
44
+ "description": "Recorded baseline. Written ONLY by `morph-spec verify --record-baseline`, from a green run — never typed by hand."
45
+ },
46
+ "timeoutMs": {
47
+ "type": "integer",
48
+ "minimum": 1,
49
+ "description": "Ceiling for this node. Exists because the derived default (120s x chained projects) is shaped for `dotnet test` and is hostile to a Node suite that takes twelve minutes."
50
+ },
51
+ "build": {
52
+ "type": "array",
53
+ "items": { "type": "string", "minLength": 1 },
54
+ "description": "Test projects to compile before running (runner 'dotnet' only). Without it, `--no-build` in the command has no fresh binary behind it."
55
+ },
56
+ "e2e": {
57
+ "type": "boolean",
58
+ "default": false,
59
+ "description": "Requires the application stack to be up. Runs at feature scope only, never in the per-task loop."
60
+ },
61
+ "linuxImage": {
62
+ "type": "string",
63
+ "minLength": 1,
64
+ "description": "Overrides the container image used by `verify --linux` for this node."
65
+ },
66
+ "evals": {
67
+ "type": "object",
68
+ "additionalProperties": false,
69
+ "required": ["cachePath"],
70
+ "description": "Required by, and only valid for, runner evals. Declared on any other runner it would be a key the verifier silently ignores - the same fail-open shape as a typo in tests[].",
71
+ "properties": {
72
+ "cachePath": {
73
+ "type": "string",
74
+ "minLength": 1,
75
+ "description": "Root of the response-cache tree, relative to the project root, and COMMITTED. A path that resolves outside the root is refused, same rule as `cwd`. No default: a silent one would create a cache tree somewhere nobody declared."
76
+ },
77
+ "datasetPath": {
78
+ "type": "string",
79
+ "minLength": 1,
80
+ "description": "Root of the versioned dataset, laid out as {agent}/{tenant}/{scenario}.json. Defaults to `eval-datasets` beside cachePath."
81
+ },
82
+ "envFile": {
83
+ "type": "string",
84
+ "minLength": 1,
85
+ "description": "GITIGNORED file holding the provider credential, read ONLY by --refresh-cache. Same pattern as e2e.auth.envFile; a credential never travels in the committed config. Defaults to `.env.evals`."
86
+ }
87
+ }
88
+ }
89
+ }
90
+ }
91
+ },
92
+ "evals": {
93
+ "type": "object",
94
+ "additionalProperties": true,
95
+ "description": "Project-level eval settings, distinct from the per-node block above: this one describes the PROJECT (which paths count as prompt or model), not one suite.",
96
+ "properties": {
97
+ "watch": {
98
+ "type": "array",
99
+ "items": { "type": "string", "minLength": 1 },
100
+ "description": "Globs that mean 'this is a prompt or a model'. Matched against what the feature changed (git diff plus untracked) to decide whether Gate 3 should pause for a missing eval. Absent means the project declares no such paths - reported as a reason of its own, distinct from 'declared and nothing was touched'."
101
+ }
102
+ }
103
+ }
104
+ }
105
+ }
106
+ }
107
+ }
@@ -107,7 +107,8 @@
107
107
  "build": { "type": "string", "enum": ["pass", "fail", "skip"] },
108
108
  "tests": { "type": "string", "enum": ["pass", "fail", "skip"] },
109
109
  "validators": { "type": "string", "enum": ["pass", "fail", "skip"] },
110
- "e2e": { "type": "string", "enum": ["pass", "fail", "skip"], "description": "Docker bring-up + Playwright specs against the running stack. Absent on entries written before the node existed — which is why it is NOT in `required`." }
110
+ "e2e": { "type": "string", "enum": ["pass", "fail", "skip"], "description": "Docker bring-up + Playwright specs against the running stack. Absent on entries written before the node existed — which is why it is NOT in `required`." },
111
+ "evals": { "type": ["string", "null"], "enum": ["pass", "fail", "skip", null], "description": "Eval suites, pulled out of the tests rollup. Written by the SAME function that writes the singular stamp (nodeStatuses in verify.js): the two shapes must stay identical, or a stamp would omit what the history records. null means the project declares no eval node at all — distinct from skip, which means it declares one and this run did not execute it. Absent on entries written before the field existed, which is why it is NOT in required." }
111
112
  },
112
113
  "additionalProperties": false
113
114
  },
@@ -134,7 +135,8 @@
134
135
  "build": { "type": "string", "enum": ["pass", "fail", "skip"] },
135
136
  "tests": { "type": "string", "enum": ["pass", "fail", "skip"] },
136
137
  "validators": { "type": "string", "enum": ["pass", "fail", "skip"] },
137
- "e2e": { "type": "string", "enum": ["pass", "fail", "skip"], "description": "Docker bring-up + Playwright specs against the running stack. Absent on entries written before the node existed — which is why it is NOT in `required`." }
138
+ "e2e": { "type": "string", "enum": ["pass", "fail", "skip"], "description": "Docker bring-up + Playwright specs against the running stack. Absent on entries written before the node existed — which is why it is NOT in `required`." },
139
+ "evals": { "type": ["string", "null"], "enum": ["pass", "fail", "skip", null], "description": "Eval suites, pulled out of the tests rollup. Written by the SAME function that writes the singular stamp (nodeStatuses in verify.js): the two shapes must stay identical, or a stamp would omit what the history records. null means the project declares no eval node at all — distinct from skip, which means it declares one and this run did not execute it. Absent on entries written before the field existed, which is why it is NOT in required." }
138
140
  },
139
141
  "additionalProperties": false
140
142
  },
@@ -149,13 +151,30 @@
149
151
  },
150
152
  "verification": {
151
153
  "type": "object",
152
- "description": "The single latest deterministic verify stamp (any scope), written ONLY by `morph-spec verify`. Distinct from `verifications`/`taskVerifications` above (per-scope history with attempts/nodes): this is overwritten by every verify call regardless of scope, carrying just enough to correlate a pass/fail with the exact commit it covers. Primary consumer: `morph-spec gate-check`, which feeds `status` to shouldPauseGate as `verificationStatus` — a red verify pauses the gate (risk-detector.js). The remaining fields (sha/ts/scope, and the derived `verificationStale`) are audit context, not pause rules.",
154
+ "description": "The single latest deterministic verify stamp (any scope), written ONLY by `morph-spec verify`. Distinct from `verifications`/`taskVerifications` above (per-scope history with attempts/nodes): this is overwritten by every verify call regardless of scope, carrying just enough to correlate a pass/fail with the exact commit it covers. Primary consumer: `morph-spec gate-check`, which feeds `status` to shouldPauseGate as `verificationStatus` — a red verify pauses the gate (risk-detector.js) — and `nodes.e2e`/`e2eReason` as `e2eStatus`/`e2eReason`, the pair that decides whether an e2e SKIP is a recorded dispensation or an absence of proof (a skip never reddens `status`, so the rollup alone is blind to it). `scope` is the third pause input: a dispensation only counts from a feature-scoped stamp (see the field below). The rest (sha/ts, and the derived `verificationStale`) is audit context.",
153
155
  "required": ["status", "sha", "ts", "scope"],
154
156
  "properties": {
155
157
  "status": { "type": "string", "enum": ["pass", "fail"] },
158
+ "nodes": {
159
+ "type": "object",
160
+ "description": "Per-node status of the verify that wrote this stamp. NOT in `required`: stamps written before the field existed carry only the rollup. Same values as `verifications.feature.nodes`, repeated here because gate-check reads the stamp and nothing else.",
161
+ "properties": {
162
+ "build": { "type": "string", "enum": ["pass", "fail", "skip"] },
163
+ "tests": { "type": "string", "enum": ["pass", "fail", "skip"] },
164
+ "validators": { "type": "string", "enum": ["pass", "fail", "skip"] },
165
+ "e2e": { "type": "string", "enum": ["pass", "fail", "skip"] },
166
+ "evals": {
167
+ "type": ["string", "null"],
168
+ "enum": ["pass", "fail", "skip", null],
169
+ "description": "Status of the `runner: \"evals\"` entries of nodes.tests.runs[], pulled out of the rollup. The rollup cannot answer what Gate 3 asks: a red eval and a red unit test both read as tests:fail, and an eval SKIPPED at task scope leaves the rollup green. null means this project declares NO eval node - distinct from 'skip', which means it declares one and this run did not execute it; risk-detector.js pauses on the two for different reasons because they call for different actions. Absent on stamps written before this field existed."
170
+ }
171
+ },
172
+ "additionalProperties": false
173
+ },
174
+ "e2eReason": { "type": ["string", "null"], "description": "The LITERAL reason the e2e node skipped (e2e-check.js's own wording), or null when it did not skip. risk-detector.js's classifyE2eSkip() reads it: 'project does not containerize' / 'does not touch runtime' are legitimate dispensations and pass; 'docker is not available' / 'requested' (--skip-e2e) / anything unclassifiable — null included — are an absence of proof and pause Gate 3. A skip recorded WITHOUT a reason is refused on purpose: a nameless dispensation is a silent no-op." },
156
175
  "sha": { "type": ["string", "null"], "description": "HEAD commit SHA at verify time (git rev-parse HEAD); null when not in a git repo or no commits yet." },
157
176
  "ts": { "type": "string", "format": "date-time", "description": "Server-side timestamp, same instant as the corresponding verifications/taskVerifications entry's updatedAt." },
158
- "scope": { "type": "string", "description": "'feature', or 'task:<id>' for a task-scoped verify." }
177
+ "scope": { "type": "string", "description": "'feature', or 'task:<id>' for a task-scoped verify. READ BY THE GATE, not just audit: this stamp is singular and any verify overwrites it, so a 'task:<id>' value at ship time means the last verify was NOT the feature's. risk-detector.js therefore accepts an e2e dispensation ('project'/'scope' in e2eReason) only from scope === 'feature' — a `morph-spec verify {f} {task}` of a task whose group does not touch runtime stamps exactly the legitimate-sounding reason that would otherwise buy Gate 3 for the whole feature (the last task of a feature is typically group: docs). Absent/unknown falls on the safe side, like an unclassifiable reason." }
159
178
  },
160
179
  "additionalProperties": false
161
180
  },
@@ -4,7 +4,7 @@ description: Guia a criação de uma landing page nova ponta-a-ponta a partir do
4
4
  version: core
5
5
  when-to-invoke: ao iniciar um novo projeto de LP com o template Umbraco genérico
6
6
  user-invokable: true
7
- cliVersion: "8.34.2"
7
+ cliVersion: "8.35.1"
8
8
  stacks:
9
9
  - umbraco
10
10
  ---
@@ -4,7 +4,7 @@ description: Migra uma landing page existente (React/Vite, Next.js estático ou
4
4
  version: core
5
5
  when-to-invoke: ao receber instrução "use /migrate-lp-to-umbraco {projeto}" do usuário, ou quando o usuário descrever necessidade de migrar uma LP para Umbraco
6
6
  user-invokable: true
7
- cliVersion: "8.34.2"
7
+ cliVersion: "8.35.1"
8
8
  stacks:
9
9
  - umbraco
10
10
  ---