@polymorphism-tech/morph-spec 8.37.1 → 8.40.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.
- package/CLAUDE.md +37 -13
- package/README.md +2 -2
- package/bin/morph-spec.js +75 -49
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +6 -5
- package/framework/MORPH.md +25 -22
- package/framework/agents.json +96 -36
- package/framework/docs/CLI.md +54 -17
- package/framework/evals/rubrics/code-quality.md +5 -0
- package/framework/evals/rubrics/condensed.md +6 -2
- package/framework/evals/rubrics/contracts.md +20 -0
- package/framework/evals/rubrics/test-coverage.md +17 -6
- package/framework/hooks/README.md +9 -3
- package/framework/hooks/claude-code/core/graph-refresh-kick.js +52 -0
- package/framework/hooks/claude-code/core/telemetry-log.js +172 -87
- package/framework/hooks/claude-code/core/validate-completion.js +16 -90
- package/framework/hooks/claude-code/core/worktree-context.js +10 -0
- package/framework/hooks/shared/command-tokens.js +96 -0
- package/framework/hooks/shared/git-exclude.js +44 -0
- package/framework/hooks/shared/git-paths.js +52 -0
- package/framework/hooks/shared/graph-freshness.js +380 -0
- package/framework/hooks/shared/graph-refresh.js +416 -0
- package/framework/hooks/shared/morph-cli.js +17 -5
- package/framework/hooks/shared/redact-secrets.js +55 -0
- package/framework/hooks/shared/telemetry-logger.js +25 -2
- package/framework/hooks/shared/transcript-usage.js +80 -0
- package/framework/mcp/registry.json +33 -2
- package/framework/rubrics/backend.json +2 -2
- package/framework/rubrics/default.json +2 -2
- package/framework/rubrics/frontend.json +2 -2
- package/framework/rules/csharp-standards.md +1 -0
- package/framework/rules/infrastructure-standards.md +0 -1
- package/framework/rules/morph-workflow.md +10 -4
- package/framework/rules/nextjs-standards.md +1 -0
- package/framework/schemas/config.schema.json +41 -1
- package/framework/schemas/feature.schema.json +5 -1
- 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 +40 -11
- package/framework/skills/core/morph-brainstorming/SKILL.md +16 -7
- package/framework/skills/core/morph-eval/SKILL.md +1 -1
- package/framework/skills/core/morph-hotfix/SKILL.md +1 -1
- package/framework/skills/core/morph-implement/SKILL.md +44 -10
- package/framework/skills/core/morph-media/SKILL.md +1 -1
- package/framework/skills/core/morph-plan/SKILL.md +73 -15
- package/framework/skills/core/morph-proposal/SKILL.md +1 -1
- package/framework/skills/core/morph-review/SKILL.md +51 -13
- 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 +39 -13
- package/framework/standards/STANDARDS.json +189 -14
- package/framework/standards/ai-agents/context-providers.md +16 -26
- package/framework/standards/ai-agents/durable-workflows-hitl.md +15 -21
- package/framework/standards/ai-agents/modalities-image-gen.md +21 -25
- package/framework/standards/ai-agents/modalities-speech-to-text.md +4 -15
- package/framework/standards/ai-agents/modalities-text-to-speech.md +2 -11
- package/framework/standards/ai-agents/modalities-vision.md +1 -18
- package/framework/standards/ai-agents/prompt-sources.md +0 -4
- package/framework/standards/ai-agents/testing-ai.md +2 -1
- package/framework/standards/architecture/code-comments.md +100 -0
- package/framework/standards/backend/dotnet/testing.md +22 -0
- package/framework/standards/backend/integrations/neon-auth/neon-auth.md +63 -50
- package/framework/standards/frontend/admin-app/data-table.md +562 -0
- package/framework/standards/frontend/admin-app/feedback.md +236 -0
- package/framework/standards/frontend/admin-app/forms.md +232 -0
- package/framework/standards/frontend/admin-app/page-structure.md +203 -0
- package/framework/standards/frontend/design-system/ai-image-generation.md +5 -5
- package/framework/standards/frontend/nextjs/components.md +37 -58
- package/framework/standards/frontend/nextjs/data-fetching.md +1 -0
- package/framework/standards/frontend/nextjs/forms.md +31 -30
- package/framework/standards/frontend/nextjs/state-management.md +2 -1
- package/framework/standards/frontend/nextjs/testing.md +18 -0
- package/framework/standards/integration/mcp/mcp-tools.md +48 -117
- package/framework/templates/code/dotnet/abstractions/result.cs +0 -2
- package/framework/templates/code/dotnet/ai-agents/AgentBootstrap.cs.template +26 -39
- package/framework/templates/code/dotnet/ai-agents/EmbeddingService.cs.template +28 -68
- package/framework/templates/code/dotnet/ai-agents/ModelRegistry.cs.template +99 -117
- package/framework/templates/code/dotnet/ai-agents/PromptRepository.cs.template +2 -44
- package/framework/templates/code/dotnet/ai-agents/ResilientToolMiddleware.cs.template +40 -61
- package/framework/templates/code/dotnet/ai-agents/VectorSearchTool.cs.template +54 -107
- package/framework/templates/code/dotnet/ai-agents/model-registry.json.template +53 -58
- package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +192 -281
- package/framework/templates/code/dotnet/database/migration.cs +49 -83
- package/framework/templates/code/dotnet/database/vector-entity.cs +2 -46
- package/framework/templates/code/dotnet/extensions/result-extensions.cs +0 -2
- package/framework/templates/code/dotnet/feature/validator.cs.hbs +11 -15
- package/framework/templates/code/dotnet/jobs/agent.cs +3 -51
- package/framework/templates/code/dotnet/jobs/job.cs +2 -97
- package/framework/templates/code/dotnet/test.cs +2 -87
- package/framework/templates/code/typescript/contracts.ts +140 -167
- package/framework/templates/context/design-system.md +3 -3
- package/framework/templates/docs/proposal.md +11 -0
- package/framework/templates/docs/spec.md +15 -0
- package/framework/templates/docs/ui-mockups.md +115 -98
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentApi.cs +1 -48
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactory.cs +3 -79
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentFactoryOptions.cs +1 -70
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpec.cs +1 -47
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Agents/AgentSpecOptions.cs +2 -99
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/AiKitAssemblyMarker.cs +0 -6
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/ConversationStore.cs +3 -88
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/IConversationStore.cs +1 -41
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Conversation/InMemoryConversationStore.cs +0 -21
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/CountingChatClient.cs +1 -25
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalAssertion.cs +2 -63
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheMissException.cs +0 -30
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheOptions.cs +1 -52
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalCacheStamp.cs +3 -78
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalFixture.cs +4 -109
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalMode.cs +0 -22
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalQualityEvaluators.cs +1 -36
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalScenario.cs +2 -57
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/EvalSummary.cs +0 -75
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/OfflineChatClient.cs +2 -59
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Evals/ShortPathResponseCache.cs +4 -111
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaGenerator.cs +0 -34
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/IMediaProvider.cs +1 -57
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaArtifact.cs +0 -19
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaDisclosure.cs +2 -74
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaGenerator.cs +2 -33
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaIdempotencyKey.cs +1 -43
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJob.cs +1 -96
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobId.cs +0 -13
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaJobState.cs +0 -27
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaPricing.cs +0 -33
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaProvenance.cs +0 -31
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaRequest.cs +3 -75
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaResult.cs +0 -42
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaReview.cs +0 -39
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaSeams.cs +1 -55
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MediaStore.cs +3 -59
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/MorphMedia.cs +0 -46
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/GoogleImageProvider.cs +3 -28
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/OpenAIImageProvider.cs +7 -61
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Media/Providers/VeoVideoProvider.cs +2 -37
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/IUsageCostSink.cs +1 -23
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostMiddleware.cs +2 -82
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Middleware/UsageCostRecord.cs +1 -68
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphOpenTelemetryExtensions.cs +1 -62
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Observability/MorphTelemetryOptions.cs +2 -62
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/IProviderClientFactory.cs +1 -25
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelAlias.cs +0 -124
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Providers/ModelRegistry.cs +1 -73
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaIngest.cs +1 -66
- package/framework/templates/dotnet/ai-kit/src/Morph.AiKit/Rag/DeltaPlan.cs +0 -41
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentFactoryTests.cs +2 -112
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/AgentSpecTests.cs +2 -43
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ConversationStoreTests.cs +5 -110
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/DeltaIngestTests.cs +7 -103
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalAssertionTests.cs +1 -42
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheMissTests.cs +1 -30
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalCacheStampTests.cs +1 -19
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFailuresTests.cs +0 -48
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalFixtureTests.cs +1 -29
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalRefreshTests.cs +2 -38
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/EvalWorkspace.cs +1 -14
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/KitEvals.cs +4 -69
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Evals/OfflineChatClientTests.cs +1 -10
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClient.cs +1 -57
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeChatClientTests.cs +0 -26
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeClock.cs +1 -19
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeMediaProvider.cs +0 -32
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeProviderClientFactory.cs +0 -14
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/FakeUsageCostSink.cs +0 -24
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Fakes/InMemoryMediaStore.cs +0 -32
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAccessibilityTests.cs +0 -37
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaAliasIsNotAnAgentTests.cs +0 -24
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +0 -78
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaGeneratorTests.cs +0 -53
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaIdempotencyKeyTests.cs +0 -44
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaJobStateTests.cs +0 -44
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaReviewTests.cs +0 -19
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaStoreTests.cs +0 -24
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/ModelRegistryTests.cs +6 -48
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/SkeletonSmokeTests.cs +1 -13
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/TelemetryTests.cs +2 -71
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/UsageCostMiddlewareTests.cs +5 -100
- package/framework/templates/feature/decisions.md +124 -122
- package/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +39 -43
- package/framework/templates/frontend/nextjs/env.mjs.hbs +29 -32
- package/framework/templates/frontend/nextjs/page.tsx.hbs +21 -22
- package/framework/templates/frontend/nextjs/use-feature.ts.hbs +42 -54
- package/framework/templates/integrations/asaas-client.cs +332 -387
- package/framework/templates/integrations/asaas-webhook.cs +290 -351
- package/framework/templates/integrations/neon-auth-config.cs +9 -105
- package/framework/templates/project/validate.js +97 -120
- package/package.json +2 -2
- package/src/commands/dashboard/dashboard.js +80 -53
- package/src/commands/graph/affected.js +4 -3
- package/src/commands/graph/build.js +109 -18
- package/src/commands/graph/explain.js +8 -5
- package/src/commands/graph/status.js +14 -8
- package/src/commands/mcp/mcp-setup.js +37 -9
- package/src/commands/observability/cost.js +148 -18
- package/src/commands/project/doctor.js +85 -15
- package/src/commands/project/init.js +6 -3
- package/src/commands/project/install-plugin-cmd.js +1 -1
- package/src/commands/project/update.js +30 -0
- package/src/commands/project/worktree.js +73 -90
- package/src/commands/state/advance.js +18 -0
- package/src/commands/state/approve.js +15 -0
- package/src/commands/state/archive.js +62 -9
- package/src/commands/state/finish.js +62 -14
- package/src/commands/state/gate-check.js +8 -1
- package/src/commands/state/gate-decision.js +8 -4
- package/src/commands/state/report-check.js +90 -9
- package/src/commands/state/usecase.js +66 -0
- package/src/commands/tasks/dag.js +17 -2
- package/src/commands/validation/validate-feature.js +6 -1
- package/src/commands/validation/verify.js +20 -1
- package/src/dashboard/app/App.jsx +80 -16
- package/src/dashboard/app/components/ActivityFeed.jsx +172 -0
- package/src/dashboard/app/components/CommandPalette.jsx +155 -0
- package/src/dashboard/app/components/DetailPanel.jsx +47 -11
- package/src/dashboard/app/components/EntityLink.jsx +55 -0
- package/src/dashboard/app/components/ErrorBoundary.jsx +54 -0
- package/src/dashboard/app/components/FlowGraph.jsx +19 -17
- package/src/dashboard/app/components/KnowledgeMarkdown.jsx +53 -0
- package/src/dashboard/app/components/Markdown.jsx +47 -0
- package/src/dashboard/app/components/PhaseRail.jsx +111 -0
- package/src/dashboard/app/components/SearchFilter.jsx +40 -22
- package/src/dashboard/app/components/Sidebar.jsx +146 -37
- package/src/dashboard/app/hooks/useMorphQuery.js +54 -0
- package/src/dashboard/app/hooks/usePref.js +38 -0
- package/src/dashboard/app/lib/format.js +69 -0
- package/src/dashboard/app/lib/phases.js +56 -0
- package/src/dashboard/app/lib/project.js +50 -0
- package/src/dashboard/app/pages/Activity.jsx +24 -0
- package/src/dashboard/app/pages/AgentMap.jsx +371 -370
- package/src/dashboard/app/pages/FeatureDetail.jsx +604 -0
- package/src/dashboard/app/pages/Features.jsx +400 -0
- package/src/dashboard/app/pages/Guide.jsx +146 -0
- package/src/dashboard/app/pages/HookInspector.jsx +357 -322
- package/src/dashboard/app/pages/PhasePipeline.jsx +277 -408
- package/src/dashboard/app/pages/Portfolio.jsx +156 -0
- package/src/dashboard/app/pages/Rubrics.jsx +101 -0
- package/src/dashboard/app/pages/RulesMap.jsx +300 -273
- package/src/dashboard/app/pages/SkillsLibrary.jsx +483 -366
- package/src/dashboard/app/pages/Standards.jsx +407 -332
- package/src/dashboard/app/styles/index.css +187 -47
- package/src/dashboard/index.html +14 -12
- package/src/dashboard/package.json +32 -24
- package/src/dashboard/scanner/activity-scanner.js +351 -0
- package/src/dashboard/scanner/agents-scanner.js +63 -1
- package/src/dashboard/scanner/docs-scanner.js +59 -0
- package/src/dashboard/scanner/feature-status.js +10 -0
- package/src/dashboard/scanner/features-scanner.js +360 -0
- package/src/dashboard/scanner/hooks-scanner.js +8 -1
- package/src/dashboard/scanner/index.js +14 -7
- package/src/dashboard/scanner/phases-scanner.js +14 -15
- package/src/dashboard/scanner/portfolio.js +153 -0
- package/src/dashboard/scanner/project-api.js +195 -0
- package/src/dashboard/scanner/rules-scanner.js +42 -37
- package/src/dashboard/scanner/skills-scanner.js +105 -43
- package/src/dashboard/scanner/standards-scanner.js +4 -1
- package/src/dashboard/vite-plugin-morph-data.js +134 -17
- package/src/lib/ai/comment-stripper.js +101 -4
- package/src/lib/detectors/claude-config-detector.js +2 -7
- package/src/lib/detectors/index.js +5 -1
- package/src/lib/evaluator-report.js +47 -0
- package/src/lib/generators/handoff-generator.js +4 -18
- package/src/lib/generators/settings-generator.js +208 -209
- package/src/lib/git/default-branch.js +52 -0
- package/src/lib/git/tree-fingerprint.js +58 -0
- package/src/lib/git/tree-state.js +167 -0
- package/src/lib/graph/god-nodes.js +12 -3
- package/src/lib/graph/graph-health.js +48 -2
- package/src/lib/graph/graph-loader.js +99 -25
- package/src/lib/graph/graphifyignore.js +145 -28
- package/src/lib/graph/sanitize.js +117 -11
- package/src/lib/installers/mcp-installer.js +724 -719
- package/src/lib/installers/memory-installer.js +1 -2
- package/src/lib/projects/registry.js +154 -0
- package/src/lib/risk-detector.js +90 -0
- package/src/lib/specs/acervo-format.js +70 -0
- package/src/lib/specs/acervo-lifecycle.js +264 -0
- package/src/lib/specs/adr-index.js +169 -0
- package/src/lib/specs/revocations.js +156 -0
- package/src/lib/specs/screen-checklist.js +357 -0
- package/src/lib/specs/usecase-check.js +20 -16
- package/src/lib/specs/usecase-promoter.js +103 -38
- package/src/lib/specs/usecase-registry.js +7 -7
- package/src/lib/tasks/tasks-json-parser.js +2 -3
- package/src/lib/telemetry/metrics.js +386 -0
- package/src/lib/telemetry/telemetry-reader.js +161 -51
- package/src/lib/telemetry/verify-event.js +79 -0
- package/src/lib/validators/code-budget/code-budget-validator.js +200 -0
- package/src/lib/validators/code-budget/comment-scanner.js +75 -0
- package/src/lib/validators/code-budget/index.js +9 -0
- package/src/lib/validators/reuse/reuse-validator.js +4 -2
- package/src/lib/validators/reuse/symbol-scanner.js +27 -22
- package/src/lib/validators/validation-runner.js +21 -5
- package/src/lib/validators/verify-runner.js +11 -0
- package/src/lib/worktree/finish-backup.js +739 -0
- package/src/lib/worktree/ignored-triage.js +15 -8
- package/src/lib/worktree/worktree-audit.js +5 -0
- package/src/scripts/install-plugin.js +1 -1
- package/src/scripts/setup-infra.js +31 -22
- package/src/utils/agents-installer.js +338 -24
- package/src/utils/banner.js +1 -1
- package/src/utils/hooks-installer.js +75 -15
- package/src/commands/index.js +0 -13
- package/src/commands/project/checkpoint.js +0 -209
- package/src/core/state/phase-state-machine.js +0 -197
- package/src/dashboard/app/hooks/useDetailPanel.js +0 -15
- package/src/dashboard/app/pages/LiveState.jsx +0 -206
- package/src/dashboard/scanner/squads-scanner.js +0 -13
- package/src/dashboard/scanner/state-scanner.js +0 -85
- package/src/lib/generators/index.js +0 -10
- package/src/lib/hooks/hook-executor.js +0 -167
- package/src/lib/validators/checkpoint-persistence.js +0 -39
- package/src/lib/validators/shared/emit-validator-dispatch.js +0 -14
- package/src/lib/validators/shared/index.js +0 -12
- package/src/lib/validators/shared/issue-counter.js +0 -14
- package/src/lib/validators/shared/result-formatter.js +0 -124
|
@@ -43,7 +43,7 @@ Skipping this chain is the most common cause of a page whose images do not feel
|
|
|
43
43
|
|
|
44
44
|
```javascript
|
|
45
45
|
// Generate a new image
|
|
46
|
-
|
|
46
|
+
mcp__gemini-image-mcp__generate_image({
|
|
47
47
|
prompt: string, // Text description (max 5000 chars, narrative style)
|
|
48
48
|
aspectRatio?: "1:1" | "2:3" | "3:2" | "3:4" | "4:3" | "9:16" | "16:9",
|
|
49
49
|
outputPath?: string, // File path to save (e.g., "public/images/feature/hero.png")
|
|
@@ -51,25 +51,25 @@ mcp__gemini_image_mcp__generate_image({
|
|
|
51
51
|
})
|
|
52
52
|
|
|
53
53
|
// Edit an existing image
|
|
54
|
-
|
|
54
|
+
mcp__gemini-image-mcp__edit_image({
|
|
55
55
|
imageSource: string, // Path to image or image ID
|
|
56
56
|
prompt: string, // Short, targeted edit instructions (1-2 sentences)
|
|
57
57
|
outputPath?: string,
|
|
58
58
|
})
|
|
59
59
|
|
|
60
60
|
// Continue editing last image
|
|
61
|
-
|
|
61
|
+
mcp__gemini-image-mcp__continue_editing({
|
|
62
62
|
prompt: string, // One adjustment at a time
|
|
63
63
|
})
|
|
64
64
|
|
|
65
65
|
// List generated images
|
|
66
|
-
|
|
66
|
+
mcp__gemini-image-mcp__list_images({
|
|
67
67
|
type?: "generated" | "edited" | "all",
|
|
68
68
|
limit?: number,
|
|
69
69
|
})
|
|
70
70
|
|
|
71
71
|
// Get image details
|
|
72
|
-
|
|
72
|
+
mcp__gemini-image-mcp__get_image_info({
|
|
73
73
|
imageId?: string, // Defaults to last image
|
|
74
74
|
})
|
|
75
75
|
```
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
> **Keywords:** component, shadcn, reusable, shared, ui, three-tier
|
|
6
6
|
> **Load When:** creating or editing React components
|
|
7
7
|
|
|
8
|
-
**Verified against:** Next.js
|
|
8
|
+
**Verified against:** Next.js 16 + shadcn 4 CLI (the code blocks typecheck under `tsc --strict`). Last-verified: 2026-09-24.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
@@ -33,83 +33,62 @@ Tier 3: features/*/components/ ← feature-scoped (knows about users, billing, e
|
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
35
|
# Add shadcn components via CLI — never write them manually
|
|
36
|
-
npx shadcn@latest add button card dialog
|
|
36
|
+
npx shadcn@latest add button card dialog field input table
|
|
37
37
|
```
|
|
38
38
|
|
|
39
39
|
If you need to change a shadcn component's behavior, wrap it — do not edit the source file.
|
|
40
40
|
|
|
41
41
|
## Tier 2 — Shared Composed Components
|
|
42
42
|
|
|
43
|
+
Composes shadcn primitives and knows nothing about the domain.
|
|
44
|
+
|
|
43
45
|
```tsx
|
|
44
|
-
// components/
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
interface DataTableProps<TData> {
|
|
55
|
-
columns: ColumnDef<TData>[];
|
|
56
|
-
data: TData[];
|
|
46
|
+
// components/page-header.tsx
|
|
47
|
+
import type { ReactNode } from 'react';
|
|
48
|
+
import { cn } from '@/lib/utils';
|
|
49
|
+
|
|
50
|
+
interface PageHeaderProps {
|
|
51
|
+
title: string;
|
|
52
|
+
description?: string;
|
|
53
|
+
actions?: ReactNode;
|
|
54
|
+
className?: string;
|
|
57
55
|
}
|
|
58
56
|
|
|
59
|
-
export function
|
|
60
|
-
const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel() });
|
|
57
|
+
export function PageHeader({ title, description, actions, className }: PageHeaderProps) {
|
|
61
58
|
return (
|
|
62
|
-
<
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
</TableHead>
|
|
70
|
-
))}
|
|
71
|
-
</TableRow>
|
|
72
|
-
))}
|
|
73
|
-
</TableHeader>
|
|
74
|
-
<TableBody>
|
|
75
|
-
{table.getRowModel().rows.map((row) => (
|
|
76
|
-
<TableRow key={row.id}>
|
|
77
|
-
{row.getVisibleCells().map((cell) => (
|
|
78
|
-
<TableCell key={cell.id}>
|
|
79
|
-
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
80
|
-
</TableCell>
|
|
81
|
-
))}
|
|
82
|
-
</TableRow>
|
|
83
|
-
))}
|
|
84
|
-
</TableBody>
|
|
85
|
-
</Table>
|
|
59
|
+
<div className={cn('flex items-start justify-between gap-4', className)}>
|
|
60
|
+
<div>
|
|
61
|
+
<h1 className="text-2xl font-semibold tracking-tight">{title}</h1>
|
|
62
|
+
{description && <p className="text-sm text-muted-foreground">{description}</p>}
|
|
63
|
+
</div>
|
|
64
|
+
{actions && <div className="flex gap-2">{actions}</div>}
|
|
65
|
+
</div>
|
|
86
66
|
);
|
|
87
67
|
}
|
|
88
68
|
```
|
|
89
69
|
|
|
70
|
+
**The shared data table has one home: `admin-app/data-table.md`.** It is the Tier 2 component with the most rules — pagination, sorting and filtering on the server, the three states, selection — so it is specified there, once. Do not write a second `components/data-table.tsx` from this page.
|
|
71
|
+
|
|
90
72
|
## Tier 3 — Feature Components
|
|
91
73
|
|
|
92
74
|
```tsx
|
|
93
|
-
// features/users/components/
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
export function UserList() {
|
|
107
|
-
const { data: users = [], isLoading } = useUsers();
|
|
108
|
-
if (isLoading) return <div>Loading...</div>;
|
|
109
|
-
return <DataTable columns={columns} data={users} />;
|
|
75
|
+
// features/users/components/users-page-header.tsx
|
|
76
|
+
import { PageHeader } from '@/components/page-header';
|
|
77
|
+
import { Button } from '@/components/ui/button';
|
|
78
|
+
|
|
79
|
+
export function UsersPageHeader({ canInvite }: { canInvite: boolean }) {
|
|
80
|
+
return (
|
|
81
|
+
<PageHeader
|
|
82
|
+
title="Users"
|
|
83
|
+
description="People with access to this workspace."
|
|
84
|
+
actions={canInvite ? <Button>Invite user</Button> : null}
|
|
85
|
+
/>
|
|
86
|
+
);
|
|
110
87
|
}
|
|
111
88
|
```
|
|
112
89
|
|
|
90
|
+
A feature **list** is a Tier 3 component too: the feature owns the columns and the URL ⇄ table mapping, the shared table owns the rendering — `admin-app/data-table.md` → "The Feature Table".
|
|
91
|
+
|
|
113
92
|
## Component Props Conventions
|
|
114
93
|
|
|
115
94
|
```tsx
|
|
@@ -18,6 +18,7 @@ Server Components for initial page load. TanStack Query for client mutations and
|
|
|
18
18
|
- NEVER use `useEffect(() => { fetch(...) }, [])` — this is the old pattern
|
|
19
19
|
- ALWAYS validate API responses with Zod before using them
|
|
20
20
|
- ALWAYS use query key factories for consistent cache invalidation
|
|
21
|
+
- NEVER fetch a whole collection to page, sort or filter it in the browser — a list is paged on the server, with the query in the URL (`admin-app/data-table.md`)
|
|
21
22
|
|
|
22
23
|
## TanStack Query Setup
|
|
23
24
|
|
|
@@ -2,20 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
> **Scope:** frontend/nextjs/forms
|
|
4
4
|
> **Layer:** 2 (on keyword)
|
|
5
|
-
> **Keywords:** form, react-hook-form, zod, validation, input, submit, zodResolver
|
|
5
|
+
> **Keywords:** form, react-hook-form, zod, validation, input, submit, zodResolver, Controller, Field, FieldError
|
|
6
6
|
> **Load When:** implementing any form in Next.js
|
|
7
7
|
|
|
8
|
-
**Verified against:** Next.js
|
|
8
|
+
**Verified against:** Next.js 16 + react-hook-form 7 + Zod 4 + @hookform/resolvers 5 + shadcn 4 `Field` (the code blocks typecheck under `tsc --strict`). Last-verified: 2026-09-24.
|
|
9
9
|
|
|
10
10
|
---
|
|
11
11
|
|
|
12
|
-
react-hook-form + Zod + shadcn
|
|
12
|
+
react-hook-form + Zod + shadcn `Field` components, wired through react-hook-form's `Controller`. The schema defines both the validation rules and the TypeScript types.
|
|
13
|
+
|
|
14
|
+
**Admin app / CRUD screen?** This is the base pattern; `admin-app/forms.md` adds what a CRUD form needs on top of it — server validation errors on the field, where the form lives (dialog, sheet, page), validation timing and the unsaved-changes guard.
|
|
13
15
|
|
|
14
16
|
## Core Rules
|
|
15
17
|
|
|
16
|
-
- ALWAYS define the Zod schema first — derive the TypeScript type from it with `z.infer<>`
|
|
18
|
+
- ALWAYS define the Zod schema first — derive the TypeScript type from it with `z.infer<>` (or `z.input<>`/`z.output<>` when the schema coerces)
|
|
17
19
|
- ALWAYS use `zodResolver` to connect schema to react-hook-form
|
|
18
|
-
- ALWAYS
|
|
20
|
+
- ALWAYS render fields with `Controller` + shadcn `<Field>`, `<FieldLabel>`, `<FieldError>` for consistent UI and accessible errors
|
|
19
21
|
- NEVER use `useState` for form field values — react-hook-form handles this
|
|
20
22
|
- ALWAYS use `useMutation` from TanStack Query for form submission
|
|
21
23
|
|
|
@@ -38,11 +40,9 @@ export type CreateUserInput = z.infer<typeof createUserSchema>;
|
|
|
38
40
|
// features/users/components/create-user-form.tsx
|
|
39
41
|
'use client';
|
|
40
42
|
|
|
41
|
-
import { useForm } from 'react-hook-form';
|
|
43
|
+
import { Controller, useForm } from 'react-hook-form';
|
|
42
44
|
import { zodResolver } from '@hookform/resolvers/zod';
|
|
43
|
-
import {
|
|
44
|
-
Form, FormControl, FormField, FormItem, FormLabel, FormMessage
|
|
45
|
-
} from '@/components/ui/form';
|
|
45
|
+
import { Field, FieldError, FieldGroup, FieldLabel } from '@/components/ui/field';
|
|
46
46
|
import { Input } from '@/components/ui/input';
|
|
47
47
|
import { Button } from '@/components/ui/button';
|
|
48
48
|
import { useCreateUser } from '@/features/users/hooks/use-create-user';
|
|
@@ -64,28 +64,28 @@ export function CreateUserForm({ onSuccess }: { onSuccess?: () => void }) {
|
|
|
64
64
|
}
|
|
65
65
|
|
|
66
66
|
return (
|
|
67
|
-
<
|
|
68
|
-
<
|
|
69
|
-
<
|
|
70
|
-
control={form.control}
|
|
67
|
+
<form onSubmit={form.handleSubmit(onSubmit)}>
|
|
68
|
+
<FieldGroup>
|
|
69
|
+
<Controller
|
|
71
70
|
name="name"
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
<
|
|
76
|
-
<
|
|
77
|
-
|
|
71
|
+
control={form.control}
|
|
72
|
+
render={({ field, fieldState }) => (
|
|
73
|
+
<Field data-invalid={fieldState.invalid}>
|
|
74
|
+
<FieldLabel htmlFor={field.name}>Name</FieldLabel>
|
|
75
|
+
<Input {...field} id={field.name} aria-invalid={fieldState.invalid} placeholder="John Doe" />
|
|
76
|
+
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
|
|
77
|
+
</Field>
|
|
78
78
|
)}
|
|
79
79
|
/>
|
|
80
|
-
<
|
|
81
|
-
control={form.control}
|
|
80
|
+
<Controller
|
|
82
81
|
name="email"
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
<
|
|
87
|
-
<
|
|
88
|
-
|
|
82
|
+
control={form.control}
|
|
83
|
+
render={({ field, fieldState }) => (
|
|
84
|
+
<Field data-invalid={fieldState.invalid}>
|
|
85
|
+
<FieldLabel htmlFor={field.name}>Email</FieldLabel>
|
|
86
|
+
<Input {...field} id={field.name} type="email" aria-invalid={fieldState.invalid} />
|
|
87
|
+
{fieldState.invalid && <FieldError errors={[fieldState.error]} />}
|
|
88
|
+
</Field>
|
|
89
89
|
)}
|
|
90
90
|
/>
|
|
91
91
|
{form.formState.errors.root && (
|
|
@@ -94,8 +94,8 @@ export function CreateUserForm({ onSuccess }: { onSuccess?: () => void }) {
|
|
|
94
94
|
<Button type="submit" disabled={isPending}>
|
|
95
95
|
{isPending ? 'Creating...' : 'Create User'}
|
|
96
96
|
</Button>
|
|
97
|
-
</
|
|
98
|
-
</
|
|
97
|
+
</FieldGroup>
|
|
98
|
+
</form>
|
|
99
99
|
);
|
|
100
100
|
}
|
|
101
101
|
```
|
|
@@ -123,11 +123,12 @@ export const updateUserSchema = createUserSchema.partial();
|
|
|
123
123
|
| Wrong | Right | Why |
|
|
124
124
|
|-------|-------|-----|
|
|
125
125
|
| `useState` for each field | `useForm` | Unnecessary re-renders on every keystroke |
|
|
126
|
-
| Manual error display | `<
|
|
126
|
+
| Manual error display | `<FieldError errors={[fieldState.error]} />` | Consistent UI, wired to the field's own error |
|
|
127
127
|
| `fetch` in submit handler | `useMutation` | Loading state, error handling, cache invalidation |
|
|
128
128
|
| Type written manually | `z.infer<typeof schema>` | Single source of truth |
|
|
129
129
|
| `z.string().email()` | `z.email()` | Zod 4 moved format checks to top-level functions |
|
|
130
130
|
| `{ required_error: '...' }` | `{ error: '...' }` | Zod 4 unified error customization on one `error` param |
|
|
131
|
+
| Legacy shadcn `<Form>`/`<FormField>`/`<FormMessage>` in a new screen | `Controller` + `<Field>`/`<FieldError>` | shadcn's forms docs are written around `Field`; a screen still on the legacy wrapper is migrated when it is next touched, never extended |
|
|
131
132
|
|
|
132
133
|
---
|
|
133
134
|
|
|
@@ -14,7 +14,8 @@ Server state (API data) lives in TanStack Query. UI state lives in React. No glo
|
|
|
14
14
|
## Core Rules
|
|
15
15
|
|
|
16
16
|
- ALWAYS use TanStack Query for anything that comes from the .NET API
|
|
17
|
-
- ALWAYS use `useState` for local UI state (modal open,
|
|
17
|
+
- ALWAYS use `useState` for local UI state (modal open, form step)
|
|
18
|
+
- ALWAYS keep a list's page, sort and filters, and a page's active tab, in the URL (`searchParams`) — never in `useState`: a refresh or a shared link must reopen the same view (`admin-app/data-table.md`, `admin-app/page-structure.md`)
|
|
18
19
|
- NEVER install Zustand or Redux without first exhausting Server Components + TanStack Query
|
|
19
20
|
- NEVER use React Context for server state — Context does not cache or deduplicate
|
|
20
21
|
- ALWAYS derive state from server data rather than syncing it to local state
|
|
@@ -101,6 +101,24 @@ export function QueryClientWrapper({ children }: { children: React.ReactNode })
|
|
|
101
101
|
}
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
+
## Test Budget
|
|
105
|
+
|
|
106
|
+
The plan (`morph-plan`) gives each task a budget: **one test per postcondition, plus one
|
|
107
|
+
regression test per bug fixed**. Going above it takes a one-line justification in the task. The
|
|
108
|
+
happy path + one error path per component above is that budget applied to a component.
|
|
109
|
+
|
|
110
|
+
- **Table before copy.** Scenarios of the same behavior — edge cases included — are rows of one
|
|
111
|
+
`it.each`/`test.each`, never N `it()` blocks that differ by one value.
|
|
112
|
+
- **No test that only pins text.** Finding an element by its text to assert what the user can do
|
|
113
|
+
is fine; a test whose only assertion is the presence or absence of a copy string (a dash, a
|
|
114
|
+
word, a tenant name) proves the file's version, not behavior. That rule belongs in a lint rule or
|
|
115
|
+
a publish-time validation, outside the suite count.
|
|
116
|
+
- **Shared helpers by default.** Reuse the existing wrappers (`test/helpers.tsx`), MSW handlers and
|
|
117
|
+
factories. Before writing a new one, look for it (`morph-spec graph explain <Name>`; fallback
|
|
118
|
+
without a graph: `grep -rn`).
|
|
119
|
+
- **TDD where it pays:** a bug gets its regression test first, and so does pure logic (formatters,
|
|
120
|
+
reducers, schema). Component and integration tests may come after the code.
|
|
121
|
+
|
|
104
122
|
## Common Mistakes
|
|
105
123
|
|
|
106
124
|
| Wrong | Right | Why |
|