@polymorphism-tech/morph-spec 8.46.0 → 9.0.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 +53 -44
- package/README.md +3 -4
- package/bin/morph-spec.js +38 -55
- package/bin/validate.js +5 -134
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +2 -2
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +41 -101
- package/framework/MORPH.md +95 -252
- package/framework/agents.json +75 -18
- package/framework/commands/create-umbraco-lp.md +2 -0
- package/framework/commands/migrate-lp-to-umbraco.md +2 -0
- package/framework/commands/morph-apply.md +5 -28
- package/framework/commands/morph-archive.md +2 -2
- package/framework/commands/morph-hotfix.md +8 -8
- package/framework/commands/morph-infra.md +17 -203
- package/framework/commands/morph-media.md +3 -0
- package/framework/commands/morph-preflight.md +7 -31
- package/framework/commands/morph-proposal.md +2 -50
- package/framework/commands/morph-status.md +3 -3
- package/framework/commands/morph-troubleshoot.md +2 -14
- package/framework/docs/CLI.md +585 -286
- package/framework/evals/review-checklist.md +82 -41
- package/framework/hooks/README.md +10 -11
- package/framework/hooks/claude-code/core/comment-guard.js +1 -1
- package/framework/hooks/claude-code/core/denylist.json +33 -3
- package/framework/hooks/claude-code/core/enforce-phase-writes.js +16 -20
- package/framework/hooks/claude-code/core/gate-guard.js +2 -11
- package/framework/hooks/claude-code/core/pre-bash-denylist.js +38 -0
- package/framework/hooks/claude-code/core/protect-spec-files.js +30 -242
- package/framework/hooks/claude-code/core/state-sync.js +17 -19
- package/framework/hooks/claude-code/core/telemetry-log.js +3 -3
- package/framework/hooks/claude-code/core/validate-completion.js +33 -97
- package/framework/hooks/claude-code/core/warn-bash-source-write.js +31 -0
- package/framework/hooks/claude-code/core/worktree-context.js +5 -4
- package/framework/hooks/claude-code/statusline.py +55 -41
- package/framework/hooks/package.json +3 -0
- package/framework/hooks/shared/activity-logger.js +1 -1
- package/framework/hooks/shared/build-check.js +10 -6
- package/framework/hooks/shared/command-tokens.js +169 -0
- package/framework/hooks/shared/comment-rules.js +1 -1
- package/framework/hooks/shared/comment-scanner.js +10 -23
- package/framework/hooks/shared/comment-stripper.js +1 -1
- package/framework/hooks/shared/e2e-check.js +67 -31
- package/framework/hooks/shared/errata.js +72 -0
- package/framework/hooks/shared/feature-locator.js +1 -1
- package/framework/hooks/shared/frontend-locations.js +6 -0
- package/framework/hooks/shared/gate-question.js +18 -0
- package/framework/hooks/shared/phase-utils.js +15 -32
- package/framework/hooks/shared/slice-progress.js +118 -0
- package/framework/hooks/shared/spawn-command.js +23 -0
- package/framework/hooks/shared/state-reader.js +61 -87
- package/framework/hooks/shared/state-writer.js +3 -3
- package/framework/mcp/registry.json +3 -4
- package/framework/phases.json +23 -39
- package/framework/rules/ai-agents-standards.md +18 -16
- package/framework/rules/asaas-standards.md +3 -1
- package/framework/rules/csharp-standards.md +10 -8
- package/framework/rules/data-standards.md +5 -5
- package/framework/rules/dotnet-templates.md +1 -1
- package/framework/rules/frontend-standards.md +4 -2
- package/framework/rules/gsap-standards.md +10 -5
- package/framework/rules/hangfire-standards.md +3 -1
- package/framework/rules/infrastructure-standards.md +4 -2
- package/framework/rules/neon-auth-standards.md +3 -1
- package/framework/rules/neon-standards.md +6 -4
- package/framework/rules/nextjs-standards.md +13 -11
- package/framework/rules/nextjs-templates.md +1 -1
- package/framework/rules/resend-standards.md +3 -1
- package/framework/schemas/config.schema.json +14 -9
- package/framework/schemas/feature.schema.json +15 -52
- package/framework/skills/README.md +4 -5
- package/framework/skills/core/create-umbraco-lp/SKILL.md +3 -3
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +3 -3
- package/framework/skills/core/morph-apply/SKILL.md +150 -223
- package/framework/skills/core/morph-hotfix/SKILL.md +34 -43
- package/framework/skills/core/morph-machine/SKILL.md +4 -4
- package/framework/skills/core/morph-media/SKILL.md +3 -3
- package/framework/skills/core/morph-plan/SKILL.md +138 -300
- package/framework/skills/core/morph-review/SKILL.md +112 -137
- package/framework/skills/core/morph-standards/SKILL.md +29 -41
- package/framework/skills/core/morph-uiux/SKILL.md +78 -153
- package/framework/standards/STANDARDS.json +90 -1219
- package/framework/standards/STANDARDS.meta.json +1305 -0
- package/framework/standards/ai-agents/evals-with-cache.md +2 -3
- package/framework/standards/ai-agents/llm-runtime-defaults.md +1 -1
- package/framework/standards/ai-agents/modalities-speech-to-text.md +36 -26
- package/framework/standards/ai-agents/prompt-sources.md +6 -4
- package/framework/standards/ai-agents/providers/model-registry.md +1 -1
- package/framework/standards/ai-agents/rag-custom-pgvector.md +67 -39
- package/framework/standards/ai-agents/setup.md +2 -2
- package/framework/standards/ai-agents/structured-output.md +1 -1
- package/framework/standards/ai-agents/sweet-spot.md +1 -1
- package/framework/standards/architecture/code-comments.md +8 -8
- package/framework/standards/architecture/vertical-slice/vertical-slice.md +18 -9
- package/framework/standards/backend/api/validation.md +135 -47
- package/framework/standards/backend/database/postgresql/database.md +11 -7
- package/framework/standards/backend/database/vector-search-rag.md +207 -324
- package/framework/standards/backend/dotnet/fluent-validation-vsa.md +14 -8
- package/framework/standards/backend/dotnet/result-pattern.md +40 -6
- package/framework/standards/backend/dotnet/scalar-ui.md +13 -7
- package/framework/standards/backend/dotnet/scrutor.md +1 -1
- package/framework/standards/backend/dotnet/testing.md +1 -1
- package/framework/standards/backend/dotnet/vsa-handler-patterns.md +7 -7
- package/framework/standards/backend/integrations/asaas/asaas-api.md +309 -165
- package/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +134 -154
- package/framework/standards/data/nosql/cache/redis.md +120 -44
- package/framework/standards/data/nosql/cosmos-db.md +114 -71
- package/framework/standards/frontend/design-system/animations.md +1 -1
- package/framework/standards/frontend/design-system/naming.md +1 -1
- package/framework/standards/frontend/nextjs/motion-patterns.md +45 -29
- package/framework/standards/frontend/nextjs/naming-conventions.md +1 -1
- package/framework/standards/infrastructure/docker/coolify-deploy.md +8 -6
- package/framework/standards/infrastructure/neon/neon-pgvector.md +120 -75
- package/framework/standards/infrastructure/neon/neon-setup.md +53 -31
- package/framework/standards/integration/mcp/mcp-tools.md +7 -7
- package/framework/templates/README.md +2 -3
- package/framework/templates/REGISTRY.json +6 -170
- package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +2 -2
- package/framework/templates/code/dotnet/extensions/database-extensions.cs +1 -1
- package/framework/templates/code/dotnet/extensions/result-extensions.cs +27 -0
- package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +2 -2
- package/framework/templates/docs/plan.md +72 -0
- package/framework/templates/dotnet/ai-kit/README.md +1 -9
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +1 -1
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Morph.AiKit.Tests.csproj +0 -10
- package/framework/templates/infrastructure/docker/coolify.template.json +3 -3
- package/framework/templates/infrastructure/github/README.md +2 -1
- package/framework/templates/infrastructure/github/workflows/deploy-coolify.yml.hbs +2 -1
- package/framework/templates/meta-prompts/squad-leaders/backend-squad.md +1 -1
- package/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +1 -1
- package/framework/templates/meta-prompts/squad-leaders/squad-leader.md +1 -1
- package/framework/templates/meta-prompts/validators/pre-commit-validator.md +3 -4
- package/package.json +1 -1
- package/src/commands/e2e/e2e.js +2 -2
- package/src/commands/observability/cost.js +18 -60
- package/src/commands/observability/telemetry.js +3 -5
- package/src/commands/project/doctor-procs.js +1 -1
- package/src/commands/project/doctor.js +9 -9
- package/src/commands/project/fleet.js +4 -4
- package/src/commands/project/heavy.js +3 -3
- package/src/commands/project/init.js +6 -1
- package/src/commands/project/setup-infra-cmd.js +2 -1
- package/src/commands/project/stack-scan.js +58 -0
- package/src/commands/project/standards.js +79 -25
- package/src/commands/project/status.js +29 -69
- package/src/commands/project/update.js +33 -19
- package/src/commands/project/worktree.js +1 -1
- package/src/commands/state/advance.js +62 -46
- package/src/commands/state/approve.js +95 -138
- package/src/commands/state/archive.js +20 -84
- package/src/commands/state/auto-approval.js +68 -0
- package/src/commands/state/create.js +28 -1
- package/src/commands/state/delete.js +1 -1
- package/src/commands/state/finish.js +11 -23
- package/src/commands/state/gate-check.js +86 -95
- package/src/commands/state/gate-decision.js +6 -4
- package/src/commands/state/handoff.js +1 -1
- package/src/commands/state/list.js +9 -9
- package/src/commands/state/report-check.js +157 -311
- package/src/commands/state/retype.js +9 -3
- package/src/commands/validation/mutate.js +77 -14
- package/src/commands/validation/plan-check.js +81 -0
- package/src/commands/validation/validate-feature.js +60 -135
- package/src/commands/validation/verify.js +41 -82
- package/src/core/paths/output-schema.js +20 -67
- package/src/core/state/gate-order.js +5 -6
- package/src/core/state/lifecycle-audit.js +2 -2
- package/src/core/state/state-manager.js +17 -98
- package/src/core/templates/template-registry.js +2 -2
- package/src/core/templates/template-seed.js +22 -0
- package/src/core/work-types.js +10 -10
- package/src/dashboard/app/App.jsx +0 -2
- package/src/dashboard/app/components/ActivityFeed.jsx +2 -3
- package/src/dashboard/app/components/CommandPalette.jsx +7 -8
- package/src/dashboard/app/components/EntityLink.jsx +1 -2
- package/src/dashboard/app/components/Markdown.jsx +1 -1
- package/src/dashboard/app/components/Sidebar.jsx +1 -2
- package/src/dashboard/app/hooks/useMorphQuery.js +1 -1
- package/src/dashboard/app/lib/phases.js +2 -4
- package/src/dashboard/app/pages/Activity.jsx +1 -1
- package/src/dashboard/app/pages/FeatureDetail.jsx +139 -129
- package/src/dashboard/app/pages/Features.jsx +9 -9
- package/src/dashboard/app/pages/Guide.jsx +2 -2
- package/src/dashboard/app/pages/PhasePipeline.jsx +3 -4
- package/src/dashboard/app/pages/RulesMap.jsx +3 -3
- package/src/dashboard/app/pages/SkillsLibrary.jsx +3 -3
- package/src/dashboard/app/pages/Standards.jsx +1 -1
- package/src/dashboard/scanner/activity-scanner.js +6 -16
- package/src/dashboard/scanner/agents-scanner.js +1 -1
- package/src/dashboard/scanner/docs-scanner.js +5 -23
- package/src/dashboard/scanner/features-scanner.js +95 -60
- package/src/dashboard/scanner/index.js +0 -2
- package/src/dashboard/scanner/project-api.js +1 -1
- package/src/dashboard/scanner/rules-scanner.js +15 -10
- package/src/dashboard/scanner/skills-scanner.js +2 -3
- package/src/dashboard/scanner/standards-scanner.js +2 -1
- package/src/lib/ci/ci-verify.js +17 -1
- package/src/lib/ci/github-ci.js +1 -1
- package/src/lib/detectors/index.js +3 -8
- package/src/lib/generators/handoff-generator.js +34 -65
- package/src/lib/generators/settings-generator.js +11 -89
- package/src/lib/git/evidence-staleness.js +1 -1
- package/src/lib/git/tree-fingerprint.js +19 -7
- package/src/lib/git/tree-state.js +2 -2
- package/src/lib/heavy/cleanup.js +1 -5
- package/src/lib/installers/memory-installer.js +6 -8
- package/src/lib/mutation/commands.js +3 -2
- package/src/lib/{tasks/dotnet-test-introspection.js → mutation/dotnet-introspection.js} +17 -282
- package/src/lib/mutation/plan.js +14 -6
- package/src/lib/mutation/runner.js +1 -1
- package/src/lib/mutation/subset.js +46 -9
- package/src/lib/plan/artifact-vocabulary.js +60 -0
- package/src/lib/plan/checks.js +234 -0
- package/src/lib/plan/plan-parser.js +209 -0
- package/src/lib/plan/plan-template.js +18 -0
- package/src/lib/review-reports.js +222 -0
- package/src/lib/risk-detector.js +134 -135
- package/src/lib/specs/adr-index.js +50 -69
- package/src/lib/specs/design-seed.js +18 -0
- package/src/lib/specs/frontmatter.js +44 -0
- package/src/lib/specs/gfm-table.js +17 -0
- package/src/lib/specs/old-format.js +68 -0
- package/src/lib/specs/revocations.js +37 -95
- package/src/lib/specs/screen-checklist.js +18 -17
- package/src/lib/stack/dotnet-build-ignores.js +47 -0
- package/src/lib/stack/stack-profile.js +1 -1
- package/src/lib/stack/stack-scan.js +267 -0
- package/src/lib/standards/registry.js +43 -0
- package/src/lib/standards/sections.js +58 -0
- package/src/lib/tasks/eval-node.js +4 -12
- package/src/lib/tasks/test-nodes.js +1 -74
- package/src/lib/tasks/test-runner.js +75 -117
- package/src/lib/telemetry/metrics.js +8 -69
- package/src/lib/telemetry/telemetry-reader.js +5 -118
- package/src/lib/telemetry/verify-event.js +5 -7
- package/src/lib/validators/code-budget/code-budget-validator.js +1 -1
- package/src/lib/validators/contracts/contract-compliance-validator.js +2 -2
- package/src/lib/validators/reuse/reuse-validator.js +24 -48
- package/src/lib/validators/reuse/symbol-scanner.js +2 -4
- package/src/lib/validators/traceability-check.js +85 -129
- package/src/lib/validators/validation-runner.js +8 -88
- package/src/lib/validators/verify-runner.js +134 -301
- package/src/lib/worktree/docker-audit.js +1 -2
- package/src/lib/worktree/fleet-scanner.js +25 -38
- package/src/scripts/setup-infra.js +42 -22
- package/src/utils/agents-installer.js +92 -13
- package/src/utils/claude-settings-manager.js +0 -35
- package/src/utils/file-copier.js +34 -6
- package/src/utils/hooks-installer.js +16 -9
- package/src/utils/skills-installer.js +1 -2
- package/framework/commands/commit.md +0 -166
- package/framework/evals/trace-schema.md +0 -67
- package/framework/hooks/claude-code/core/tasks-json-guard.js +0 -83
- package/framework/hooks/claude-code/core/trace-autogen.js +0 -277
- package/framework/hooks/git/pre-commit/specs.sh +0 -50
- package/framework/hooks/shared/tasks-validator.js +0 -111
- package/framework/rubrics/backend.json +0 -41
- package/framework/rubrics/default.json +0 -36
- package/framework/rubrics/frontend.json +0 -36
- package/framework/rules/morph-task-tracking.md +0 -54
- package/framework/rules/morph-workflow.md +0 -244
- package/framework/schemas/tasks.schema.json +0 -79
- package/framework/skills/core/morph-brainstorming/SKILL.md +0 -161
- package/framework/skills/core/morph-implement/SKILL.md +0 -194
- package/framework/skills/core/morph-proposal/SKILL.md +0 -152
- package/framework/skills/core/morph-stack-scan/SKILL.md +0 -145
- package/framework/templates/docs/proposal.md +0 -192
- package/framework/templates/docs/spec.md +0 -57
- package/framework/templates/docs/ui-components.md +0 -52
- package/framework/templates/docs/ui-design-system.md +0 -76
- package/framework/templates/docs/ui-flows.md +0 -167
- package/framework/templates/examples/spec-examples.md +0 -91
- package/framework/templates/feature/decisions.md +0 -124
- package/framework/templates/feature/recap.md +0 -145
- package/framework/templates/project/validate.js +0 -97
- package/framework/templates/tasks.template.json +0 -17
- package/src/commands/state/usecase.js +0 -143
- package/src/commands/tasks/dag.js +0 -181
- package/src/dashboard/app/pages/Rubrics.jsx +0 -97
- package/src/dashboard/scanner/rubrics-scanner.js +0 -12
- package/src/lib/agents/output-collector.js +0 -76
- package/src/lib/evaluator-report.js +0 -91
- package/src/lib/specs/acervo-format.js +0 -70
- package/src/lib/specs/acervo-lifecycle.js +0 -264
- package/src/lib/specs/done-criteria-check.js +0 -200
- package/src/lib/specs/usecase-check.js +0 -301
- package/src/lib/specs/usecase-promoter.js +0 -301
- package/src/lib/specs/usecase-registry.js +0 -237
- package/src/lib/tasks/dispatch-planner.js +0 -319
- package/src/lib/tasks/mermaid-renderer.js +0 -132
- package/src/lib/tasks/task-classifier.js +0 -30
- package/src/lib/tasks/task-parser.js +0 -209
- package/src/lib/tasks/tasks-json-parser.js +0 -296
- package/src/lib/tasks/test-scope.js +0 -597
- package/src/lib/validators/architecture/architecture-validator.js +0 -270
- package/src/lib/validators/architecture/index.js +0 -7
- package/src/lib/validators/css/css-validator.js +0 -340
- package/src/lib/validators/css/index.js +0 -7
- package/src/lib/validators/design-system/design-system-validator.js +0 -237
- package/src/lib/validators/design-system/index.js +0 -7
- package/src/lib/validators/score-aggregator.js +0 -244
- package/src/lib/validators/ui/index.js +0 -7
- package/src/lib/validators/ui/ui-contrast-validator.js +0 -422
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
# Spec Template Reference
|
|
2
|
-
|
|
3
|
-
> **Layer:** 3 | **Load:** on-demand | **Keywords:** spec, specification, template
|
|
4
|
-
|
|
5
|
-
**The canonical template is `docs/spec.md` of the template system** (REGISTRY id `spec`),
|
|
6
|
-
resolved from the installed package — see `framework/templates/README.md`.
|
|
7
|
-
|
|
8
|
-
This file contains extended examples for each spec section.
|
|
9
|
-
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
## Example: Entity (Pseudo-code)
|
|
13
|
-
|
|
14
|
-
```csharp
|
|
15
|
-
class ProcessingJob {
|
|
16
|
-
Guid Id
|
|
17
|
-
string OriginalPhotoUrl // Azure Blob URL, max 500 chars
|
|
18
|
-
string? ProcessedPhotoUrl // Nullable, populated after processing
|
|
19
|
-
ProcessingStatus Status // Enum: Pending, Processing, Completed, Failed
|
|
20
|
-
DateTime CreatedAt
|
|
21
|
-
ICollection<ExecutionLog> Logs // 1:N relationship
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
enum ProcessingStatus {
|
|
25
|
-
Pending = 0, Processing = 1, Completed = 2, // Normal flow
|
|
26
|
-
Failed = 100 // Error states (high values)
|
|
27
|
-
}
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
## Example: Command (Pseudo-code)
|
|
31
|
-
|
|
32
|
-
```csharp
|
|
33
|
-
UploadPhotoCommand {
|
|
34
|
-
Input: IFormFile photo, string? email
|
|
35
|
-
Output: Guid jobId
|
|
36
|
-
|
|
37
|
-
Handler:
|
|
38
|
-
1. Validate file (size <= 10MB, type in [.jpg, .png])
|
|
39
|
-
2. Upload to Azure Blob Storage
|
|
40
|
-
3. Create ProcessingJob entity (status = Pending)
|
|
41
|
-
4. Enqueue Hangfire background job
|
|
42
|
-
5. Return jobId
|
|
43
|
-
}
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
## Example: API Endpoints
|
|
47
|
-
|
|
48
|
-
```csharp
|
|
49
|
-
PhotoProcessingController {
|
|
50
|
-
POST /api/upload → multipart/form-data → { jobId: Guid }
|
|
51
|
-
GET /api/status/{id} → jobId → { status, progress, createdAt }
|
|
52
|
-
GET /api/download/{id} → jobId → Redirect to Blob URL or 404
|
|
53
|
-
}
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Example: Flow
|
|
57
|
-
|
|
58
|
-
```
|
|
59
|
-
Upload Flow (Actor: User)
|
|
60
|
-
1. User selects photo → System validates (size, type) → If invalid: show error
|
|
61
|
-
2. User sees preview → clicks "Upload"
|
|
62
|
-
3. System creates ProcessingJob → uploads to Blob → enqueues Hangfire job → returns jobId
|
|
63
|
-
4. System navigates to /processing/{jobId} → polls every 5s
|
|
64
|
-
End State: User on progress page, job processing in background
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## Example: ADR
|
|
68
|
-
|
|
69
|
-
### ADR-001: Use Hangfire for Background Jobs
|
|
70
|
-
**Status:** Accepted
|
|
71
|
-
**Context:** Need background processing for AI photo transformation (30-120s).
|
|
72
|
-
**Decision:** Hangfire (self-hosted).
|
|
73
|
-
**Alternatives:**
|
|
74
|
-
1. Azure Functions — serverless, auto-scaling, but cold start + $10/mo for 50k jobs
|
|
75
|
-
2. Hangfire — zero cost, simpler, but scales with app
|
|
76
|
-
3. Quartz.NET — more features, but steeper learning curve
|
|
77
|
-
**Trade-offs:** Simplicity vs Features (Hangfire sufficient for MVP)
|
|
78
|
-
|
|
79
|
-
## Example: Cost Estimate
|
|
80
|
-
|
|
81
|
-
| Resource | SKU | Monthly | Justification |
|
|
82
|
-
|----------|-----|---------|---------------|
|
|
83
|
-
| Blob Storage | LRS | $0.02 | Store photos, low redundancy OK |
|
|
84
|
-
| Azure SQL | Basic | $4.99 | < 100k jobs/month |
|
|
85
|
-
| Container App | Consumption | $0.49 | Scale to zero |
|
|
86
|
-
| Hangfire | Self-hosted | $0.00 | In-process |
|
|
87
|
-
| **Total** | | **~$5.50** | |
|
|
88
|
-
|
|
89
|
-
---
|
|
90
|
-
|
|
91
|
-
*MORPH-SPEC by Polymorphism Tech*
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
# Architecture Decision Records - {{titleCase FEATURE_NAME}}
|
|
2
|
-
|
|
3
|
-
## ADR-001: {Decision Title}
|
|
4
|
-
|
|
5
|
-
**Date:** {{DATE}}
|
|
6
|
-
**Status:** Proposed | Accepted | Deprecated | Superseded
|
|
7
|
-
**Deciders:** MORPH Agents, Developer
|
|
8
|
-
**Alcance:** feature
|
|
9
|
-
|
|
10
|
-
### Context
|
|
11
|
-
|
|
12
|
-
{Describe the context and problem that led to this decision}
|
|
13
|
-
|
|
14
|
-
### Decision
|
|
15
|
-
|
|
16
|
-
{Describe the decision made}
|
|
17
|
-
|
|
18
|
-
### Consequences
|
|
19
|
-
|
|
20
|
-
**Pros:**
|
|
21
|
-
- {Positive consequence 1}
|
|
22
|
-
- {Positive consequence 2}
|
|
23
|
-
|
|
24
|
-
**Cons:**
|
|
25
|
-
- {Negative consequence 1}
|
|
26
|
-
|
|
27
|
-
**Risks:**
|
|
28
|
-
- {Identified risk}
|
|
29
|
-
|
|
30
|
-
### Alternatives Considered
|
|
31
|
-
|
|
32
|
-
#### Option A: {Name}
|
|
33
|
-
- Pros: {advantages}
|
|
34
|
-
- Cons: {disadvantages}
|
|
35
|
-
- **Rejected because:** {reason}
|
|
36
|
-
|
|
37
|
-
#### Option B: {Name}
|
|
38
|
-
- Pros: {advantages}
|
|
39
|
-
- Cons: {disadvantages}
|
|
40
|
-
- **Rejected because:** {reason}
|
|
41
|
-
|
|
42
|
-
---
|
|
43
|
-
|
|
44
|
-
{{#if (eq STACK "nextjs-neon")}}
|
|
45
|
-
## ADR-002: Database Access Strategy
|
|
46
|
-
|
|
47
|
-
**Date:** {{DATE}}
|
|
48
|
-
**Status:** Accepted
|
|
49
|
-
|
|
50
|
-
### Context
|
|
51
|
-
|
|
52
|
-
Need to decide how the .NET API accesses Neon PostgreSQL.
|
|
53
|
-
|
|
54
|
-
### Decision
|
|
55
|
-
|
|
56
|
-
Use Dapper with Npgsql for direct SQL queries. No EF Core.
|
|
57
|
-
|
|
58
|
-
### Consequences
|
|
59
|
-
|
|
60
|
-
**Pros:**
|
|
61
|
-
- Full control over SQL queries
|
|
62
|
-
- Better performance (no ORM overhead)
|
|
63
|
-
- Direct access to PostgreSQL features (jsonb, pgvector, functions)
|
|
64
|
-
- RLS policies apply naturally through connection
|
|
65
|
-
|
|
66
|
-
**Cons:**
|
|
67
|
-
- No automatic migrations (use Neon CLI / dotnet ef instead)
|
|
68
|
-
- Manual SQL query writing
|
|
69
|
-
- No change tracking
|
|
70
|
-
|
|
71
|
-
---
|
|
72
|
-
|
|
73
|
-
## ADR-003: Auth Strategy
|
|
74
|
-
|
|
75
|
-
**Date:** {{DATE}}
|
|
76
|
-
**Status:** Accepted
|
|
77
|
-
|
|
78
|
-
### Context
|
|
79
|
-
|
|
80
|
-
Need authentication for both Next.js frontend and .NET API.
|
|
81
|
-
|
|
82
|
-
### Decision
|
|
83
|
-
|
|
84
|
-
Use Neon Auth (Better Auth) for authentication. Auth data lives in the Neon database. JWT validated by .NET API middleware.
|
|
85
|
-
|
|
86
|
-
### Consequences
|
|
87
|
-
|
|
88
|
-
**Pros:**
|
|
89
|
-
- Auth data in same database — no external provider, no sync delays
|
|
90
|
-
- RLS policies work with Neon Auth JWT via auth.user_id() / pg_session_jwt
|
|
91
|
-
- Built-in social login, email/password via @neondatabase/auth SDK
|
|
92
|
-
- Branch isolation — each Neon branch gets isolated auth data
|
|
93
|
-
- No webhooks needed — query neon_auth schema directly
|
|
94
|
-
|
|
95
|
-
**Cons:**
|
|
96
|
-
- Neon Auth is currently in Beta
|
|
97
|
-
- JWT must be forwarded to .NET API for backend auth
|
|
98
|
-
{{/if}}
|
|
99
|
-
|
|
100
|
-
---
|
|
101
|
-
|
|
102
|
-
## Template for New ADRs
|
|
103
|
-
|
|
104
|
-
```markdown
|
|
105
|
-
## ADR-XXX: {Title}
|
|
106
|
-
|
|
107
|
-
**Date:**
|
|
108
|
-
**Status:** Proposed | Accepted | Deprecated | Superseded
|
|
109
|
-
**Alcance:** feature | projeto — `projeto` when the rule holds beyond this feature: `morph-spec finish` copies it to `.morph/specs/adrs/`, the folder brainstorming and plan read instead of archived decisions.md
|
|
110
|
-
|
|
111
|
-
### Context
|
|
112
|
-
{Why is this decision needed?}
|
|
113
|
-
|
|
114
|
-
### Decision
|
|
115
|
-
{What was decided?}
|
|
116
|
-
|
|
117
|
-
### Consequences
|
|
118
|
-
**Pros:** {list}
|
|
119
|
-
**Cons:** {list}
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
---
|
|
123
|
-
|
|
124
|
-
*Generated by MORPH Framework*
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
# Feature Recap: {{titleCase FEATURE_NAME}}
|
|
2
|
-
|
|
3
|
-
## Summary
|
|
4
|
-
|
|
5
|
-
| Field | Value |
|
|
6
|
-
|-------|-------|
|
|
7
|
-
| **Feature ID** | {{FEATURE_NAME}} |
|
|
8
|
-
| **Completed** | {{DATE}} |
|
|
9
|
-
| **Total Tasks** | {X} |
|
|
10
|
-
| **Time Spent** | {X}h |
|
|
11
|
-
| **Agents Used** | {list} |
|
|
12
|
-
{{#if STACK}}| **Stack** | {{STACK}} |{{/if}}
|
|
13
|
-
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
## Tasks Completed
|
|
17
|
-
|
|
18
|
-
| ID | Title | Category | Duration |
|
|
19
|
-
|----|-------|----------|----------|
|
|
20
|
-
| T001 | {title} | {{#if (eq STACK "nextjs-neon")}}Database{{else}}{category}{{/if}} | {X}min |
|
|
21
|
-
| T002 | {title} | {{#if (eq STACK "nextjs-neon")}}Backend{{else}}{category}{{/if}} | {X}min |
|
|
22
|
-
| T003 | {title} | {{#if (eq STACK "nextjs-neon")}}Frontend{{else}}{category}{{/if}} | {X}min |
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
{{#if (eq STACK "nextjs-neon")}}
|
|
27
|
-
## Validation Results
|
|
28
|
-
|
|
29
|
-
| Validator | Status | Details |
|
|
30
|
-
|-----------|--------|---------|
|
|
31
|
-
| contract-compliance | Pass/Fail | {details} |
|
|
32
|
-
| architecture | Pass/Fail | {details} |
|
|
33
|
-
| design-system | Pass/Fail | {details} |
|
|
34
|
-
| coding-standards | Pass/Fail | {details} |
|
|
35
|
-
|
|
36
|
-
---
|
|
37
|
-
|
|
38
|
-
{{/if}}
|
|
39
|
-
## What Was Delivered
|
|
40
|
-
|
|
41
|
-
### Functionality
|
|
42
|
-
- {Functionality 1 delivered}
|
|
43
|
-
- {Functionality 2 delivered}
|
|
44
|
-
- {Functionality 3 delivered}
|
|
45
|
-
|
|
46
|
-
{{#if (eq STACK "nextjs-neon")}}
|
|
47
|
-
### Database (Neon PostgreSQL)
|
|
48
|
-
- Tables: {list}
|
|
49
|
-
- RLS Policies: {count} policies
|
|
50
|
-
- Migrations: {count} files
|
|
51
|
-
|
|
52
|
-
### Backend API (.NET)
|
|
53
|
-
- Endpoints: {count} endpoints
|
|
54
|
-
- Services: {list}
|
|
55
|
-
|
|
56
|
-
### Frontend (Next.js)
|
|
57
|
-
- Pages: {list}
|
|
58
|
-
- Components: {list}
|
|
59
|
-
{{/if}}
|
|
60
|
-
|
|
61
|
-
---
|
|
62
|
-
|
|
63
|
-
## Files Created
|
|
64
|
-
|
|
65
|
-
```
|
|
66
|
-
{{#if (eq STACK "nextjs-neon")}}
|
|
67
|
-
migrations/{files}
|
|
68
|
-
backend/src/{files}
|
|
69
|
-
frontend/src/{files}
|
|
70
|
-
{{else}}
|
|
71
|
-
{list of created files}
|
|
72
|
-
{{/if}}
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## Files Modified
|
|
76
|
-
|
|
77
|
-
```
|
|
78
|
-
{list of modified files}
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## Architecture Decisions
|
|
84
|
-
|
|
85
|
-
| Decision | Rationale |
|
|
86
|
-
|----------|-----------|
|
|
87
|
-
| {Decision 1} | {Reason} |
|
|
88
|
-
| {Decision 2} | {Reason} |
|
|
89
|
-
|
|
90
|
-
See full ADRs in `decisions.md`
|
|
91
|
-
|
|
92
|
-
---
|
|
93
|
-
|
|
94
|
-
## Test Coverage
|
|
95
|
-
|
|
96
|
-
| Type | Files | Coverage |
|
|
97
|
-
|------|-------|----------|
|
|
98
|
-
| {{#if (eq STACK "nextjs-neon")}}Backend Unit{{else}}Unit Tests{{/if}} | {X} | {X}% |
|
|
99
|
-
| {{#if (eq STACK "nextjs-neon")}}Frontend Component{{else}}Integration Tests{{/if}} | {X} | {X}% |
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
## Lessons Learned
|
|
104
|
-
|
|
105
|
-
### What Went Well
|
|
106
|
-
- {Positive point 1}
|
|
107
|
-
- {Positive point 2}
|
|
108
|
-
|
|
109
|
-
### What Could Be Improved
|
|
110
|
-
- {Improvement point 1}
|
|
111
|
-
- {Improvement point 2}
|
|
112
|
-
|
|
113
|
-
### Recommendations for Future
|
|
114
|
-
- {Recommendation 1}
|
|
115
|
-
- {Recommendation 2}
|
|
116
|
-
|
|
117
|
-
---
|
|
118
|
-
|
|
119
|
-
## Metrics
|
|
120
|
-
|
|
121
|
-
| Metric | Value |
|
|
122
|
-
|--------|-------|
|
|
123
|
-
| Tasks Completed | {X}/{X} |
|
|
124
|
-
| Checkpoints Passed | {X} |
|
|
125
|
-
{{#if (eq STACK "nextjs-neon")}}| Validation Passes | {X}/{X} |
|
|
126
|
-
{{else}}| Code Reviews | {X} |
|
|
127
|
-
{{/if}}| Bugs Found | {X} |
|
|
128
|
-
| Bugs Fixed | {X} |
|
|
129
|
-
|
|
130
|
-
---
|
|
131
|
-
|
|
132
|
-
## Related Resources
|
|
133
|
-
|
|
134
|
-
- **Proposal:** `proposal.md`
|
|
135
|
-
- **Spec:** `spec.md`
|
|
136
|
-
{{#if (eq STACK "nextjs-neon")}}- **Contracts (.NET):** `contracts.cs`
|
|
137
|
-
- **Contracts (TS):** `contracts.ts`
|
|
138
|
-
{{else}}- **Contracts:** `contracts.cs`
|
|
139
|
-
{{/if}}- **Tasks:** `tasks.json`
|
|
140
|
-
- **Decisions:** `decisions.md`
|
|
141
|
-
- **PR:** {link}
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
*Generated by MORPH Framework on {{DATE}}*
|
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
const validator = process.argv[2];
|
|
4
|
-
const isJson = process.argv.includes('--json');
|
|
5
|
-
|
|
6
|
-
if (!validator) {
|
|
7
|
-
console.error('Usage: node bin/validate.js <validator> [--json]');
|
|
8
|
-
process.exit(1);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const { execSync } = await import('child_process');
|
|
12
|
-
const { existsSync } = await import('fs');
|
|
13
|
-
const { join } = await import('path');
|
|
14
|
-
|
|
15
|
-
const cwd = process.cwd();
|
|
16
|
-
|
|
17
|
-
const results = {
|
|
18
|
-
validator,
|
|
19
|
-
errors: 0,
|
|
20
|
-
warnings: 0,
|
|
21
|
-
passed: true,
|
|
22
|
-
issues: [],
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
function runCommand(cmd, options = {}) {
|
|
26
|
-
try {
|
|
27
|
-
const stdout = execSync(cmd, { cwd, stdio: ['pipe', 'pipe', 'pipe'], ...options }).toString();
|
|
28
|
-
return { success: true, stdout, stderr: '' };
|
|
29
|
-
} catch (err) {
|
|
30
|
-
return {
|
|
31
|
-
success: false,
|
|
32
|
-
stdout: err.stdout?.toString() || '',
|
|
33
|
-
stderr: err.stderr?.toString() || err.message,
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
const hasFrontend = existsSync(join(cwd, 'src/frontend')) || existsSync(join(cwd, 'frontend'));
|
|
39
|
-
const hasBackend = existsSync(join(cwd, 'src/backend')) || existsSync(join(cwd, 'backend'));
|
|
40
|
-
const hasSln = existsSync(join(cwd, 'src/backend/backend.sln')) ||
|
|
41
|
-
existsSync(join(cwd, 'src/backend/Backend.sln'));
|
|
42
|
-
|
|
43
|
-
const frontendDir = existsSync(join(cwd, 'src/frontend')) ? 'src/frontend' : 'frontend';
|
|
44
|
-
const backendDir = existsSync(join(cwd, 'src/backend')) ? 'src/backend' : 'backend';
|
|
45
|
-
|
|
46
|
-
switch (validator) {
|
|
47
|
-
case 'architecture': {
|
|
48
|
-
if (hasBackend && hasSln) {
|
|
49
|
-
const slnFile = hasSln ? (
|
|
50
|
-
existsSync(join(cwd, 'src/backend/backend.sln')) ? 'backend.sln' : 'Backend.sln'
|
|
51
|
-
) : '.';
|
|
52
|
-
const result = runCommand(`dotnet build ${slnFile} --no-restore -warnaserror`, { cwd: join(cwd, backendDir) });
|
|
53
|
-
if (!result.success) {
|
|
54
|
-
results.errors++;
|
|
55
|
-
results.passed = false;
|
|
56
|
-
results.issues.push({ level: 'error', message: `dotnet build failed: ${result.stderr.split('\n')[0]}` });
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
break;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
case 'nextjs-component':
|
|
63
|
-
case 'packages':
|
|
64
|
-
case 'design-system': {
|
|
65
|
-
if (hasFrontend) {
|
|
66
|
-
const result = runCommand('npx tsc --noEmit', { cwd: join(cwd, frontendDir) });
|
|
67
|
-
if (!result.success) {
|
|
68
|
-
results.errors++;
|
|
69
|
-
results.passed = false;
|
|
70
|
-
results.issues.push({ level: 'error', message: `TypeScript errors found. Run: npx tsc --noEmit` });
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
break;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
case 'ui-contrast':
|
|
77
|
-
case 'css': {
|
|
78
|
-
results.issues.push({ level: 'info', message: `${validator} requires manual review` });
|
|
79
|
-
break;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
default:
|
|
83
|
-
results.issues.push({ level: 'warning', message: `Unknown validator: ${validator}` });
|
|
84
|
-
break;
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (isJson) {
|
|
88
|
-
console.log(JSON.stringify(results, null, 2));
|
|
89
|
-
} else {
|
|
90
|
-
const icon = results.passed ? '✅' : '❌';
|
|
91
|
-
console.log(`${icon} Validator: ${validator} — ${results.passed ? 'PASSED' : `FAILED (${results.errors} errors)`}`);
|
|
92
|
-
for (const issue of results.issues) {
|
|
93
|
-
console.log(` [${issue.level}] ${issue.message}`);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
process.exit(results.passed ? 0 : 1);
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": "1.0",
|
|
3
|
-
"feature": "{{featureName}}",
|
|
4
|
-
"tasks": [
|
|
5
|
-
{
|
|
6
|
-
"id": "T1",
|
|
7
|
-
"title": "Example task title",
|
|
8
|
-
"description": "What this task accomplishes and why",
|
|
9
|
-
"dependencies": [],
|
|
10
|
-
"effort": "M",
|
|
11
|
-
"doneCriteria": "Verifiable acceptance condition stated in one sentence",
|
|
12
|
-
"status": "pending",
|
|
13
|
-
"outputs": [],
|
|
14
|
-
"group": "backend"
|
|
15
|
-
}
|
|
16
|
-
]
|
|
17
|
-
}
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `morph-spec usecase reserve [--count <n>] [--feature <name>] [--json]` —
|
|
3
|
-
* atomically mint the next N `UC-{nn}` numbers, shared across every worktree
|
|
4
|
-
* of this repo. See `usecase-registry.js` for why this exists (worktrees only
|
|
5
|
-
* ever see their own tree, so an independent max+1 scan collides).
|
|
6
|
-
*
|
|
7
|
-
* `--feature` is more than an audit label: `usecase-promoter.js`'s collision
|
|
8
|
-
* guard uses the reservation record to tell a legitimate cross-feature
|
|
9
|
-
* correction (never reserved — reusing a published number by design) from an
|
|
10
|
-
* accidental collision (both features reserved the same id). Passing it is
|
|
11
|
-
* how `morph-plan` gets that protection; omitting it degrades to "reserved,
|
|
12
|
-
* no owner recorded" — still collision-free, just unable to name the
|
|
13
|
-
* conflicting feature if one ever surfaces.
|
|
14
|
-
*
|
|
15
|
-
* `morph-spec usecase check <feature>` — see `usecaseCheckCommand` below.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
|
-
import chalk from 'chalk';
|
|
19
|
-
import { existsSync, readdirSync } from 'fs';
|
|
20
|
-
import { join } from 'path';
|
|
21
|
-
import { resolveGitCommonDir } from '../../../framework/hooks/shared/git-paths.js';
|
|
22
|
-
import { reserveUseCases } from '../../lib/specs/usecase-registry.js';
|
|
23
|
-
import { checkUseCases } from '../../lib/specs/usecase-check.js';
|
|
24
|
-
import { checkLifecycle } from '../../lib/specs/acervo-lifecycle.js';
|
|
25
|
-
import { parseTasksJsonLenient } from '../../lib/tasks/tasks-json-parser.js';
|
|
26
|
-
import { isValidFeatureName } from '../project/worktree.js';
|
|
27
|
-
import { printLifecycleWarnings } from '../tasks/dag.js';
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Best-effort feature-name inference when `--feature` is omitted: only when
|
|
31
|
-
* exactly one active feature exists is the guess unambiguous. Anything else
|
|
32
|
-
* (zero, or more than one) is left null rather than guessed wrong — a wrong
|
|
33
|
-
* guess would poison the collision guard's provenance record.
|
|
34
|
-
*/
|
|
35
|
-
function inferActiveFeature(cwd) {
|
|
36
|
-
const featuresDir = join(cwd, '.morph', 'features');
|
|
37
|
-
try {
|
|
38
|
-
if (!existsSync(featuresDir)) return null;
|
|
39
|
-
const entries = readdirSync(featuresDir, { withFileTypes: true }).filter((e) => e.isDirectory());
|
|
40
|
-
return entries.length === 1 ? entries[0].name : null;
|
|
41
|
-
} catch {
|
|
42
|
-
return null;
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* @param {{ count?: string, feature?: string, json?: boolean, cwd?: string }} [options]
|
|
48
|
-
*/
|
|
49
|
-
export function usecaseReserveCommand(options = {}) {
|
|
50
|
-
const cwd = options.cwd || process.cwd();
|
|
51
|
-
const count = Number.parseInt(options.count, 10);
|
|
52
|
-
const n = Number.isInteger(count) && count > 0 ? count : 1;
|
|
53
|
-
const feature = options.feature || inferActiveFeature(cwd) || null;
|
|
54
|
-
|
|
55
|
-
let gitCommonDir = null;
|
|
56
|
-
try { gitCommonDir = resolveGitCommonDir(cwd); } catch { gitCommonDir = null; }
|
|
57
|
-
|
|
58
|
-
let result;
|
|
59
|
-
try {
|
|
60
|
-
result = reserveUseCases(cwd, { feature, count: n, gitCommonDir });
|
|
61
|
-
} catch (error) {
|
|
62
|
-
if (options.json) {
|
|
63
|
-
console.log(JSON.stringify({ reserved: false, error: error.message }));
|
|
64
|
-
process.exit(1);
|
|
65
|
-
}
|
|
66
|
-
console.error(chalk.red(`\n❌ ${error.message}\n`));
|
|
67
|
-
process.exit(1);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const warning = gitCommonDir
|
|
71
|
-
? null
|
|
72
|
-
: 'projeto fora de um repositório git — numeração protegida só localmente; paralelismo entre worktrees NÃO está garantido.';
|
|
73
|
-
|
|
74
|
-
if (options.json) {
|
|
75
|
-
console.log(JSON.stringify({ reserved: true, ...result, feature, warning }));
|
|
76
|
-
process.exit(0);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
console.log(chalk.green(`\n✅ Reservado: ${result.numbers.join(' ')}`));
|
|
80
|
-
if (feature) console.log(chalk.gray(` feature: ${feature}`));
|
|
81
|
-
if (warning) console.log(chalk.yellow(`⚠️ ${warning}\n`));
|
|
82
|
-
else console.log('');
|
|
83
|
-
process.exit(0);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* `morph-spec usecase check <feature> [--json]` — the use-case half of `dag`,
|
|
88
|
-
* runnable before `tasks.json` exists: the feature's use cases and the
|
|
89
|
-
* revocations its `spec.md` declares, against the acervo's lifecycle. With a
|
|
90
|
-
* `tasks.json`, also the task → use case plumbing `dag` checks.
|
|
91
|
-
*
|
|
92
|
-
* Exit 1 only for what `dag` also refuses (a task pointing at a use case that
|
|
93
|
-
* does not exist, a tasks.json that does not validate); lifecycle findings are
|
|
94
|
-
* warnings.
|
|
95
|
-
*
|
|
96
|
-
* @param {string} feature
|
|
97
|
-
* @param {{ json?: boolean, cwd?: string }} [options]
|
|
98
|
-
*/
|
|
99
|
-
export async function usecaseCheckCommand(feature, options = {}) {
|
|
100
|
-
const cwd = options.cwd || process.cwd();
|
|
101
|
-
const fail = (error) => {
|
|
102
|
-
if (options.json) console.log(JSON.stringify({ feature, error }));
|
|
103
|
-
else console.error(chalk.red(`\n❌ ${error}\n`));
|
|
104
|
-
process.exit(1);
|
|
105
|
-
};
|
|
106
|
-
|
|
107
|
-
if (!isValidFeatureName(feature)) fail(`nome de feature inválido: "${feature}"`);
|
|
108
|
-
const featureDir = join(cwd, '.morph', 'features', feature);
|
|
109
|
-
if (!existsSync(featureDir)) fail(`feature não encontrada: .morph/features/${feature}`);
|
|
110
|
-
|
|
111
|
-
const tasksPath = join(featureDir, '2-plan', 'tasks.json');
|
|
112
|
-
let tasksData = null;
|
|
113
|
-
if (existsSync(tasksPath)) {
|
|
114
|
-
try {
|
|
115
|
-
({ data: tasksData } = await parseTasksJsonLenient(tasksPath));
|
|
116
|
-
} catch (error) {
|
|
117
|
-
fail(`tasks.json inválido: ${error.message}`);
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const useCases = tasksData ? checkUseCases(tasksData, join(featureDir, '2-plan', 'usecases')) : null;
|
|
122
|
-
const lifecycle = checkLifecycle({ cwd, featureDir, tasksData });
|
|
123
|
-
const broken = useCases?.errors.length > 0;
|
|
124
|
-
|
|
125
|
-
if (options.json) {
|
|
126
|
-
console.log(JSON.stringify({ feature, useCases, lifecycle }, null, 2));
|
|
127
|
-
process.exit(broken ? 1 : 0);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
if (broken) {
|
|
131
|
-
console.error(chalk.red(`\n❌ Use cases — ${useCases.errors.length} erro(s)\n`));
|
|
132
|
-
for (const e of useCases.errors) console.error(chalk.red(` ${e}`));
|
|
133
|
-
}
|
|
134
|
-
if (useCases?.warnings.length) {
|
|
135
|
-
console.error(chalk.yellow(`\n⚠ Use cases — ${useCases.warnings.length} aviso(s)`));
|
|
136
|
-
for (const w of useCases.warnings) console.error(chalk.yellow(` ${w}`));
|
|
137
|
-
}
|
|
138
|
-
printLifecycleWarnings(lifecycle);
|
|
139
|
-
if (!broken && !useCases?.warnings.length && !lifecycle.warnings.length) {
|
|
140
|
-
console.log(chalk.green(`\n✅ ${feature}: use cases e acervo sem achados\n`));
|
|
141
|
-
}
|
|
142
|
-
process.exit(broken ? 1 : 0);
|
|
143
|
-
}
|