@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
@@ -19,6 +19,7 @@ import { checkMissingAgents, checkAgentsDrift } from '../../utils/agents-install
19
19
  import { getProjectTags } from '../../lib/stack-filter.js';
20
20
  import { auditGraph } from '../../lib/graph/graph-health.js';
21
21
  import { auditFeatureLifecycle } from '../../core/state/lifecycle-audit.js';
22
+ import { validateTestNodes, morphConfigPath } from '../../lib/tasks/test-nodes.js';
22
23
 
23
24
  const isWindows = platform() === 'win32';
24
25
  /**
@@ -367,6 +368,43 @@ async function doctorFullCommand(frameworkRoot) {
367
368
  check('state.json', false, true, 'not found (run: morph-spec init)');
368
369
  }
369
370
 
371
+ // ── 8. project.tests[] — o contrato do config, camada 3 ─────────────────
372
+ //
373
+ // As outras duas camadas são o `config.schema.json` (declarativa) e
374
+ // `validateTestNodes()` chamada pelo `verify` (fail-closed, em uso). Esta
375
+ // aqui existe para o defeito chegar ANTES do gate: um `id` com typo em
376
+ // `tests[]` só se manifesta quando alguém roda `morph-spec verify` e lê um
377
+ // nó vermelho — o doctor o mostra na checagem de saúde, que é onde se olha
378
+ // primeiro. Reusa `validateTestNodes` (a MESMA autoridade que o verify
379
+ // consulta): uma segunda leitura do mesmo campo aqui seria uma segunda
380
+ // opinião sobre o que é um nó válido, e as duas divergiriam.
381
+ //
382
+ // PULA de verdade — sem check e sem cabeçalho — quando não há `config.json`
383
+ // ou quando `project.tests` não foi declarado. Um projeto sem declaração usa
384
+ // o fallback de quatro passos e não tem contrato a violar; este repositório
385
+ // é exatamente esse caso, e um check que não pode passar aqui é ruído, não
386
+ // achado (`test/commands/doctor.test.js`: `doctor --full` sem nenhum `✗`).
387
+ // WARN e nunca ERROR: a barreira fail-closed é o `verify`; o doctor informa.
388
+ const testsConfigPath = morphConfigPath(frameworkRoot);
389
+ if (await pathExists(testsConfigPath)) {
390
+ let testsConfig = null;
391
+ try {
392
+ testsConfig = JSON.parse((await fs.readFile(testsConfigPath, 'utf8')).replace(/^\uFEFF/, ''));
393
+ } catch {
394
+ testsConfig = null; // config ilegível já é reportado pelo doctor base
395
+ }
396
+ if (testsConfig?.project?.tests !== undefined) {
397
+ console.log(chalk.cyan('\n .morph/config/config.json — project.tests[]'));
398
+ const declared = validateTestNodes(testsConfig, frameworkRoot);
399
+ const broken = declared.filter((n) => n.status === 'fail');
400
+ check(`config tests[] (${declared.length - broken.length}/${declared.length})`,
401
+ broken.length === 0, true,
402
+ broken.length > 0
403
+ ? broken.map((n) => n.reason ?? `invalid-test-node: ${n.id}`).join('; ')
404
+ : '');
405
+ }
406
+ }
407
+
370
408
  // ── Display ──────────────────────────────────────────────────────────────
371
409
  console.log('\n' + '─'.repeat(60));
372
410
  console.log(chalk.bold('\nResults:\n'));
@@ -586,11 +624,14 @@ export async function doctorWorktreesCommand(targetPath, options = {}) {
586
624
  }
587
625
 
588
626
  const issues = auditWorktrees(targetPath);
589
- // `severity: 'info'` entries (a worktree carrying unintegrated work) are
590
- // REPORTED but are not failures — a `doctor --worktrees || ...` in CI must not
591
- // go red because somebody has an open PR. The human path below splits the same
592
- // way; both surfaces must agree on what counts as broken.
593
- const isProblem = (i) => i.severity !== 'info';
627
+ // `severity: 'info'` entries (a worktree carrying unintegrated work) and
628
+ // `severity: 'warn'` entries (a worktree created outside morph's container,
629
+ // and the docker findings from `docker-audit.js`: an orphan stack, a port
630
+ // held by another compose project) are REPORTED but are not failures — a
631
+ // `doctor --worktrees || ...` in CI must not go red because somebody has an
632
+ // open PR, a hand-made tree, or a container still up. The human path below
633
+ // splits the same way; both surfaces must agree on what counts as broken.
634
+ const isProblem = (i) => !['info', 'warn'].includes(i.severity);
594
635
 
595
636
  if (options.json) {
596
637
  console.log(JSON.stringify({ issues }, null, 2));
@@ -617,7 +658,7 @@ export async function doctorWorktreesCommand(targetPath, options = {}) {
617
658
  console.log(` → ${i.fix}`);
618
659
  }
619
660
  for (const i of informational) {
620
- console.log(` ℹ ${i.type}`);
661
+ console.log(i.severity === 'warn' ? chalk.yellow(` ⚠ ${i.type}`) : ` ℹ ${i.type}`);
621
662
  console.log(` ${i.detail}`);
622
663
  console.log(` → ${i.fix}`);
623
664
  }
@@ -687,6 +728,86 @@ function auditPullRequests(root) {
687
728
  return issues;
688
729
  }
689
730
 
731
+ /**
732
+ * `morph-spec doctor --ai` — as cinco checagens de projeto .NET com agentes.
733
+ *
734
+ * **Superfície própria, no molde do `--mcp`, e é decisão, não acidente.** O
735
+ * `--ai` NÃO entra no `--full` nem no `doctor` default:
736
+ *
737
+ * - o renderer do `--full` é `ok → ✓`, `warn → ⚠`, **`else → ✗`** — não tem o
738
+ * ramo `skip → ○`. Uma checagem de IA lá seria VERMELHA neste repositório
739
+ * mesmo dizendo "não verificado", e `test/commands/doctor.test.js` exige
740
+ * `doesNotMatch(out, /✗/)` para `doctor --full` aqui, com a justificativa
741
+ * escrita no próprio teste: *"every check must be satisfiable here — a
742
+ * permanently red one teaches nothing"*;
743
+ * - o `doctor` default é o comando mais rodado do dia, e cinco linhas `○`
744
+ * permanentes em todo projeto sem .NET é ruído com custo e sem informação.
745
+ *
746
+ * Exit code: 1 se houver ao menos um `error`; 0 caso contrário. `warn` e `skip`
747
+ * nunca mudam o código de saída.
748
+ *
749
+ * @param {string} targetPath
750
+ * @param {object} [options] - repassado a `collectAiChecks` (`config`, `deps`)
751
+ * @returns {Promise<Array>} as checagens, para o canário assere-las sem parsear texto
752
+ */
753
+ export async function doctorAiCommand(targetPath, options = {}) {
754
+ const { collectAiChecks, aiExitCode, allSkipped } = await import('../../lib/ai/ai-checks.js');
755
+ const { readMorphConfig } = await import('../../lib/tasks/test-runner.js');
756
+
757
+ logger.header('AI Health Check (.NET + agentes)');
758
+ logger.blank();
759
+
760
+ const config = options.config !== undefined ? options.config : readMorphConfig(targetPath);
761
+ const checks = collectAiChecks(targetPath, { config, deps: options.deps ?? {} });
762
+
763
+ if (allSkipped(checks)) {
764
+ // Condição 4 do silêncio: nenhuma checagem teve insumo. Uma linha, não
765
+ // cinco `○` vazios — listar cinco vezes "não verificado" é o ruído que
766
+ // esta superfície existe para não produzir.
767
+ const reasons = [...new Set(checks.map((c) => c.reason))];
768
+ for (const reason of reasons) {
769
+ console.log(chalk.gray(` ○ Nenhuma das ${checks.length} checagens teve insumo — ${reason}.`));
770
+ }
771
+ logger.blank();
772
+ process.exitCode = 0;
773
+ return checks;
774
+ }
775
+
776
+ for (const c of checks) {
777
+ if (c.status === 'ok') {
778
+ console.log(chalk.green(` ✓ ${c.name}`));
779
+ } else if (c.status === 'skip') {
780
+ console.log(chalk.gray(` ○ ${c.name}`) + chalk.gray(` — não verificado: ${c.reason}`));
781
+ } else if (c.status === 'warn') {
782
+ console.log(chalk.yellow(` ⚠ ${c.name}`));
783
+ } else {
784
+ console.log(chalk.red(` ✗ ${c.name}`));
785
+ }
786
+ for (const f of c.findings) {
787
+ const mark = f.severity === 'error' ? chalk.red(' ✗') : chalk.yellow(' →');
788
+ console.log(`${mark} ${chalk.gray(f.message)}`);
789
+ }
790
+ for (const file of c.unverified ?? []) {
791
+ console.log(chalk.gray(` ○ não verificado: ${relative(targetPath, file) || file} (ilegível)`));
792
+ }
793
+ }
794
+
795
+ logger.blank();
796
+ const errors = checks.filter((c) => c.status === 'error').length;
797
+ const warns = checks.filter((c) => c.status === 'warn').length;
798
+ const skips = checks.filter((c) => c.status === 'skip').length;
799
+ const oks = checks.filter((c) => c.status === 'ok').length;
800
+
801
+ const summary = `${oks} ok · ${warns} aviso(s) · ${errors} erro(s) · ${skips} não verificada(s)`;
802
+ if (errors > 0) console.log(chalk.red(` ❌ ${summary}`));
803
+ else if (warns > 0) console.log(chalk.yellow(` ⚠️ ${summary}`));
804
+ else console.log(chalk.green(` ✅ ${summary}`));
805
+ logger.blank();
806
+
807
+ process.exitCode = aiExitCode(checks);
808
+ return checks;
809
+ }
810
+
690
811
  export async function doctorCommand(options = {}) {
691
812
  // `--json` and `--prune` only mean something under `--worktrees`. Falling
692
813
  // through to the human health check would hand a script a banner and a table
@@ -701,6 +822,22 @@ export async function doctorCommand(options = {}) {
701
822
  return false;
702
823
  }
703
824
 
825
+ // `--ai` é superfície própria (D1). Combiná-la com outra superfície pediria
826
+ // dois relatórios com dois códigos de saída no mesmo processo — o segundo
827
+ // apagaria o primeiro em silêncio. Mesmo molde da guarda acima: recusa em
828
+ // vez de fingir.
829
+ if (options.ai) {
830
+ const conflicts = ['full', 'mcp', 'worktrees'].filter((f) => options[f]);
831
+ if (conflicts.length) {
832
+ const flags = conflicts.map((f) => `--${f}`).join(' e ');
833
+ logger.error(`--ai não se combina com ${flags} — cada superfície tem o seu relatório e o seu código de saída.`);
834
+ logger.dim(' Rode: morph-spec doctor --ai');
835
+ process.exitCode = 1;
836
+ return false;
837
+ }
838
+ return doctorAiCommand(process.cwd(), options);
839
+ }
840
+
704
841
  // Reset mode: remove morph-managed settings entries
705
842
  if (options.reset) {
706
843
  const targetPath = process.cwd();
@@ -0,0 +1,95 @@
1
+ /**
2
+ * `morph-spec env [feature] [--json|--posix|--powershell]` — print the
3
+ * dedicated environment of a worktree (port block + compose project) in a
4
+ * shell-loadable form.
5
+ *
6
+ * Inside Claude Code the `worktree-env-inject` hook applies this block to
7
+ * every dev-server / compose launcher automatically. This command is the same
8
+ * contract for everything OUTSIDE the harness: a human terminal
9
+ * (`eval "$(morph-spec env)"`), a CI step, a sub-agent running without hooks.
10
+ * It derives from `buildComposeEnv` — the function the `verify` e2e node and
11
+ * `e2e up` already use — so a shell and the stack can never disagree.
12
+ *
13
+ * Feature resolution: explicit argument, else the `morph/{f}` (or
14
+ * `morph-task/{n}`) branch of the cwd. Read-only: allocation is idempotent and
15
+ * never moves an existing block.
16
+ */
17
+
18
+ import { execFileSync } from 'child_process';
19
+ import { readFileSync } from 'fs';
20
+ import { join, resolve } from 'path';
21
+ import chalk from 'chalk';
22
+ import { buildComposeEnv } from '../../lib/e2e/compose-env.js';
23
+ import { resolvePrimaryRoot } from './worktree.js';
24
+ import { currentBranch } from '../../lib/worktree/feature-truth.js';
25
+
26
+ /** `morph/<f>` → `<f>`; `morph-task/<n>` → `task/<n>`; anything else → null. */
27
+ export function envKeyFromBranch(branch) {
28
+ if (!branch) return null;
29
+ const feature = branch.match(/^morph\/(.+)$/)?.[1];
30
+ if (feature) return feature;
31
+ const task = branch.match(/^morph-task\/(.+)$/)?.[1];
32
+ return task ? `task/${task}` : null;
33
+ }
34
+
35
+ function readConfig(root) {
36
+ try {
37
+ return JSON.parse(readFileSync(join(root, '.morph', 'config', 'config.json'), 'utf8').replace(/^/, ''));
38
+ } catch {
39
+ return null;
40
+ }
41
+ }
42
+
43
+ function gitCommonDir(cwd) {
44
+ try {
45
+ const out = execFileSync('git', ['rev-parse', '--git-common-dir'], { cwd, stdio: 'pipe' }).toString().trim();
46
+ return out ? resolve(cwd, out) : null;
47
+ } catch {
48
+ return null;
49
+ }
50
+ }
51
+
52
+ /** POSIX single-quote. */
53
+ const shq = (v) => `'${String(v).replace(/'/g, "'\\''")}'`;
54
+
55
+ /**
56
+ * Pure: the env map for a key, or `{ error }`.
57
+ * @param {string|null} featureArg
58
+ * @param {string} cwd
59
+ */
60
+ export function resolveWorktreeEnv(featureArg, cwd = process.cwd()) {
61
+ const key = featureArg || envKeyFromBranch(currentBranch(cwd));
62
+ if (!key) {
63
+ return { error: 'no-feature', message: 'Nenhuma feature: passe o nome ou rode de uma branch morph/{f} / morph-task/{n}.' };
64
+ }
65
+ const common = gitCommonDir(cwd);
66
+ if (!common) {
67
+ return { error: 'not-a-git-repo', message: 'Fora de um repositório git não há bloco de portas.' };
68
+ }
69
+ const root = resolvePrimaryRoot(cwd);
70
+ const env = buildComposeEnv({ cwd: root, config: readConfig(root), featureName: key, gitCommonDir: common });
71
+ return { key, env };
72
+ }
73
+
74
+ export function render(env, format) {
75
+ const entries = Object.entries(env);
76
+ if (format === 'json') return JSON.stringify(env, null, 2);
77
+ if (format === 'powershell') return entries.map(([k, v]) => `$env:${k}="${String(v).replace(/"/g, '`"')}"`).join('\n');
78
+ return entries.map(([k, v]) => `export ${k}=${shq(v)}`).join('\n');
79
+ }
80
+
81
+ /**
82
+ * @param {string|undefined} featureArg
83
+ * @param {{ json?: boolean, posix?: boolean, powershell?: boolean }} options
84
+ */
85
+ export function envCommand(featureArg, options = {}) {
86
+ const result = resolveWorktreeEnv(featureArg || null, process.cwd());
87
+ if (result.error) {
88
+ if (options.json) console.log(JSON.stringify({ error: result.error, message: result.message }));
89
+ else console.error(chalk.red(`✗ ${result.message}`));
90
+ process.exit(1);
91
+ }
92
+ const format = options.json ? 'json' : options.powershell ? 'powershell' : 'posix';
93
+ console.log(render(result.env, format));
94
+ process.exit(0);
95
+ }