@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.
- package/CLAUDE.md +22 -5
- package/README.md +2 -2
- package/bin/morph-spec.js +18 -4
- package/bin/validate.js +379 -379
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +5 -4
- package/docs/QUICKSTART.md +1 -1
- package/framework/MORPH.md +16 -17
- package/framework/agents.json +197 -44
- package/framework/ai-pin.json +22 -0
- package/framework/commands/morph-media.md +45 -0
- package/framework/docs/CLI.md +236 -11
- package/framework/evals/proof-rubrics/README.md +76 -0
- package/framework/evals/proof-rubrics/eval-de-modelo.md +64 -0
- package/framework/evals/proof-rubrics/fiacao.md +54 -0
- package/framework/evals/proof-rubrics/guard-cego.md +52 -0
- package/framework/evals/proof-rubrics/media-claims.md +109 -0
- package/framework/evals/proof-rubrics/mutation-proof.md +77 -0
- package/framework/evals/proof-rubrics/observabilidade-genai.md +119 -0
- package/framework/evals/proof-rubrics/verde-nao-e-coberto.md +48 -0
- package/framework/evals/rubrics/architecture.md +30 -0
- package/framework/evals/rubrics/code-quality.md +26 -0
- package/framework/evals/rubrics/test-coverage.md +20 -0
- package/framework/hooks/claude-code/core/protect-spec-files.js +41 -4
- package/framework/hooks/claude-code/core/worktree-env-inject.js +43 -0
- package/framework/hooks/claude-code/statusline.sh +11 -11
- package/framework/hooks/git/commit-msg/conventional-commits.sh +33 -33
- package/framework/hooks/git/pre-commit/agents.sh +25 -25
- package/framework/hooks/git/pre-commit/orchestrator.sh +64 -64
- package/framework/hooks/git/pre-commit/specs.sh +50 -50
- package/framework/hooks/git/pre-push/run-tests.sh +44 -44
- package/framework/hooks/shared/e2e-check.js +135 -22
- package/framework/hooks/shared/payload-utils.js +15 -2
- package/framework/hooks/shared/stdin-reader.js +26 -26
- package/framework/rules/ai-agents-standards.md +14 -2
- package/framework/schemas/ai-pin.schema.json +97 -0
- package/framework/schemas/config.schema.json +107 -0
- package/framework/schemas/feature.schema.json +23 -4
- package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
- package/framework/skills/core/morph-apply/SKILL.md +26 -5
- package/framework/skills/core/morph-brainstorming/SKILL.md +1 -1
- package/framework/skills/core/morph-eval/SKILL.md +1 -1
- package/framework/skills/core/morph-hotfix/SKILL.md +2 -2
- package/framework/skills/core/morph-implement/SKILL.md +18 -2
- package/framework/skills/core/morph-media/SKILL.md +215 -0
- package/framework/skills/core/morph-plan/SKILL.md +33 -2
- package/framework/skills/core/morph-proposal/SKILL.md +1 -1
- package/framework/skills/core/morph-review/SKILL.md +166 -9
- package/framework/skills/core/morph-stack-scan/SKILL.md +1 -1
- package/framework/skills/core/morph-standards/SKILL.md +1 -1
- package/framework/skills/core/morph-uiux/SKILL.md +1 -1
- package/framework/standards/PROVENANCE.json +81 -3
- package/framework/standards/STANDARDS.json +1483 -839
- package/framework/standards/ai-agents/agent-archetypes.md +160 -0
- package/framework/standards/ai-agents/agent-session.md +164 -68
- package/framework/standards/ai-agents/agent-spec.md +196 -0
- package/framework/standards/ai-agents/batching.md +61 -37
- package/framework/standards/ai-agents/context-providers.md +97 -24
- package/framework/standards/ai-agents/conversational-agent-with-phases.md +239 -0
- package/framework/standards/ai-agents/cost-and-budget.md +256 -0
- package/framework/standards/ai-agents/durable-workflows-hitl.md +98 -5
- package/framework/standards/ai-agents/evals-with-cache.md +289 -0
- package/framework/standards/ai-agents/guardrails.md +222 -0
- package/framework/standards/ai-agents/llm-runtime-defaults.md +226 -0
- package/framework/standards/ai-agents/mcp-server.md +119 -18
- package/framework/standards/ai-agents/mcp-tools.md +85 -32
- package/framework/standards/ai-agents/media-pipeline.md +352 -0
- package/framework/standards/ai-agents/media-video.md +267 -0
- package/framework/standards/ai-agents/middleware-patterns.md +39 -5
- package/framework/standards/ai-agents/modalities-image-gen.md +354 -105
- package/framework/standards/ai-agents/modalities-speech-to-text.md +8 -2
- package/framework/standards/ai-agents/modalities-text-to-speech.md +10 -2
- package/framework/standards/ai-agents/modalities-vision.md +6 -2
- package/framework/standards/ai-agents/multi-agent-patterns.md +61 -5
- package/framework/standards/ai-agents/observability-patterns.md +227 -17
- package/framework/standards/ai-agents/production.md +38 -9
- package/framework/standards/ai-agents/prompt-sources.md +389 -0
- package/framework/standards/ai-agents/providers/model-registry.md +174 -39
- package/framework/standards/ai-agents/rag-custom-pgvector.md +69 -4
- package/framework/standards/ai-agents/service-tier-flex.md +27 -19
- package/framework/standards/ai-agents/setup.md +166 -50
- package/framework/standards/ai-agents/structured-output.md +34 -3
- package/framework/standards/ai-agents/sweet-spot.md +23 -3
- package/framework/standards/ai-agents/testing-ai.md +236 -0
- package/framework/standards/ai-agents/vector-data-extensions.md +50 -20
- package/framework/standards/ai-agents/workflows.md +27 -7
- package/framework/standards/frontend/design-system/ai-image-generation.md +12 -0
- package/framework/standards/frontend/design-system/ai-video-generation.md +13 -0
- package/framework/standards/infrastructure/docker/local-compose-isolation.md +3 -1
- package/framework/templates/.idea/morph-templates.xml +92 -0
- package/framework/templates/.vscode/morph-templates.code-snippets +186 -0
- package/framework/templates/IDE-SNIPPETS.md +262 -262
- package/framework/templates/REGISTRY.json +13 -0
- package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -7
- package/framework/templates/code/dotnet/ai-agents/AgentBootstrap.cs.template +39 -39
- package/framework/templates/code/dotnet/ai-agents/EmbeddingService.cs.template +68 -68
- package/framework/templates/code/dotnet/ai-agents/ModelRegistry.cs.template +117 -117
- package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +1 -1
- package/framework/templates/code/dotnet/ai-agents/ResilientToolMiddleware.cs.template +61 -61
- package/framework/templates/code/dotnet/ai-agents/VectorSearchTool.cs.template +107 -107
- package/framework/templates/code/dotnet/ai-agents/model-registry.json.template +58 -58
- package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +281 -281
- package/framework/templates/code/dotnet/database/migration.cs +83 -83
- package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +21 -21
- package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -4
- package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -4
- package/framework/templates/code/dotnet/feature/validator.cs.hbs +15 -15
- package/framework/templates/code/sql/ai-agents/agent-prompts-migration.sql.template +1 -1
- package/framework/templates/code/sql/ai-agents/pgvector-embeddings-migration.sql.template +91 -91
- package/framework/templates/code/typescript/contracts.ts +167 -167
- package/framework/templates/docs/clarifications.md +253 -253
- package/framework/templates/docs/schema-analysis.md +119 -119
- package/framework/templates/docs/ui-components.md +52 -52
- package/framework/templates/docs/ui-design-system.md +76 -76
- package/framework/templates/docs/ui-flows.md +167 -167
- package/framework/templates/docs/ui-mockups.md +98 -98
- package/framework/templates/dotnet/ai-kit/Directory.Build.props +25 -0
- package/framework/templates/dotnet/ai-kit/Directory.Packages.props +26 -0
- package/framework/templates/dotnet/ai-kit/Morph.AiKit.sln +56 -0
- package/framework/templates/dotnet/ai-kit/NuGet.config +12 -0
- package/framework/templates/dotnet/ai-kit/README.md +128 -0
- package/framework/templates/dotnet/ai-kit/global.json +9 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentApi.cs +65 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactory.cs +289 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactoryOptions.cs +91 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpec.cs +91 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpecOptions.cs +181 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/AiKitAssemblyMarker.cs +14 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/ConversationStore.cs +174 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/IConversationStore.cs +54 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/InMemoryConversationStore.cs +75 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/CountingChatClient.cs +71 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalAssertion.cs +246 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheMissException.cs +57 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheOptions.cs +78 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheStamp.cs +225 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalFixture.cs +463 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalMode.cs +32 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalQualityEvaluators.cs +49 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalScenario.cs +214 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalSummary.cs +168 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/OfflineChatClient.cs +142 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/ShortPathResponseCache.cs +349 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaGenerator.cs +42 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaProvider.cs +77 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaArtifact.cs +28 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaDisclosure.cs +107 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaGenerator.cs +253 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaIdempotencyKey.cs +103 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJob.cs +259 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobId.cs +21 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobState.cs +47 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaPricing.cs +102 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaProvenance.cs +44 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaRequest.cs +192 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaResult.cs +94 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaReview.cs +99 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaSeams.cs +97 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaStore.cs +133 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MorphMedia.cs +93 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/GoogleImageProvider.cs +112 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/OpenAIImageProvider.cs +288 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/VeoVideoProvider.cs +158 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/IUsageCostSink.cs +29 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostMiddleware.cs +208 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostRecord.cs +95 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Morph.AiKit.csproj +38 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphOpenTelemetryExtensions.cs +119 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphTelemetryOptions.cs +82 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/IProviderClientFactory.cs +33 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelAlias.cs +267 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelRegistry.cs +474 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/model-registry.v2.json +87 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs +169 -0
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaPlan.cs +49 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentFactoryTests.cs +495 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentSpecTests.cs +260 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ConversationStoreTests.cs +405 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/DeltaIngestTests.cs +379 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalAssertionTests.cs +197 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheMissTests.cs +139 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheStampTests.cs +157 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFailuresTests.cs +178 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFixtureTests.cs +153 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalRefreshTests.cs +194 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalWorkspace.cs +86 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/KitEvals.cs +213 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/OfflineChatClientTests.cs +95 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClient.cs +225 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClientTests.cs +215 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeClock.cs +33 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeMediaProvider.cs +89 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeProviderClientFactory.cs +55 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeUsageCostSink.cs +60 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/InMemoryMediaStore.cs +131 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAccessibilityTests.cs +133 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAliasIsNotAnAgentTests.cs +127 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +216 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaGeneratorTests.cs +264 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaIdempotencyKeyTests.cs +148 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaJobStateTests.cs +184 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaReviewTests.cs +89 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaStoreTests.cs +98 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ModelRegistryTests.cs +451 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Morph.AiKit.Tests.csproj +76 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/SkeletonSmokeTests.cs +33 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/TelemetryTests.cs +261 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/UsageCostMiddlewareTests.cs +374 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/.morph-eval-cache.json +12 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/orcamento.acme.a-resposta-estruturada/1/CF70A7CE27BBD66A/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.a-saudacao/1/19F631228C6E00BA/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.acme.b-escalonamento/1/A24A7C9BDD8239D8/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/contents.data +13 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-cache/cache/triagem.globex.a-saudacao/1/E38CD37DF003EDB7/entry.json +7 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/orcamento/acme/a-resposta-estruturada.json +24 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/a-saudacao.json +23 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/acme/b-escalonamento.json +24 -0
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/eval-datasets/triagem/globex/a-saudacao.json +23 -0
- package/framework/templates/feature/decisions.md +122 -122
- package/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +43 -43
- package/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -26
- package/framework/templates/frontend/nextjs/env.mjs.hbs +32 -32
- package/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -56
- package/framework/templates/frontend/nextjs/page.tsx.hbs +22 -22
- package/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -26
- package/framework/templates/frontend/nextjs/use-feature.ts.hbs +54 -54
- package/framework/templates/infrastructure/docker/Dockerfile.template +58 -58
- package/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -38
- package/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -48
- package/framework/templates/infrastructure/github/README.md +56 -56
- package/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -45
- package/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -27
- package/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -59
- package/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -39
- package/framework/templates/integrations/asaas-client.cs +387 -387
- package/framework/templates/integrations/asaas-webhook.cs +351 -351
- package/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -76
- package/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -100
- package/framework/templates/meta-prompts/validators/pre-commit-validator.md +95 -95
- package/framework/templates/project/validate.js +120 -120
- package/framework/templates/state.template.json +17 -17
- package/framework/templates/ui/design-system.css +226 -226
- package/package.json +3 -3
- package/src/commands/dashboard/dashboard.js +53 -53
- package/src/commands/e2e/e2e.js +15 -2
- package/src/commands/index.js +13 -13
- package/src/commands/project/checkpoint.js +209 -209
- package/src/commands/project/doctor.js +148 -6
- package/src/commands/project/update.js +469 -153
- package/src/commands/project/worktree.js +76 -4
- package/src/commands/state/advance.js +24 -2
- package/src/commands/state/approve.js +33 -1
- package/src/commands/state/create.js +72 -11
- package/src/commands/state/finish.js +379 -24
- package/src/commands/state/gate-check.js +190 -6
- package/src/commands/state/score.js +36 -1
- package/src/commands/validation/verify.js +134 -25
- package/src/core/state/phase-state-machine.js +197 -197
- package/src/core/state/state-manager.js +9 -1
- package/src/core/templates/template-renderer.js +477 -477
- package/src/dashboard/app/components/DetailPanel.jsx +11 -11
- package/src/dashboard/app/components/FlowGraph.jsx +17 -17
- package/src/dashboard/app/components/SearchFilter.jsx +22 -22
- package/src/dashboard/app/hooks/useDetailPanel.js +15 -15
- package/src/dashboard/app/main.jsx +13 -13
- package/src/dashboard/app/pages/AgentMap.jsx +370 -370
- package/src/dashboard/app/pages/PhasePipeline.jsx +408 -408
- package/src/dashboard/app/pages/RulesMap.jsx +273 -273
- package/src/dashboard/app/pages/SkillsLibrary.jsx +366 -366
- package/src/dashboard/app/pages/Standards.jsx +332 -332
- package/src/dashboard/app/styles/index.css +47 -47
- package/src/dashboard/index.html +12 -12
- package/src/dashboard/package.json +24 -24
- package/src/dashboard/scanner/phases-scanner.js +15 -15
- package/src/dashboard/scanner/rubrics-scanner.js +12 -12
- package/src/dashboard/scanner/rules-scanner.js +37 -37
- package/src/dashboard/scanner/skills-scanner.js +43 -43
- package/src/dashboard/scanner/squads-scanner.js +13 -13
- package/src/dashboard/vite-plugin-morph-data.js +17 -17
- package/src/dashboard/vite.config.js +24 -24
- package/src/lib/ai/ai-checks.js +182 -0
- package/src/lib/ai/ai-project-scan.js +347 -0
- package/src/lib/ai/code-audit.js +181 -0
- package/src/lib/ai/comment-stripper.js +184 -0
- package/src/lib/ai/pin-drift.js +138 -0
- package/src/lib/ai/registry-audit.js +285 -0
- package/src/lib/detectors/design-system-detector.js +188 -188
- package/src/lib/detectors/index.js +217 -217
- package/src/lib/e2e/compose-env.js +50 -4
- package/src/lib/evaluator-report.js +269 -15
- package/src/lib/generators/design-system-generator.js +508 -508
- package/src/lib/generators/settings-generator.js +209 -209
- package/src/lib/git/default-branch.js +92 -4
- package/src/lib/git/pr-files.js +56 -0
- package/src/lib/hooks/hook-executor.js +167 -167
- package/src/lib/installers/effects.js +193 -0
- package/src/lib/installers/mcp-installer.js +719 -719
- package/src/lib/installers/templates-reconcile.js +3 -3
- package/src/lib/risk-detector.js +284 -0
- package/src/lib/standards/verified-against.js +276 -0
- package/src/lib/tasks/eval-node.js +485 -0
- package/src/lib/tasks/linux-runner.js +297 -0
- package/src/lib/tasks/task-classifier.js +30 -30
- package/src/lib/tasks/task-parser.js +209 -209
- package/src/lib/tasks/test-nodes.js +486 -0
- package/src/lib/tasks/test-runner.js +410 -33
- package/src/lib/validators/checkpoint-persistence.js +39 -39
- package/src/lib/validators/css/css-validator.js +340 -340
- package/src/lib/validators/shared/emit-validator-dispatch.js +14 -14
- package/src/lib/validators/shared/issue-counter.js +14 -14
- package/src/lib/validators/verify-runner.js +583 -28
- package/src/lib/worktree/docker-audit.js +287 -0
- package/src/lib/worktree/env-allocator.js +24 -0
- package/src/lib/worktree/worktree-audit.js +30 -1
- package/src/scripts/setup-infra.js +24 -11
- package/src/utils/agent-id-mapper.js +11 -11
- package/src/utils/agents-installer.js +18 -8
- package/src/utils/claude-md-injector.js +10 -5
- package/src/utils/claude-settings-manager.js +300 -300
- package/src/utils/file-copier.js +11 -4
- package/src/utils/hooks-installer.js +29 -26
- package/src/utils/skills-installer.js +36 -29
- package/src/utils/version-checker.js +68 -3
- 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
|
-
*
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
*
|
|
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
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
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
|
-
*
|
|
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(
|
|
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
|
-
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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/
|
|
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` |
|
|
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).
|
|
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.
|
|
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.
|
|
7
|
+
cliVersion: "8.35.1"
|
|
8
8
|
stacks:
|
|
9
9
|
- umbraco
|
|
10
10
|
---
|