@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
|
@@ -1,83 +1,49 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
{
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
},
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
migrationBuilder.
|
|
47
|
-
name: "
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/// <inheritdoc />
|
|
53
|
-
protected override void Down(MigrationBuilder migrationBuilder)
|
|
54
|
-
{
|
|
55
|
-
migrationBuilder.DropTable(
|
|
56
|
-
name: "{{pascalCase FEATURE_NAME}}s");
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// ============================================================
|
|
61
|
-
// HOW TO CREATE A MIGRATION
|
|
62
|
-
// ============================================================
|
|
63
|
-
//
|
|
64
|
-
// 1. Add your entity to AppDbContext:
|
|
65
|
-
//
|
|
66
|
-
// public DbSet<{{pascalCase FEATURE_NAME}}> {{pascalCase FEATURE_NAME}}s => Set<{{pascalCase FEATURE_NAME}}>();
|
|
67
|
-
//
|
|
68
|
-
// 2. Add your configuration:
|
|
69
|
-
//
|
|
70
|
-
// protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
71
|
-
// {
|
|
72
|
-
// modelBuilder.ApplyConfiguration(new {{pascalCase FEATURE_NAME}}Configuration());
|
|
73
|
-
// }
|
|
74
|
-
//
|
|
75
|
-
// 3. Run migration command:
|
|
76
|
-
//
|
|
77
|
-
// dotnet ef migrations add Add{{pascalCase FEATURE_NAME}} -p src/{{NAMESPACE}}.Infrastructure -s src/{{NAMESPACE}}.Web
|
|
78
|
-
//
|
|
79
|
-
// 4. Apply migration:
|
|
80
|
-
//
|
|
81
|
-
// dotnet ef database update -p src/{{NAMESPACE}}.Infrastructure -s src/{{NAMESPACE}}.Web
|
|
82
|
-
//
|
|
83
|
-
// ============================================================
|
|
1
|
+
using Microsoft.EntityFrameworkCore.Migrations;
|
|
2
|
+
|
|
3
|
+
#nullable disable
|
|
4
|
+
|
|
5
|
+
namespace {{NAMESPACE}}.Infrastructure.Data.Migrations;
|
|
6
|
+
|
|
7
|
+
public partial class Add{{pascalCase FEATURE_NAME}} : Migration
|
|
8
|
+
{
|
|
9
|
+
protected override void Up(MigrationBuilder migrationBuilder)
|
|
10
|
+
{
|
|
11
|
+
migrationBuilder.CreateTable(
|
|
12
|
+
name: "{{pascalCase FEATURE_NAME}}s",
|
|
13
|
+
columns: table => new
|
|
14
|
+
{
|
|
15
|
+
Id = table.Column<int>(type: "int", nullable: false)
|
|
16
|
+
.Annotation("SqlServer:Identity", "1, 1"),
|
|
17
|
+
Name = table.Column<string>(type: "nvarchar(200)", maxLength: 200, nullable: false),
|
|
18
|
+
Status = table.Column<string>(type: "nvarchar(50)", maxLength: 50, nullable: false),
|
|
19
|
+
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false,
|
|
20
|
+
defaultValueSql: "GETUTCDATE()"),
|
|
21
|
+
UpdatedAt = table.Column<DateTime>(type: "datetime2", nullable: true)
|
|
22
|
+
},
|
|
23
|
+
constraints: table =>
|
|
24
|
+
{
|
|
25
|
+
table.PrimaryKey("PK_{{pascalCase FEATURE_NAME}}s", x => x.Id);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
migrationBuilder.CreateIndex(
|
|
29
|
+
name: "IX_{{pascalCase FEATURE_NAME}}s_Name",
|
|
30
|
+
table: "{{pascalCase FEATURE_NAME}}s",
|
|
31
|
+
column: "Name");
|
|
32
|
+
|
|
33
|
+
migrationBuilder.CreateIndex(
|
|
34
|
+
name: "IX_{{pascalCase FEATURE_NAME}}s_Status",
|
|
35
|
+
table: "{{pascalCase FEATURE_NAME}}s",
|
|
36
|
+
column: "Status");
|
|
37
|
+
|
|
38
|
+
migrationBuilder.CreateIndex(
|
|
39
|
+
name: "IX_{{pascalCase FEATURE_NAME}}s_CreatedAt",
|
|
40
|
+
table: "{{pascalCase FEATURE_NAME}}s",
|
|
41
|
+
column: "CreatedAt");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
protected override void Down(MigrationBuilder migrationBuilder)
|
|
45
|
+
{
|
|
46
|
+
migrationBuilder.DropTable(
|
|
47
|
+
name: "{{pascalCase FEATURE_NAME}}s");
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// PGVECTOR ENTITY + CONFIGURATION TEMPLATE
|
|
3
|
-
// Generated by MORPH Framework
|
|
4
|
-
// ============================================================
|
|
5
|
-
|
|
6
1
|
using System.ComponentModel.DataAnnotations.Schema;
|
|
7
2
|
using Microsoft.EntityFrameworkCore;
|
|
8
3
|
using Microsoft.EntityFrameworkCore.Metadata.Builders;
|
|
@@ -12,10 +7,6 @@ using Pgvector;
|
|
|
12
7
|
|
|
13
8
|
namespace {{NAMESPACE}}.Domain.Entities;
|
|
14
9
|
|
|
15
|
-
/// <summary>
|
|
16
|
-
/// Entity with vector embedding for similarity search via pgvector.
|
|
17
|
-
/// Dimensions: 1536 (text-embedding-3-small). Adjust if using a different model.
|
|
18
|
-
/// </summary>
|
|
19
10
|
public class {{pascalCase FEATURE_NAME}}
|
|
20
11
|
{
|
|
21
12
|
public Guid Id { get; set; }
|
|
@@ -23,6 +14,7 @@ public class {{pascalCase FEATURE_NAME}}
|
|
|
23
14
|
public string Content { get; set; } = string.Empty;
|
|
24
15
|
public string? Metadata { get; set; }
|
|
25
16
|
|
|
17
|
+
// 1536 é a dimensão do text-embedding-3-small; troca junto com o modelo, aqui e na configuração
|
|
26
18
|
[Column(TypeName = "vector(1536)")]
|
|
27
19
|
public Vector? Embedding { get; set; }
|
|
28
20
|
|
|
@@ -30,12 +22,9 @@ public class {{pascalCase FEATURE_NAME}}
|
|
|
30
22
|
public DateTimeOffset? UpdatedAt { get; set; }
|
|
31
23
|
}
|
|
32
24
|
|
|
33
|
-
// ============================================================
|
|
34
|
-
// ENTITY TYPE CONFIGURATION
|
|
35
|
-
// ============================================================
|
|
36
|
-
|
|
37
25
|
namespace {{NAMESPACE}}.Infrastructure.Data.Configurations;
|
|
38
26
|
|
|
27
|
+
// Exige UseVector() no AddNpgsql e HasPostgresExtension("vector") no OnModelCreating
|
|
39
28
|
public class {{pascalCase FEATURE_NAME}}Configuration : IEntityTypeConfiguration<{{pascalCase FEATURE_NAME}}>
|
|
40
29
|
{
|
|
41
30
|
public void Configure(EntityTypeBuilder<{{pascalCase FEATURE_NAME}}> builder)
|
|
@@ -49,7 +38,6 @@ public class {{pascalCase FEATURE_NAME}}Configuration : IEntityTypeConfiguration
|
|
|
49
38
|
builder.Property(e => e.Embedding).HasColumnType("vector(1536)");
|
|
50
39
|
builder.Property(e => e.CreatedAt).HasDefaultValueSql("now()");
|
|
51
40
|
|
|
52
|
-
// HNSW index for cosine similarity search
|
|
53
41
|
builder.HasIndex(e => e.Embedding)
|
|
54
42
|
.HasMethod("hnsw")
|
|
55
43
|
.HasOperators("vector_cosine_ops")
|
|
@@ -59,35 +47,3 @@ public class {{pascalCase FEATURE_NAME}}Configuration : IEntityTypeConfiguration
|
|
|
59
47
|
builder.HasIndex(e => e.Title);
|
|
60
48
|
}
|
|
61
49
|
}
|
|
62
|
-
|
|
63
|
-
// ============================================================
|
|
64
|
-
// SETUP INSTRUCTIONS
|
|
65
|
-
// ============================================================
|
|
66
|
-
//
|
|
67
|
-
// 1. Install NuGet packages:
|
|
68
|
-
//
|
|
69
|
-
// dotnet add package Pgvector.EntityFrameworkCore
|
|
70
|
-
// dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL
|
|
71
|
-
//
|
|
72
|
-
// 2. Configure NpgsqlDataSource with vector support in Program.cs:
|
|
73
|
-
//
|
|
74
|
-
// builder.Services.AddNpgsql<AppDbContext>(
|
|
75
|
-
// connectionString,
|
|
76
|
-
// npgsqlOptions => npgsqlOptions.UseVector());
|
|
77
|
-
//
|
|
78
|
-
// 3. Register in DbContext:
|
|
79
|
-
//
|
|
80
|
-
// public DbSet<{{pascalCase FEATURE_NAME}}> {{pascalCase FEATURE_NAME}}s => Set<{{pascalCase FEATURE_NAME}}>();
|
|
81
|
-
//
|
|
82
|
-
// protected override void OnModelCreating(ModelBuilder modelBuilder)
|
|
83
|
-
// {
|
|
84
|
-
// modelBuilder.HasPostgresExtension("vector");
|
|
85
|
-
// modelBuilder.ApplyConfiguration(new {{pascalCase FEATURE_NAME}}Configuration());
|
|
86
|
-
// }
|
|
87
|
-
//
|
|
88
|
-
// 4. Create and apply migration:
|
|
89
|
-
//
|
|
90
|
-
// dotnet ef migrations add Add{{pascalCase FEATURE_NAME}}WithVector -p src/{{NAMESPACE}}.Infrastructure -s src/{{NAMESPACE}}.Web
|
|
91
|
-
// dotnet ef database update -p src/{{NAMESPACE}}.Infrastructure -s src/{{NAMESPACE}}.Web
|
|
92
|
-
//
|
|
93
|
-
// ============================================================
|
|
@@ -5,7 +5,6 @@ namespace {{pascalCase PROJECT_NAME}}.Extensions;
|
|
|
5
5
|
|
|
6
6
|
public static class ResultExtensions
|
|
7
7
|
{
|
|
8
|
-
// For non-generic Result
|
|
9
8
|
public static TOut Match<TOut>(
|
|
10
9
|
this Result result,
|
|
11
10
|
Func<TOut> onSuccess,
|
|
@@ -16,7 +15,6 @@ public static class ResultExtensions
|
|
|
16
15
|
: onFailure(result.Error);
|
|
17
16
|
}
|
|
18
17
|
|
|
19
|
-
// 🔥 THIS is what your endpoint needs
|
|
20
18
|
public static TOut Match<TIn, TOut>(
|
|
21
19
|
this Result<TIn> result,
|
|
22
20
|
Func<TIn, TOut> onSuccess,
|
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
using FluentValidation;
|
|
2
|
-
|
|
3
|
-
namespace {{pascalCase PROJECT_NAME}}.Features.{{pascalCase FEATURE_NAME}}Feature.{{pascalCase SLICE_NAME}};
|
|
4
|
-
|
|
5
|
-
public class {{pascalCase SLICE_NAME}}Validator : AbstractValidator<{{pascalCase SLICE_NAME}}Request>
|
|
6
|
-
{
|
|
7
|
-
public {{pascalCase SLICE_NAME}}Validator()
|
|
8
|
-
{
|
|
9
|
-
// TODO: Add validation rules for {{pascalCase SLICE_NAME}}Request properties
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
// .NotEmpty().WithMessage("Name is required")
|
|
13
|
-
// .MaximumLength(200).WithMessage("Name must not exceed 200 characters");
|
|
14
|
-
}
|
|
15
|
-
}
|
|
1
|
+
using FluentValidation;
|
|
2
|
+
|
|
3
|
+
namespace {{pascalCase PROJECT_NAME}}.Features.{{pascalCase FEATURE_NAME}}Feature.{{pascalCase SLICE_NAME}};
|
|
4
|
+
|
|
5
|
+
public class {{pascalCase SLICE_NAME}}Validator : AbstractValidator<{{pascalCase SLICE_NAME}}Request>
|
|
6
|
+
{
|
|
7
|
+
public {{pascalCase SLICE_NAME}}Validator()
|
|
8
|
+
{
|
|
9
|
+
// TODO: Add validation rules for {{pascalCase SLICE_NAME}}Request properties
|
|
10
|
+
}
|
|
11
|
+
}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// MICROSOFT AGENT FRAMEWORK TEMPLATE
|
|
3
|
-
// Generated by MORPH Framework
|
|
4
|
-
// ============================================================
|
|
5
|
-
|
|
6
1
|
using System.ComponentModel;
|
|
7
2
|
using System.Text.Json;
|
|
8
3
|
using Microsoft.Extensions.AI;
|
|
@@ -10,15 +5,10 @@ using Microsoft.Extensions.Logging;
|
|
|
10
5
|
|
|
11
6
|
namespace {{NAMESPACE}}.Agents.{{pascalCase FEATURE_NAME}};
|
|
12
7
|
|
|
13
|
-
/// <summary>
|
|
14
|
-
/// AI Agent for analyzing {{pascalCase FEATURE_NAME}} data.
|
|
15
|
-
/// Uses Microsoft Agent Framework with IChatClient (gpt-4o-mini by default).
|
|
16
|
-
/// </summary>
|
|
17
8
|
public class {{pascalCase FEATURE_NAME}}AnalyzerAgent(
|
|
18
9
|
IChatClient chatClient,
|
|
19
10
|
ILogger<{{pascalCase FEATURE_NAME}}AnalyzerAgent> logger) : I{{pascalCase FEATURE_NAME}}AnalyzerAgent
|
|
20
11
|
{
|
|
21
|
-
/// <inheritdoc />
|
|
22
12
|
public async Task<{{pascalCase FEATURE_NAME}}AnalysisResult> AnalyzeAsync(
|
|
23
13
|
{{pascalCase FEATURE_NAME}}Data data,
|
|
24
14
|
CancellationToken cancellationToken = default)
|
|
@@ -65,14 +55,12 @@ public class {{pascalCase FEATURE_NAME}}AnalyzerAgent(
|
|
|
65
55
|
return result;
|
|
66
56
|
}
|
|
67
57
|
|
|
68
|
-
#region Tools
|
|
69
|
-
|
|
70
58
|
[Description("Gets additional context for the analysis")]
|
|
71
59
|
private async Task<string> GetContextAsync(
|
|
72
60
|
[Description("What context is needed")] string query,
|
|
73
61
|
CancellationToken ct = default)
|
|
74
62
|
{
|
|
75
|
-
// TODO:
|
|
63
|
+
// TODO: buscar o contexto (banco ou busca)
|
|
76
64
|
await Task.CompletedTask;
|
|
77
65
|
return $"Context for: {query}";
|
|
78
66
|
}
|
|
@@ -82,19 +70,16 @@ public class {{pascalCase FEATURE_NAME}}AnalyzerAgent(
|
|
|
82
70
|
[Description("Metric type to retrieve")] string metricType,
|
|
83
71
|
CancellationToken ct = default)
|
|
84
72
|
{
|
|
85
|
-
// TODO:
|
|
73
|
+
// TODO: buscar as métricas
|
|
86
74
|
await Task.CompletedTask;
|
|
87
75
|
return $"Metrics for: {metricType}";
|
|
88
76
|
}
|
|
89
77
|
|
|
90
|
-
#endregion
|
|
91
|
-
|
|
92
|
-
#region Response Parsing
|
|
93
|
-
|
|
94
78
|
private {{pascalCase FEATURE_NAME}}AnalysisResult ParseResponse(string response)
|
|
95
79
|
{
|
|
96
80
|
try
|
|
97
81
|
{
|
|
82
|
+
// o modelo às vezes cerca o JSON com ```json mesmo instruído a não fazer
|
|
98
83
|
var json = response
|
|
99
84
|
.Replace("```json", "")
|
|
100
85
|
.Replace("```", "")
|
|
@@ -126,37 +111,4 @@ public class {{pascalCase FEATURE_NAME}}AnalyzerAgent(
|
|
|
126
111
|
public List<string>? Recommendations { get; set; }
|
|
127
112
|
public double ConfidenceScore { get; set; }
|
|
128
113
|
}
|
|
129
|
-
|
|
130
|
-
#endregion
|
|
131
114
|
}
|
|
132
|
-
|
|
133
|
-
// ============================================================
|
|
134
|
-
// DEPENDENCY INJECTION SETUP
|
|
135
|
-
// ============================================================
|
|
136
|
-
//
|
|
137
|
-
// In Program.cs:
|
|
138
|
-
//
|
|
139
|
-
// // Register IChatClient (Azure OpenAI with Managed Identity)
|
|
140
|
-
// builder.Services.AddSingleton<IChatClient>(sp =>
|
|
141
|
-
// {
|
|
142
|
-
// var cfg = sp.GetRequiredService<IConfiguration>();
|
|
143
|
-
// return new AzureOpenAIClient(
|
|
144
|
-
// new Uri(cfg["AzureOpenAI:Endpoint"]!),
|
|
145
|
-
// new DefaultAzureCredential())
|
|
146
|
-
// .GetChatClient(cfg["AzureOpenAI:DeploymentName"] ?? "gpt-4o-mini")
|
|
147
|
-
// .AsIChatClient();
|
|
148
|
-
// });
|
|
149
|
-
//
|
|
150
|
-
// // Option A: Register as scoped service
|
|
151
|
-
// builder.Services.AddScoped<I{{pascalCase FEATURE_NAME}}AnalyzerAgent, {{pascalCase FEATURE_NAME}}AnalyzerAgent>();
|
|
152
|
-
//
|
|
153
|
-
// // Option B: Register as keyed agent (recommended for multiple agents)
|
|
154
|
-
// builder.AddAIAgent("{{pascalCase FEATURE_NAME}}Analyzer", (sp, key) =>
|
|
155
|
-
// {
|
|
156
|
-
// var chatClient = sp.GetRequiredService<IChatClient>();
|
|
157
|
-
// return new ChatClientAgent(chatClient,
|
|
158
|
-
// name: key,
|
|
159
|
-
// instructions: "You are an expert {{pascalCase FEATURE_NAME}} analyst.");
|
|
160
|
-
// });
|
|
161
|
-
//
|
|
162
|
-
// ============================================================
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
// ============================================================
|
|
2
|
-
// HANGFIRE JOB TEMPLATE (VSA Pattern — ApplicationDbContext direto)
|
|
3
|
-
// Generated by MORPH Framework
|
|
4
|
-
// ============================================================
|
|
5
|
-
|
|
6
1
|
using Hangfire;
|
|
7
2
|
using Microsoft.EntityFrameworkCore;
|
|
8
3
|
using Microsoft.Extensions.Logging;
|
|
@@ -10,21 +5,11 @@ using {{pascalCase PROJECT_NAME}}.Database;
|
|
|
10
5
|
|
|
11
6
|
namespace {{pascalCase PROJECT_NAME}}.Features.{{pascalCase FEATURE_NAME}}.Jobs;
|
|
12
7
|
|
|
13
|
-
/// <summary>
|
|
14
|
-
/// Background job for processing {{pascalCase FEATURE_NAME}}.
|
|
15
|
-
/// Uses Hangfire for scheduling and retry handling.
|
|
16
|
-
/// Injects ApplicationDbContext directly (no service layer, no generic repository).
|
|
17
|
-
/// </summary>
|
|
18
8
|
public class {{pascalCase FEATURE_NAME}}ProcessorJob(
|
|
19
9
|
ApplicationDbContext db,
|
|
20
10
|
I{{pascalCase FEATURE_NAME}}AnalyzerAgent analyzer,
|
|
21
11
|
ILogger<{{pascalCase FEATURE_NAME}}ProcessorJob> logger) : I{{pascalCase FEATURE_NAME}}ProcessorJob
|
|
22
12
|
{
|
|
23
|
-
/// <summary>
|
|
24
|
-
/// Executes the {{pascalCase FEATURE_NAME}} processing job.
|
|
25
|
-
/// </summary>
|
|
26
|
-
/// <param name="id">The {{pascalCase FEATURE_NAME}} ID to process</param>
|
|
27
|
-
/// <param name="cancellationToken">Cancellation token</param>
|
|
28
13
|
[AutomaticRetry(Attempts = 3, DelaysInSeconds = new[] { 60, 300, 900 })]
|
|
29
14
|
[Queue("default")]
|
|
30
15
|
[JobDisplayName("{{pascalCase FEATURE_NAME}} Processing - ID: {0}")]
|
|
@@ -34,7 +19,6 @@ public class {{pascalCase FEATURE_NAME}}ProcessorJob(
|
|
|
34
19
|
|
|
35
20
|
try
|
|
36
21
|
{
|
|
37
|
-
// Get the entity directly from the DbSet
|
|
38
22
|
var entity = await db.Set<{{pascalCase FEATURE_NAME}}>().FindAsync(new object[] { id }, cancellationToken);
|
|
39
23
|
if (entity is null)
|
|
40
24
|
{
|
|
@@ -42,14 +26,12 @@ public class {{pascalCase FEATURE_NAME}}ProcessorJob(
|
|
|
42
26
|
return;
|
|
43
27
|
}
|
|
44
28
|
|
|
45
|
-
// Check if already processed
|
|
46
29
|
if (entity.Status == {{pascalCase FEATURE_NAME}}Status.Completed)
|
|
47
30
|
{
|
|
48
31
|
logger.LogInformation("{{pascalCase FEATURE_NAME}} {Id} already completed, skipping", id);
|
|
49
32
|
return;
|
|
50
33
|
}
|
|
51
34
|
|
|
52
|
-
// Perform MAF agent analysis (if applicable)
|
|
53
35
|
var analysisData = new {{pascalCase FEATURE_NAME}}Data(entity.Name);
|
|
54
36
|
var analysis = await analyzer.AnalyzeAsync(analysisData, cancellationToken);
|
|
55
37
|
|
|
@@ -57,7 +39,6 @@ public class {{pascalCase FEATURE_NAME}}ProcessorJob(
|
|
|
57
39
|
"{{pascalCase FEATURE_NAME}} {Id} analyzed. Confidence: {Confidence:P0}",
|
|
58
40
|
id, analysis.ConfidenceScore);
|
|
59
41
|
|
|
60
|
-
// Update the tracked entity and persist
|
|
61
42
|
entity.MarkAsCompleted(analysis);
|
|
62
43
|
await db.SaveChangesAsync(cancellationToken);
|
|
63
44
|
|
|
@@ -66,54 +47,17 @@ public class {{pascalCase FEATURE_NAME}}ProcessorJob(
|
|
|
66
47
|
catch (Exception ex)
|
|
67
48
|
{
|
|
68
49
|
logger.LogError(ex, "Failed to process {{pascalCase FEATURE_NAME}} {Id}", id);
|
|
69
|
-
throw; //
|
|
50
|
+
throw; // sem a exceção o Hangfire não aplica o AutomaticRetry
|
|
70
51
|
}
|
|
71
52
|
}
|
|
72
53
|
}
|
|
73
54
|
|
|
74
|
-
// ============================================================
|
|
75
|
-
// RECURRING JOB CONFIGURATION
|
|
76
|
-
// ============================================================
|
|
77
|
-
//
|
|
78
|
-
// For scheduled/recurring jobs, configure in Program.cs:
|
|
79
|
-
//
|
|
80
|
-
// // Run every hour
|
|
81
|
-
// RecurringJob.AddOrUpdate<I{{pascalCase FEATURE_NAME}}ProcessorJob>(
|
|
82
|
-
// "{{kebabCase FEATURE_NAME}}-processor",
|
|
83
|
-
// job => job.ExecuteAsync(0, CancellationToken.None),
|
|
84
|
-
// Cron.Hourly);
|
|
85
|
-
//
|
|
86
|
-
// // Run daily at midnight
|
|
87
|
-
// RecurringJob.AddOrUpdate<I{{pascalCase FEATURE_NAME}}ProcessorJob>(
|
|
88
|
-
// "{{kebabCase FEATURE_NAME}}-daily-processor",
|
|
89
|
-
// job => job.ExecuteAsync(0, CancellationToken.None),
|
|
90
|
-
// Cron.Daily);
|
|
91
|
-
//
|
|
92
|
-
// // Custom cron expression (every 15 minutes)
|
|
93
|
-
// RecurringJob.AddOrUpdate<I{{pascalCase FEATURE_NAME}}ProcessorJob>(
|
|
94
|
-
// "{{kebabCase FEATURE_NAME}}-frequent-processor",
|
|
95
|
-
// job => job.ExecuteAsync(0, CancellationToken.None),
|
|
96
|
-
// "*/15 * * * *");
|
|
97
|
-
//
|
|
98
|
-
// ============================================================
|
|
99
|
-
|
|
100
|
-
// ============================================================
|
|
101
|
-
// BATCH JOB TEMPLATE
|
|
102
|
-
// ============================================================
|
|
103
|
-
|
|
104
|
-
/// <summary>
|
|
105
|
-
/// Batch job for processing multiple {{pascalCase FEATURE_NAME}}s.
|
|
106
|
-
/// Queries pending items via LINQ on the DbSet and enqueues individual jobs.
|
|
107
|
-
/// </summary>
|
|
108
55
|
public class {{pascalCase FEATURE_NAME}}BatchProcessorJob(
|
|
109
56
|
ApplicationDbContext db,
|
|
110
57
|
ILogger<{{pascalCase FEATURE_NAME}}BatchProcessorJob> logger)
|
|
111
58
|
{
|
|
112
|
-
/// <summary>
|
|
113
|
-
/// Processes all pending {{pascalCase FEATURE_NAME}}s.
|
|
114
|
-
/// </summary>
|
|
115
59
|
[AutomaticRetry(Attempts = 1)]
|
|
116
|
-
[Queue("batch")]
|
|
60
|
+
[Queue("batch")] // a fila precisa constar em AddHangfireServer(o => o.Queues), senão ninguém a consome
|
|
117
61
|
[JobDisplayName("{{pascalCase FEATURE_NAME}} Batch Processing")]
|
|
118
62
|
public async Task ProcessAllPendingAsync(CancellationToken cancellationToken)
|
|
119
63
|
{
|
|
@@ -127,7 +71,6 @@ public class {{pascalCase FEATURE_NAME}}BatchProcessorJob(
|
|
|
127
71
|
|
|
128
72
|
foreach (var item in pending)
|
|
129
73
|
{
|
|
130
|
-
// Enqueue individual processing jobs
|
|
131
74
|
BackgroundJob.Enqueue<I{{pascalCase FEATURE_NAME}}ProcessorJob>(
|
|
132
75
|
job => job.ExecuteAsync(item.Id, CancellationToken.None));
|
|
133
76
|
}
|
|
@@ -135,41 +78,3 @@ public class {{pascalCase FEATURE_NAME}}BatchProcessorJob(
|
|
|
135
78
|
logger.LogInformation("Enqueued {Count} processing jobs", pending.Count);
|
|
136
79
|
}
|
|
137
80
|
}
|
|
138
|
-
|
|
139
|
-
// ============================================================
|
|
140
|
-
// HANGFIRE CONFIGURATION
|
|
141
|
-
// ============================================================
|
|
142
|
-
//
|
|
143
|
-
// In Program.cs:
|
|
144
|
-
//
|
|
145
|
-
// // Add Hangfire services
|
|
146
|
-
// builder.Services.AddHangfire(config => config
|
|
147
|
-
// .SetDataCompatibilityLevel(CompatibilityLevel.Version_180)
|
|
148
|
-
// .UseSimpleAssemblyNameTypeSerializer()
|
|
149
|
-
// .UseRecommendedSerializerSettings()
|
|
150
|
-
// .UseSqlServerStorage(connectionString, new SqlServerStorageOptions
|
|
151
|
-
// {
|
|
152
|
-
// CommandBatchMaxTimeout = TimeSpan.FromMinutes(5),
|
|
153
|
-
// SlidingInvisibilityTimeout = TimeSpan.FromMinutes(5),
|
|
154
|
-
// QueuePollInterval = TimeSpan.Zero,
|
|
155
|
-
// UseRecommendedIsolationLevel = true,
|
|
156
|
-
// DisableGlobalLocks = true
|
|
157
|
-
// }));
|
|
158
|
-
//
|
|
159
|
-
// builder.Services.AddHangfireServer(options =>
|
|
160
|
-
// {
|
|
161
|
-
// options.Queues = new[] { "default", "batch" };
|
|
162
|
-
// options.WorkerCount = Environment.ProcessorCount * 2;
|
|
163
|
-
// });
|
|
164
|
-
//
|
|
165
|
-
// // Register jobs (ApplicationDbContext already registered via AddDbContext)
|
|
166
|
-
// builder.Services.AddScoped<I{{pascalCase FEATURE_NAME}}ProcessorJob, {{pascalCase FEATURE_NAME}}ProcessorJob>();
|
|
167
|
-
// builder.Services.AddScoped<{{pascalCase FEATURE_NAME}}BatchProcessorJob>();
|
|
168
|
-
//
|
|
169
|
-
// // In app pipeline
|
|
170
|
-
// app.UseHangfireDashboard("/hangfire", new DashboardOptions
|
|
171
|
-
// {
|
|
172
|
-
// Authorization = new[] { new HangfireAuthorizationFilter() }
|
|
173
|
-
// });
|
|
174
|
-
//
|
|
175
|
-
// ============================================================
|