@polymorphism-tech/morph-spec 8.33.0 → 8.35.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 (253) hide show
  1. package/CLAUDE.md +22 -2
  2. package/README.md +2 -2
  3. package/bin/morph-spec.js +43 -5
  4. package/claude-plugin.json +1 -1
  5. package/docs/CHEATSHEET.md +5 -4
  6. package/docs/QUICKSTART.md +1 -1
  7. package/framework/CLAUDE.md +2 -2
  8. package/framework/MORPH.md +20 -22
  9. package/framework/agents.json +198 -44
  10. package/framework/ai-pin.json +22 -0
  11. package/framework/commands/morph-media.md +45 -0
  12. package/framework/docs/CLI.md +238 -10
  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/README.md +11 -1
  25. package/framework/hooks/claude-code/core/block-destructive-worktree-removal.js +5 -8
  26. package/framework/hooks/claude-code/core/block-raw-worktree-add.js +79 -0
  27. package/framework/hooks/claude-code/core/chain.js +27 -7
  28. package/framework/hooks/claude-code/core/protect-spec-files.js +41 -4
  29. package/framework/hooks/claude-code/core/worktree-context.js +83 -14
  30. package/framework/hooks/claude-code/core/worktree-create.js +206 -0
  31. package/framework/hooks/claude-code/core/worktree-env-inject.js +87 -0
  32. package/framework/hooks/claude-code/core/worktree-remove.js +81 -0
  33. package/framework/hooks/shared/command-tokens.js +23 -0
  34. package/framework/hooks/shared/e2e-check.js +0 -0
  35. package/framework/hooks/shared/git-paths.js +25 -0
  36. package/framework/hooks/shared/hook-response.js +17 -0
  37. package/framework/hooks/shared/morph-cli.js +134 -0
  38. package/framework/rules/ai-agents-standards.md +14 -2
  39. package/framework/rules/infrastructure-standards.md +3 -1
  40. package/framework/schemas/ai-pin.schema.json +97 -0
  41. package/framework/schemas/config.schema.json +107 -0
  42. package/framework/schemas/feature.schema.json +23 -4
  43. package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
  44. package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
  45. package/framework/skills/core/morph-apply/SKILL.md +28 -7
  46. package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
  47. package/framework/skills/core/morph-eval/SKILL.md +1 -1
  48. package/framework/skills/core/morph-hotfix/SKILL.md +2 -2
  49. package/framework/skills/core/morph-implement/SKILL.md +20 -2
  50. package/framework/skills/core/morph-media/SKILL.md +215 -0
  51. package/framework/skills/core/morph-plan/SKILL.md +38 -4
  52. package/framework/skills/core/morph-proposal/SKILL.md +1 -1
  53. package/framework/skills/core/morph-review/SKILL.md +166 -9
  54. package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
  55. package/framework/skills/core/morph-standards/SKILL.md +1 -1
  56. package/framework/skills/core/morph-uiux/SKILL.md +1 -1
  57. package/framework/standards/PROVENANCE.json +81 -3
  58. package/framework/standards/STANDARDS.json +1504 -830
  59. package/framework/standards/ai-agents/agent-archetypes.md +160 -0
  60. package/framework/standards/ai-agents/agent-session.md +256 -160
  61. package/framework/standards/ai-agents/agent-spec.md +196 -0
  62. package/framework/standards/ai-agents/batching.md +217 -193
  63. package/framework/standards/ai-agents/context-providers.md +261 -188
  64. package/framework/standards/ai-agents/conversational-agent-with-phases.md +239 -0
  65. package/framework/standards/ai-agents/cost-and-budget.md +256 -0
  66. package/framework/standards/ai-agents/durable-workflows-hitl.md +98 -5
  67. package/framework/standards/ai-agents/evals-with-cache.md +289 -0
  68. package/framework/standards/ai-agents/guardrails.md +222 -0
  69. package/framework/standards/ai-agents/llm-runtime-defaults.md +226 -0
  70. package/framework/standards/ai-agents/mcp-server.md +351 -250
  71. package/framework/standards/ai-agents/mcp-tools.md +250 -197
  72. package/framework/standards/ai-agents/media-pipeline.md +352 -0
  73. package/framework/standards/ai-agents/media-video.md +267 -0
  74. package/framework/standards/ai-agents/middleware-patterns.md +241 -207
  75. package/framework/standards/ai-agents/modalities-image-gen.md +422 -173
  76. package/framework/standards/ai-agents/modalities-speech-to-text.md +177 -171
  77. package/framework/standards/ai-agents/modalities-text-to-speech.md +189 -181
  78. package/framework/standards/ai-agents/modalities-vision.md +205 -201
  79. package/framework/standards/ai-agents/multi-agent-patterns.md +211 -155
  80. package/framework/standards/ai-agents/observability-patterns.md +227 -17
  81. package/framework/standards/ai-agents/production.md +260 -231
  82. package/framework/standards/ai-agents/prompt-sources.md +389 -0
  83. package/framework/standards/ai-agents/providers/model-registry.md +293 -158
  84. package/framework/standards/ai-agents/rag-custom-pgvector.md +69 -4
  85. package/framework/standards/ai-agents/service-tier-flex.md +143 -135
  86. package/framework/standards/ai-agents/setup.md +166 -50
  87. package/framework/standards/ai-agents/structured-output.md +280 -249
  88. package/framework/standards/ai-agents/sweet-spot.md +129 -109
  89. package/framework/standards/ai-agents/testing-ai.md +236 -0
  90. package/framework/standards/ai-agents/vector-data-extensions.md +50 -20
  91. package/framework/standards/ai-agents/workflows.md +27 -7
  92. package/framework/standards/frontend/design-system/ai-image-generation.md +12 -0
  93. package/framework/standards/frontend/design-system/ai-video-generation.md +13 -0
  94. package/framework/standards/infrastructure/docker/local-compose-isolation.md +90 -0
  95. package/framework/templates/REGISTRY.json +14 -1
  96. package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +95 -95
  97. package/framework/templates/code/sql/ai-agents/agent-prompts-migration.sql.template +58 -58
  98. package/framework/templates/dotnet/ai-kit/Directory.Build.props +25 -0
  99. package/framework/templates/dotnet/ai-kit/Directory.Packages.props +26 -0
  100. package/framework/templates/dotnet/ai-kit/Morph.AiKit.sln +56 -0
  101. package/framework/templates/dotnet/ai-kit/NuGet.config +12 -0
  102. package/framework/templates/dotnet/ai-kit/README.md +128 -0
  103. package/framework/templates/dotnet/ai-kit/global.json +9 -0
  104. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentApi.cs +65 -0
  105. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactory.cs +289 -0
  106. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactoryOptions.cs +91 -0
  107. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpec.cs +91 -0
  108. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpecOptions.cs +181 -0
  109. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/AiKitAssemblyMarker.cs +14 -0
  110. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/ConversationStore.cs +174 -0
  111. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/IConversationStore.cs +54 -0
  112. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/InMemoryConversationStore.cs +75 -0
  113. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/CountingChatClient.cs +71 -0
  114. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalAssertion.cs +246 -0
  115. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheMissException.cs +57 -0
  116. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheOptions.cs +78 -0
  117. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheStamp.cs +225 -0
  118. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalFixture.cs +463 -0
  119. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalMode.cs +32 -0
  120. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalQualityEvaluators.cs +49 -0
  121. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalScenario.cs +214 -0
  122. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalSummary.cs +168 -0
  123. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/OfflineChatClient.cs +142 -0
  124. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/ShortPathResponseCache.cs +349 -0
  125. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaGenerator.cs +42 -0
  126. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaProvider.cs +77 -0
  127. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaArtifact.cs +28 -0
  128. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaDisclosure.cs +107 -0
  129. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaGenerator.cs +253 -0
  130. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaIdempotencyKey.cs +103 -0
  131. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJob.cs +259 -0
  132. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobId.cs +21 -0
  133. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobState.cs +47 -0
  134. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaPricing.cs +102 -0
  135. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaProvenance.cs +44 -0
  136. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaRequest.cs +192 -0
  137. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaResult.cs +94 -0
  138. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaReview.cs +99 -0
  139. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaSeams.cs +97 -0
  140. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaStore.cs +133 -0
  141. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MorphMedia.cs +93 -0
  142. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/GoogleImageProvider.cs +112 -0
  143. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/OpenAIImageProvider.cs +288 -0
  144. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/VeoVideoProvider.cs +158 -0
  145. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/IUsageCostSink.cs +29 -0
  146. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostMiddleware.cs +208 -0
  147. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostRecord.cs +95 -0
  148. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Morph.AiKit.csproj +38 -0
  149. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphOpenTelemetryExtensions.cs +119 -0
  150. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphTelemetryOptions.cs +82 -0
  151. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/IProviderClientFactory.cs +33 -0
  152. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelAlias.cs +267 -0
  153. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelRegistry.cs +474 -0
  154. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/model-registry.v2.json +87 -0
  155. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs +169 -0
  156. package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaPlan.cs +49 -0
  157. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentFactoryTests.cs +495 -0
  158. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentSpecTests.cs +260 -0
  159. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ConversationStoreTests.cs +405 -0
  160. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/DeltaIngestTests.cs +379 -0
  161. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalAssertionTests.cs +197 -0
  162. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheMissTests.cs +139 -0
  163. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheStampTests.cs +157 -0
  164. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFailuresTests.cs +178 -0
  165. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFixtureTests.cs +153 -0
  166. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalRefreshTests.cs +194 -0
  167. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalWorkspace.cs +86 -0
  168. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/KitEvals.cs +213 -0
  169. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/OfflineChatClientTests.cs +95 -0
  170. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClient.cs +225 -0
  171. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClientTests.cs +215 -0
  172. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeClock.cs +33 -0
  173. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeMediaProvider.cs +89 -0
  174. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeProviderClientFactory.cs +55 -0
  175. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeUsageCostSink.cs +60 -0
  176. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/InMemoryMediaStore.cs +131 -0
  177. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAccessibilityTests.cs +133 -0
  178. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAliasIsNotAnAgentTests.cs +127 -0
  179. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +216 -0
  180. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaGeneratorTests.cs +264 -0
  181. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaIdempotencyKeyTests.cs +148 -0
  182. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaJobStateTests.cs +184 -0
  183. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaReviewTests.cs +89 -0
  184. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaStoreTests.cs +98 -0
  185. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ModelRegistryTests.cs +451 -0
  186. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Morph.AiKit.Tests.csproj +76 -0
  187. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/SkeletonSmokeTests.cs +33 -0
  188. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/TelemetryTests.cs +261 -0
  189. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/UsageCostMiddlewareTests.cs +374 -0
  190. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/.morph-eval-cache.json +12 -0
  191. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/contents.data +13 -0
  192. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/entry.json +7 -0
  193. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/contents.data +13 -0
  194. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/entry.json +7 -0
  195. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/contents.data +13 -0
  196. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/entry.json +7 -0
  197. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/contents.data +13 -0
  198. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/entry.json +7 -0
  199. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/orcamento/acme/a-resposta-estruturada.json +24 -0
  200. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/a-saudacao.json +23 -0
  201. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/b-escalonamento.json +24 -0
  202. package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/globex/a-saudacao.json +23 -0
  203. package/framework/templates/infrastructure/docker/docker-compose.template.yml +24 -14
  204. package/package.json +3 -3
  205. package/src/commands/e2e/e2e.js +91 -40
  206. package/src/commands/project/doctor.js +143 -6
  207. package/src/commands/project/env.js +95 -0
  208. package/src/commands/project/update.js +469 -153
  209. package/src/commands/project/worktree.js +274 -53
  210. package/src/commands/state/advance.js +24 -2
  211. package/src/commands/state/approve.js +33 -1
  212. package/src/commands/state/create.js +72 -11
  213. package/src/commands/state/delete.js +8 -0
  214. package/src/commands/state/finish.js +360 -53
  215. package/src/commands/state/gate-check.js +190 -6
  216. package/src/commands/state/score.js +36 -1
  217. package/src/commands/validation/verify.js +134 -25
  218. package/src/core/state/state-manager.js +9 -1
  219. package/src/dashboard/app/pages/HookInspector.jsx +430 -418
  220. package/src/dashboard/scanner/hooks-scanner.js +5 -1
  221. package/src/lib/ai/ai-checks.js +182 -0
  222. package/src/lib/ai/ai-project-scan.js +347 -0
  223. package/src/lib/ai/code-audit.js +181 -0
  224. package/src/lib/ai/comment-stripper.js +184 -0
  225. package/src/lib/ai/pin-drift.js +138 -0
  226. package/src/lib/ai/registry-audit.js +285 -0
  227. package/src/lib/e2e/compose-env.js +55 -14
  228. package/src/lib/e2e/stack-teardown.js +115 -0
  229. package/src/lib/evaluator-report.js +269 -15
  230. package/src/lib/generators/architecture-scanner.js +2 -1
  231. package/src/lib/git/default-branch.js +92 -4
  232. package/src/lib/graph/graphifyignore.js +2 -1
  233. package/src/lib/installers/effects.js +193 -0
  234. package/src/lib/installers/templates-reconcile.js +3 -3
  235. package/src/lib/risk-detector.js +284 -0
  236. package/src/lib/standards/verified-against.js +276 -0
  237. package/src/lib/tasks/eval-node.js +485 -0
  238. package/src/lib/tasks/linux-runner.js +297 -0
  239. package/src/lib/tasks/test-nodes.js +486 -0
  240. package/src/lib/tasks/test-runner.js +431 -37
  241. package/src/lib/validators/verify-runner.js +590 -28
  242. package/src/lib/worktree/dirs.js +32 -0
  243. package/src/lib/worktree/docker-audit.js +287 -0
  244. package/src/lib/worktree/env-allocator.js +69 -11
  245. package/src/lib/worktree/worktree-audit.js +70 -3
  246. package/src/scripts/setup-infra.js +24 -11
  247. package/src/utils/agents-installer.js +18 -8
  248. package/src/utils/claude-md-injector.js +10 -5
  249. package/src/utils/file-copier.js +28 -16
  250. package/src/utils/hooks-installer.js +75 -29
  251. package/src/utils/skills-installer.js +194 -187
  252. package/src/utils/version-checker.js +68 -3
  253. package/framework/standards/ai-agents/prompts-in-db.md +0 -214
@@ -0,0 +1,13 @@
1
+ {
2
+ "messages": [
3
+ {
4
+ "role": "assistant",
5
+ "contents": [
6
+ {
7
+ "$type": "text",
8
+ "text": "Bom dia! Como posso ajudar voce hoje?"
9
+ }
10
+ ]
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "scenarioName": "triagem.acme.a-saudacao",
3
+ "iterationName": "1",
4
+ "key": "19F631228C6E00BA41892982E6EA1BB23822FA53D6E62C79B6724893618E7E03AE4F70F94332FDEE0DAA960974BA1171",
5
+ "creation": "2026-09-09T04:54:34.8385364+00:00",
6
+ "expiration": "2036-09-06T04:54:34.8385364+00:00"
7
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "messages": [
3
+ {
4
+ "role": "assistant",
5
+ "contents": [
6
+ {
7
+ "$type": "text",
8
+ "text": "Encaminhando voce para um atendente humano agora."
9
+ }
10
+ ]
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "scenarioName": "triagem.acme.b-escalonamento",
3
+ "iterationName": "1",
4
+ "key": "A24A7C9BDD8239D87A60FD05A4BF870DAB4CFBE8BE7A796FF86534B6F37F4517321D3420D76ED6B5EF000C68CB18301F",
5
+ "creation": "2026-09-09T04:54:34.8448053+00:00",
6
+ "expiration": "2036-09-06T04:54:34.8448053+00:00"
7
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "messages": [
3
+ {
4
+ "role": "assistant",
5
+ "contents": [
6
+ {
7
+ "$type": "text",
8
+ "text": "Bom dia! Aqui e o atendimento da Globex."
9
+ }
10
+ ]
11
+ }
12
+ ]
13
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "scenarioName": "triagem.globex.a-saudacao",
3
+ "iterationName": "1",
4
+ "key": "E38CD37DF003EDB77815FF1A086F48ACBDD63E743D44DFFDF2A23EEED34731E8D3B6E51A4EBB740CB0BF2720D8AA02ED",
5
+ "creation": "2026-09-09T04:54:34.846003+00:00",
6
+ "expiration": "2036-09-06T04:54:34.846003+00:00"
7
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "messages": [
3
+ {
4
+ "role": "system",
5
+ "text": "Responda SOMENTE com um objeto JSON com as chaves valor e prazo."
6
+ },
7
+ {
8
+ "role": "user",
9
+ "text": "quanto custa a revisao anual?"
10
+ }
11
+ ],
12
+ "assertions": [
13
+ {
14
+ "name": "tem-valor",
15
+ "kind": "json-has-key",
16
+ "target": "valor"
17
+ },
18
+ {
19
+ "name": "tem-prazo",
20
+ "kind": "json-has-key",
21
+ "target": "prazo"
22
+ }
23
+ ]
24
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "messages": [
3
+ {
4
+ "role": "system",
5
+ "text": "Voce e o atendente da Acme. Responda em portugues, em uma frase."
6
+ },
7
+ {
8
+ "role": "user",
9
+ "text": "bom dia"
10
+ }
11
+ ],
12
+ "assertions": [
13
+ {
14
+ "name": "cumprimenta",
15
+ "kind": "contains",
16
+ "value": "bom dia"
17
+ },
18
+ {
19
+ "name": "sem-dado-pessoal",
20
+ "kind": "no-pii"
21
+ }
22
+ ]
23
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "messages": [
3
+ {
4
+ "role": "system",
5
+ "text": "Voce e o atendente da Acme. Responda em portugues, em uma frase."
6
+ },
7
+ {
8
+ "role": "user",
9
+ "text": "quero falar com um humano agora"
10
+ }
11
+ ],
12
+ "assertions": [
13
+ {
14
+ "name": "confirma-encaminhamento",
15
+ "kind": "contains",
16
+ "value": "encaminhando"
17
+ },
18
+ {
19
+ "name": "nao-promete-prazo",
20
+ "kind": "not-contains",
21
+ "value": "garantimos"
22
+ }
23
+ ]
24
+ }
@@ -0,0 +1,23 @@
1
+ {
2
+ "messages": [
3
+ {
4
+ "role": "system",
5
+ "text": "Voce e o atendente da Globex. Responda em portugues, em uma frase."
6
+ },
7
+ {
8
+ "role": "user",
9
+ "text": "bom dia"
10
+ }
11
+ ],
12
+ "assertions": [
13
+ {
14
+ "name": "cumprimenta",
15
+ "kind": "contains",
16
+ "value": "Globex"
17
+ },
18
+ {
19
+ "name": "sem-dado-pessoal",
20
+ "kind": "no-pii"
21
+ }
22
+ ]
23
+ }
@@ -1,17 +1,29 @@
1
1
  # Docker Compose for Local Development
2
2
  # Next.js + Neon Stack
3
3
  #
4
- # Ports come from variables with sane defaults so `morph-spec e2e up` can hand
5
- # each feature worktree its own port block (see env-allocator.js). Hardcode
6
- # "3000:3000" here and two features running side by side collide on the host,
7
- # no matter what the harness injects — the container names would be distinct
8
- # and the ports would not.
4
+ # One compose project per worktree. The harness sets
5
+ # COMPOSE_PROJECT_NAME=morph-{feature}, which prefixes every container, network
6
+ # and volume — so two features running side by side never share a resource.
7
+ # Explicit `container_name:` entries are NOT prefixed, which is why this file
8
+ # declares none: a named container is a collision waiting for the second
9
+ # worktree.
9
10
  #
10
- # Healthchecks are what make `up --wait` meaningful: without them Compose
11
- # reports "started" the moment the process launches, and the e2e node would
12
- # navigate an application that is not serving yet.
11
+ # Host ports come from the feature's port block (see env-allocator.js):
12
+ # PORT block + 0 (web)
13
+ # API_PORT block + 1 (api)
14
+ # POSTGRES_PORT block + 2 (postgres)
15
+ # REDIS_PORT block + 3 (redis)
16
+ # Every published port reads one of those variables with a single-stack
17
+ # default. A fixed host port here would defeat the block no matter what the
18
+ # harness injects — `morph-spec e2e up` and the verify e2e node refuse such a
19
+ # compose inside a worktree (`compose-not-isolable`).
13
20
  #
14
- # The harness also exports PLAYWRIGHT_BASE_URL for the same allocated port, so
21
+ # Named volumes are reclaimed by `morph-spec finish` when the feature closes
22
+ # (`--keep-volumes` opts out). Healthchecks are what make `up --wait`
23
+ # meaningful: without them Compose reports "started" the moment the process
24
+ # launches, and the e2e node would navigate an application not serving yet.
25
+ #
26
+ # The harness also exports PLAYWRIGHT_BASE_URL for the allocated port, so
15
27
  # `playwright.config.ts` must read it instead of hardcoding a URL:
16
28
  # baseURL: process.env.PLAYWRIGHT_BASE_URL ?? `http://localhost:${process.env.PORT ?? 3000}`
17
29
 
@@ -21,12 +33,11 @@ services:
21
33
  build:
22
34
  context: .
23
35
  dockerfile: Dockerfile.dev
24
- container_name: {{kebabCase FEATURE_NAME}}-app
25
36
  ports:
26
37
  - "${PORT:-3000}:3000"
27
38
  environment:
28
39
  - NODE_ENV=development
29
- - DATABASE_URL=${DATABASE_URL}
40
+ - DATABASE_URL=${DATABASE_URL:-postgresql://postgres:postgres@postgres:5432/${POSTGRES_DB:-app}}
30
41
  volumes:
31
42
  - .:/app
32
43
  - /app/node_modules
@@ -46,19 +57,18 @@ services:
46
57
  # PostgreSQL Database (Local development)
47
58
  postgres:
48
59
  image: postgres:15-alpine
49
- container_name: {{kebabCase FEATURE_NAME}}-postgres
50
60
  restart: unless-stopped
51
61
  ports:
52
62
  - "${POSTGRES_PORT:-5432}:5432"
53
63
  environment:
54
64
  POSTGRES_USER: postgres
55
65
  POSTGRES_PASSWORD: postgres
56
- POSTGRES_DB: {{snakeCase FEATURE_NAME}}
66
+ POSTGRES_DB: ${POSTGRES_DB:-app}
57
67
  volumes:
58
68
  - postgres-data:/var/lib/postgresql/data
59
69
  - ./migrations:/docker-entrypoint-initdb.d
60
70
  healthcheck:
61
- test: ["CMD-SHELL", "pg_isready -U postgres -d {{snakeCase FEATURE_NAME}}"]
71
+ test: ["CMD-SHELL", "pg_isready -U postgres -d ${POSTGRES_DB:-app}"]
62
72
  interval: 5s
63
73
  timeout: 5s
64
74
  retries: 10
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polymorphism-tech/morph-spec",
3
- "version": "8.33.0",
3
+ "version": "8.35.0",
4
4
  "description": "MORPH-SPEC: NLH (Natural Language Harness) for spec-driven development with Claude Code",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -41,8 +41,8 @@
41
41
  },
42
42
  "scripts": {
43
43
  "start": "node bin/morph-spec.js",
44
- "generate": "node scripts/generate-refs.js",
45
- "generate:check": "node scripts/generate-refs.js --check",
44
+ "generate": "node scripts/generate-refs.js && node scripts/generate-ai-pin-props.js && node scripts/api-probe/probe.mjs --generate",
45
+ "generate:check": "node scripts/generate-refs.js --check && node scripts/generate-ai-pin-props.js --check && node scripts/api-probe/probe.mjs --check",
46
46
  "generate-standards": "node scripts/generate-standards-registry.js",
47
47
  "generate-standards:check": "node scripts/generate-standards-registry.js --check",
48
48
  "validate": "node scripts/validate-framework.js && node scripts/check-rubric-parity.js",
@@ -7,6 +7,11 @@
7
7
  * running still matches the working tree, and `down` releases it — which
8
8
  * `morph-spec finish` also does as part of teardown.
9
9
  *
10
+ * Every subcommand acts in the TREE THAT OWNS THE FEATURE: run from the
11
+ * primary root for a feature that lives in a worktree, the compose file, the
12
+ * bind mount and the stamp are all the worktree's — the root's copy is a
13
+ * different checkout of different code.
14
+ *
10
15
  * All the real logic lives in framework/hooks/shared/e2e-check.js, shared with
11
16
  * the `verify` e2e node so the two can never drift.
12
17
  *
@@ -22,16 +27,21 @@ import {
22
27
  bringUpStack,
23
28
  composeProjectName,
24
29
  computeSourceStamp,
30
+ decideIsolation,
25
31
  defaultExec,
32
+ deleteStamp,
26
33
  getStackStatus,
27
34
  isDockerAvailable,
35
+ lintComposeIsolation,
28
36
  prepareAuth,
29
37
  readStamp,
30
38
  resolveComposeFile,
31
39
  resolveSpecCommand,
32
40
  tearDownStack,
33
41
  } from '../../../framework/hooks/shared/e2e-check.js';
42
+ import { isSecondaryWorktree } from '../../../framework/hooks/shared/git-paths.js';
34
43
  import { buildComposeEnv } from '../../lib/e2e/compose-env.js';
44
+ import { findWorktreeForFeature, resolvePrimaryRoot } from '../project/worktree.js';
35
45
 
36
46
  /** Exit code for a usage error, matching `verify`'s convention. */
37
47
  const EXIT_USAGE = 2;
@@ -41,20 +51,26 @@ const EXIT_USAGE = 2;
41
51
  // ============================================================================
42
52
 
43
53
  /**
44
- * Everything the three subcommands need, resolved once.
45
- * Returns null (after printing) when the project has no compose file — that is
46
- * a usage error here, unlike in the verify node where it is a graded skip.
54
+ * Everything the three subcommands need, resolved once — against the tree
55
+ * that owns the feature (its live worktree when it has one, the root
56
+ * otherwise).
57
+ *
58
+ * Returns null (after printing) when that tree has no compose file — a usage
59
+ * error here, unlike in the verify node where it is a graded skip.
47
60
  */
48
61
  function resolveContext(featureName, { json = false } = {}) {
49
- const cwd = process.cwd();
50
- const config = readConfig(cwd);
62
+ const root = resolvePrimaryRoot(process.cwd());
63
+ const found = findWorktreeForFeature(featureName, root);
64
+ const cwd = found?.path ?? root;
65
+
66
+ const config = readConfig(cwd) ?? readConfig(root);
51
67
  const composeFile = resolveComposeFile(cwd, config);
52
68
 
53
69
  if (!composeFile) {
54
70
  const message =
55
- 'No compose file found (compose.yaml, docker-compose.yml, …). ' +
71
+ `No compose file found in ${cwd} (compose.yaml, docker-compose.yml, …). ` +
56
72
  'Set project.e2e.composeFile in .morph/config/config.json if it lives elsewhere.';
57
- if (json) console.log(JSON.stringify({ error: message }, null, 2));
73
+ if (json) console.log(JSON.stringify({ error: message, tree: cwd }, null, 2));
58
74
  else console.error(chalk.red(`\n❌ ${message}\n`));
59
75
  return null;
60
76
  }
@@ -64,6 +80,9 @@ function resolveContext(featureName, { json = false } = {}) {
64
80
 
65
81
  return {
66
82
  cwd,
83
+ root,
84
+ tree: cwd,
85
+ insideWorktree: isSecondaryWorktree(cwd),
67
86
  config,
68
87
  composeFile,
69
88
  projectName,
@@ -79,39 +98,17 @@ function resolveContext(featureName, { json = false } = {}) {
79
98
  * The port block comes from `buildComposeEnv` rather than being assembled here
80
99
  * so this command and the `e2e` node inside `verify` agree by construction —
81
100
  * isolation that exists only in the command nobody runs is no isolation at all.
82
- * `COMPOSE_PROJECT_NAME` isolates container NAMES but not host ports; a compose
83
- * that hardcodes ports instead of reading `${PORT:-3000}` cannot be isolated at
84
- * all, which is surfaced as a warning rather than silently accepted.
85
101
  */
86
102
  function buildEnv({ cwd, config, featureName, projectName, gitCommonDir }) {
103
+ // COMPOSE_PROJECT_NAME is part of the port layout now; the explicit key stays
104
+ // as the fail-open floor for a repo with no git common dir (no block → no
105
+ // layout), where the project name is still what isolates the containers.
87
106
  return {
88
107
  COMPOSE_PROJECT_NAME: projectName,
89
108
  ...buildComposeEnv({ cwd, config, featureName, gitCommonDir }),
90
109
  };
91
110
  }
92
111
 
93
- /**
94
- * Warn once when the compose file publishes fixed host ports: with a hardcoded
95
- * `"3000:3000"` the fleet port block cannot take effect, so two features
96
- * running simultaneously will collide no matter what we inject.
97
- */
98
- function warnOnFixedPorts(cwd, composeFile) {
99
- try {
100
- const raw = readFileSync(join(cwd, composeFile), 'utf8');
101
- const publishesFixed = /^\s*-\s*["']?\d+:\d+["']?\s*$/m.test(raw);
102
- if (publishesFixed) {
103
- console.log(
104
- chalk.yellow(
105
- '⚠️ Compose publishes fixed host ports. Parallel worktrees will collide — ' +
106
- 'use ${PORT:-3000}:3000 so the fleet port block applies.'
107
- )
108
- );
109
- }
110
- } catch {
111
- // Unreadable compose is the caller's problem, not this warning's.
112
- }
113
- }
114
-
115
112
  // ============================================================================
116
113
  // up
117
114
  // ============================================================================
@@ -119,20 +116,48 @@ function warnOnFixedPorts(cwd, composeFile) {
119
116
  /**
120
117
  * `morph-spec e2e up <feature> [--fresh]`
121
118
  *
122
- * Exit codes: 0 = stack healthy · 1 = failed to come up (or auth broke) ·
123
- * 2 = usage (no compose file / no docker).
119
+ * `--fresh` is destructive on purpose: it tears the previous stack down WITH
120
+ * its named volumes and forces the auth seed to run again. A rebuild that
121
+ * preserved the database would hand the next suite the previous run's rows,
122
+ * and a storageState captured against that database would keep authenticating
123
+ * a user that no longer exists.
124
+ *
125
+ * Exit codes: 0 = stack healthy · 1 = failed to come up (or auth broke, or the
126
+ * compose cannot be isolated inside a worktree) · 2 = usage (no compose file /
127
+ * no docker).
124
128
  */
125
129
  export async function e2eUpCommand(featureName, options = {}) {
126
130
  const ctx = resolveContext(featureName, options);
127
131
  if (!ctx) process.exit(EXIT_USAGE);
128
132
 
133
+ // Isolation BEFORE the docker check: `COMPOSE_PROJECT_NAME` isolates
134
+ // container names but not host ports, and a compose that hardcodes them (or
135
+ // names its containers) collides with the sibling worktree no matter what we
136
+ // inject. Same rule as the verify node — see decideIsolation().
137
+ const lint = lintComposeIsolation(readComposeText(ctx.cwd, ctx.composeFile));
138
+ const isolation = decideIsolation({ findings: lint.findings, insideWorktree: ctx.insideWorktree });
139
+ if (isolation.status === 'fail') {
140
+ if (options.json) {
141
+ console.log(JSON.stringify(
142
+ { error: 'compose-not-isolable', feature: featureName, tree: ctx.tree, composeFile: ctx.composeFile, reason: isolation.reason, findings: lint.findings },
143
+ null, 2,
144
+ ));
145
+ } else {
146
+ console.error(chalk.red(`\n❌ ${isolation.reason}`));
147
+ for (const f of lint.findings) console.error(chalk.gray(` ${ctx.composeFile}:${f.line}: ${f.text}`));
148
+ console.error('');
149
+ }
150
+ process.exit(1);
151
+ }
152
+ if (isolation.status === 'warn' && !options.json) {
153
+ console.log(chalk.yellow(`⚠️ ${isolation.reason}`));
154
+ }
155
+
129
156
  if (!isDockerAvailable(ctx.cwd)) {
130
157
  console.error(chalk.red('\n❌ Docker is not available in this environment.\n'));
131
158
  process.exit(EXIT_USAGE);
132
159
  }
133
160
 
134
- if (!options.json) warnOnFixedPorts(ctx.cwd, ctx.composeFile);
135
-
136
161
  const result = bringUpStack(ctx.cwd, {
137
162
  composeFile: ctx.composeFile,
138
163
  projectName: ctx.projectName,
@@ -143,18 +168,26 @@ export async function e2eUpCommand(featureName, options = {}) {
143
168
 
144
169
  const auth =
145
170
  result.status === 'pass'
146
- ? prepareAuth(ctx.cwd, { config: ctx.config, env: ctx.env })
171
+ ? prepareAuth(ctx.cwd, { config: ctx.config, env: ctx.env, forceSeed: Boolean(options.fresh) })
147
172
  : { status: 'skip', reason: null };
148
173
 
174
+ // Same warnings[] contract as the verify e2e node: a seedCommand that never
175
+ // runs because `mode` switches it off is reported, never swallowed.
176
+ const warnings = [];
177
+ if (isolation.status === 'warn') warnings.push(isolation.reason);
178
+ if (auth.warning) warnings.push(auth.warning);
179
+
149
180
  const failed = result.status === 'fail' || auth.status === 'fail';
150
181
  const payload = {
151
182
  feature: featureName,
152
183
  project: ctx.projectName,
184
+ tree: ctx.tree,
153
185
  composeFile: ctx.composeFile,
154
186
  status: failed ? 'fail' : 'pass',
155
187
  reused: result.reused,
156
188
  reason: result.reason,
157
189
  auth: { status: auth.status, reason: auth.reason },
190
+ ...(warnings.length ? { warnings } : {}),
158
191
  };
159
192
 
160
193
  if (options.json) {
@@ -165,7 +198,9 @@ export async function e2eUpCommand(featureName, options = {}) {
165
198
  } else {
166
199
  const how = result.reused ? chalk.gray(`(${result.reason})`) : chalk.gray('(built)');
167
200
  console.log(chalk.green(`\n✓ Stack up — ${ctx.projectName} ${how}`));
201
+ console.log(chalk.gray(` tree: ${ctx.tree}`));
168
202
  if (auth.reason) console.log(chalk.gray(` auth: ${auth.reason}`));
203
+ if (auth.warning) console.log(chalk.yellow(`⚠️ ${auth.warning}`));
169
204
  console.log('');
170
205
  }
171
206
 
@@ -217,6 +252,7 @@ export async function e2eStatusCommand(featureName, options = {}) {
217
252
  const payload = {
218
253
  feature: featureName,
219
254
  project: ctx.projectName,
255
+ tree: ctx.tree,
220
256
  composeFile: ctx.composeFile,
221
257
  up: status.up,
222
258
  healthy: status.healthy,
@@ -236,6 +272,7 @@ export async function e2eStatusCommand(featureName, options = {}) {
236
272
  } else {
237
273
  console.log('');
238
274
  console.log(chalk.bold(`E2E stack — ${ctx.projectName}`));
275
+ console.log(chalk.gray(`tree: ${ctx.tree}`));
239
276
  console.log(chalk.gray(`compose: ${ctx.composeFile}`));
240
277
  console.log(chalk.gray(`url: ${payload.baseUrl}`));
241
278
  console.log('');
@@ -262,7 +299,8 @@ export async function e2eStatusCommand(featureName, options = {}) {
262
299
  * `morph-spec e2e down <feature> [--volumes]`
263
300
  *
264
301
  * Teardown is best-effort by design — a stack that will not come down must
265
- * never block `finish`.
302
+ * never block `finish`. The freshness stamp goes regardless: a stamp that
303
+ * outlives its containers would let the next `up` reuse a stack that is gone.
266
304
  */
267
305
  export async function e2eDownCommand(featureName, options = {}) {
268
306
  const ctx = resolveContext(featureName, options);
@@ -274,11 +312,16 @@ export async function e2eDownCommand(featureName, options = {}) {
274
312
  env: ctx.env,
275
313
  volumes: Boolean(options.volumes),
276
314
  });
315
+ const stampDeleted = deleteStamp(ctx.gitCommonDir, ctx.projectName);
277
316
 
278
317
  if (options.json) {
279
- console.log(JSON.stringify({ feature: featureName, project: ctx.projectName, status: result.status }, null, 2));
318
+ console.log(JSON.stringify(
319
+ { feature: featureName, project: ctx.projectName, tree: ctx.tree, status: result.status, stampDeleted },
320
+ null, 2,
321
+ ));
280
322
  } else if (result.status === 'pass') {
281
- console.log(chalk.green(`\n✓ Stack down — ${ctx.projectName}\n`));
323
+ console.log(chalk.green(`\n✓ Stack down — ${ctx.projectName}`));
324
+ console.log(chalk.gray(` tree: ${ctx.tree}\n`));
282
325
  } else {
283
326
  console.log(chalk.yellow(`\n⚠️ Teardown reported a problem (not fatal):\n${result.output}\n`));
284
327
  }
@@ -300,6 +343,14 @@ function readConfig(cwd) {
300
343
  }
301
344
  }
302
345
 
346
+ function readComposeText(cwd, composeFile) {
347
+ try {
348
+ return readFileSync(join(cwd, composeFile), 'utf8');
349
+ } catch {
350
+ return '';
351
+ }
352
+ }
353
+
303
354
  /** Same resolution (and same fail-open) as verify-runner's. */
304
355
  function resolveGitCommonDir(cwd) {
305
356
  try {