@polymorphism-tech/morph-spec 4.12.0 → 4.14.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 +7 -7
- package/README.md +28 -34
- package/bin/morph-spec.js +41 -24
- package/bin/task-manager.js +962 -1341
- package/bin/validate.js +1 -1
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +14 -16
- package/docs/QUICKSTART.md +15 -15
- package/framework/CLAUDE.md +5 -2
- package/framework/agents/README.md +3 -4
- package/framework/agents/ai-agents/ai-system-architect.md +6 -10
- package/framework/agents/architecture/seo-growth-hacker.md +166 -326
- package/framework/agents/architecture/standards-architect.md +21 -31
- package/framework/agents/backend/dotnet-senior.md +160 -86
- package/framework/agents/backend/ef-modeler.md +2 -6
- package/framework/agents/backend/hangfire-orchestrator.md +8 -9
- package/framework/agents/backend/ms-agent-expert.md +1 -1
- package/framework/agents/frontend/nextjs-expert.md +198 -133
- package/framework/agents/frontend/ui-ux-designer.md +226 -267
- package/framework/agents/infrastructure/infra-architect.md +191 -27
- package/framework/agents/integrations/clerk-auth.md +19 -26
- package/framework/agents/integrations/hangfire-integration.md +1 -4
- package/framework/agents.json +1084 -2278
- package/framework/commands/morph-apply.md +4 -6
- package/framework/commands/morph-preflight.md +192 -269
- package/framework/commands/morph-proposal.md +210 -238
- package/framework/commands/morph-status.md +72 -92
- package/framework/commands/morph-troubleshoot.md +6 -13
- package/framework/hooks/README.md +1 -6
- package/framework/hooks/claude-code/post-tool-use/validator-feedback.js +4 -6
- package/framework/hooks/claude-code/pre-compact/save-morph-context.js +12 -7
- package/framework/hooks/claude-code/pre-tool-use/enforce-phase-writes.js +2 -2
- package/framework/hooks/claude-code/pre-tool-use/protect-spec-files.js +2 -2
- package/framework/hooks/claude-code/pre-tool-use/task-tracking-guard.js +5 -10
- package/framework/hooks/claude-code/session-start/inject-morph-context.js +63 -30
- package/framework/hooks/claude-code/session-start/resume-context.js +77 -0
- package/framework/hooks/claude-code/statusline.py +4 -5
- package/framework/hooks/claude-code/stop/validate-completion.js +4 -4
- package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +8 -8
- package/framework/hooks/shared/compact-restore.js +28 -5
- package/framework/hooks/shared/phase-utils.js +4 -8
- package/framework/hooks/shared/state-reader.js +34 -3
- package/framework/phases.json +162 -200
- package/framework/rules/ai-agents-standards.md +15 -0
- package/framework/rules/asaas-standards.md +13 -0
- package/framework/rules/clerk-standards.md +13 -0
- package/framework/rules/csharp-standards.md +8 -4
- package/framework/rules/data-standards.md +18 -0
- package/framework/rules/dotnet-templates.md +87 -0
- package/framework/rules/frontend-standards.md +13 -13
- package/framework/rules/hangfire-standards.md +13 -0
- package/framework/rules/infrastructure-standards.md +27 -16
- package/framework/rules/morph-workflow.md +73 -13
- package/framework/rules/nextjs-standards.md +1 -0
- package/framework/rules/nextjs-templates.md +40 -0
- package/framework/rules/resend-standards.md +12 -0
- package/framework/rules/supabase-standards.md +29 -0
- package/framework/skills/README.md +6 -8
- package/framework/skills/level-0-meta/mcp-registry.json +21 -99
- package/framework/{standards/ai-agents/team-orchestration.md → skills/level-0-meta/morph-agent-teams/SKILL.md} +472 -479
- package/framework/skills/level-0-meta/morph-brainstorming/SKILL.md +28 -1
- package/framework/skills/level-0-meta/morph-checklist/SKILL.md +2 -2
- package/framework/skills/level-0-meta/morph-code-review/SKILL.md +1 -5
- package/framework/skills/level-0-meta/morph-code-review/scripts/scan-csharp.mjs +1 -1
- package/framework/skills/level-0-meta/morph-frontend-review/SKILL.md +23 -41
- package/framework/skills/level-0-meta/morph-init/SKILL.md +18 -14
- package/framework/skills/level-0-meta/morph-parallel-dispatch/SKILL.md +225 -0
- package/framework/skills/level-0-meta/morph-post-implementation/SKILL.md +20 -0
- package/framework/skills/level-0-meta/morph-tool-usage-guide/SKILL.md +4 -8
- package/framework/skills/level-0-meta/morph-tool-usage-guide/references/tools-per-phase.md +15 -59
- package/framework/skills/level-0-meta/morph-verification-before-completion/SKILL.md +7 -19
- package/framework/skills/level-0-meta/morph-verification-before-completion/scripts/check-phase-outputs.mjs +8 -8
- package/framework/skills/level-1-workflows/README.md +1 -1
- package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +49 -50
- package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +57 -123
- package/framework/skills/level-1-workflows/morph-phase-design/references/architecture-analysis-guide.md +5 -50
- package/framework/skills/level-1-workflows/morph-phase-design/references/spec-example.md +1 -1
- package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +127 -159
- package/framework/skills/level-1-workflows/morph-phase-implement/prompts/code-quality-reviewer-prompt.md +1 -1
- package/framework/skills/level-1-workflows/morph-phase-implement/prompts/implementer-prompt.md +4 -3
- package/framework/skills/level-1-workflows/morph-phase-implement/prompts/spec-reviewer-prompt.md +2 -2
- package/framework/skills/level-1-workflows/morph-phase-implement/references/recap-example.md +1 -1
- package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +17 -13
- package/framework/skills/level-1-workflows/morph-phase-tasks/SKILL.md +22 -40
- package/framework/skills/level-1-workflows/morph-phase-tasks/references/task-planning-patterns.md +143 -172
- package/framework/skills/level-1-workflows/morph-phase-tasks/references/tasks-example.md +5 -5
- package/framework/skills/level-1-workflows/morph-phase-uiux/SKILL.md +57 -77
- package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +1 -1
- package/framework/squad-templates/backend-only.json +6 -6
- package/framework/squad-templates/frontend-only.json +17 -8
- package/framework/squad-templates/full-stack.json +29 -24
- package/framework/standards/STANDARDS.json +1021 -2369
- package/framework/standards/backend/dotnet/fluent-validation-vsa.md +200 -0
- package/framework/standards/backend/dotnet/result-pattern.md +213 -0
- package/framework/standards/backend/dotnet/scalar-ui.md +172 -0
- package/framework/standards/backend/dotnet/scrutor.md +158 -0
- package/framework/standards/backend/dotnet/vsa-handler-patterns.md +274 -0
- package/framework/standards/frontend/nextjs/motion-patterns.md +1 -1
- package/framework/standards/infrastructure/supabase/mcp-setup.md +83 -193
- package/framework/standards/integration/mcp/mcp-tools.md +91 -77
- package/framework/templates/IDE-SNIPPETS.md +2 -6
- package/framework/templates/README.md +709 -814
- package/framework/templates/REGISTRY.json +223 -762
- package/framework/templates/code/dotnet/abstractions/api-endpoint.cs +7 -0
- package/framework/templates/code/dotnet/abstractions/error.cs +60 -0
- package/framework/templates/code/dotnet/abstractions/handler.cs +12 -0
- package/framework/templates/code/dotnet/abstractions/result.cs +74 -0
- package/framework/templates/code/dotnet/backend/repository.cs +148 -141
- package/framework/templates/code/dotnet/constants/api-tags.cs +6 -0
- package/framework/templates/code/dotnet/exceptions/exception-handler.cs +32 -0
- package/framework/templates/code/dotnet/extensions/database-extensions.cs +20 -0
- package/framework/templates/code/dotnet/extensions/handler-registration.cs +38 -0
- package/framework/templates/code/dotnet/extensions/health-checks.cs +24 -0
- package/framework/templates/code/dotnet/extensions/map-endpoints.cs +35 -0
- package/framework/templates/code/dotnet/extensions/result-extensions.cs +29 -0
- package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +21 -0
- package/framework/templates/code/dotnet/feature/entity.cs.hbs +8 -0
- package/framework/templates/code/dotnet/feature/errors.cs.hbs +8 -0
- package/framework/templates/code/dotnet/feature/handler.cs.hbs +24 -0
- package/framework/templates/code/dotnet/feature/request.cs.hbs +4 -0
- package/framework/templates/code/dotnet/feature/response.cs.hbs +4 -0
- package/framework/templates/code/dotnet/feature/validator.cs.hbs +15 -0
- package/framework/templates/code/dotnet/jobs/job.cs +21 -17
- package/framework/templates/code/dotnet/pipelines/logging-decorator.cs +31 -0
- package/framework/templates/code/dotnet/pipelines/validation-decorator.cs +97 -0
- package/framework/templates/code/dotnet/test.cs +192 -106
- package/framework/templates/context/ARCHITECTURE.md +89 -0
- package/framework/templates/context/CONTEXT-FEATURE.md +2 -2
- package/framework/templates/context/CONTEXT.md +180 -181
- package/framework/templates/context/design-system.md +1 -5
- package/framework/templates/docs/onboarding.md +2 -3
- package/framework/templates/docs/proposal.md +171 -182
- package/framework/templates/docs/spec.md +1 -3
- package/framework/templates/docs/ui-components.md +0 -72
- package/framework/templates/examples/design-system-examples.md +4 -4
- package/framework/templates/feature/decisions.md +0 -66
- package/framework/templates/feature/recap.md +1 -2
- package/framework/templates/infrastructure/github/README.md +56 -593
- package/framework/templates/integrations/clerk-config.cs +0 -41
- package/framework/templates/meta-prompts/parallel-workers/parallel-worker.md +2 -2
- package/framework/templates/meta-prompts/squad-leaders/backend-squad.md +1 -2
- package/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +83 -126
- package/framework/templates/meta-prompts/validators/pre-commit-validator.md +2 -2
- package/framework/templates/project/validate.js +2 -4
- package/framework/templates/ui/design-system.css +1 -1
- package/framework/workflows/README.md +8 -8
- package/framework/workflows/configs/fast-track.json +51 -0
- package/framework/workflows/configs/full.json +68 -0
- package/framework/workflows/configs/standard.json +7 -3
- package/framework/workflows/docs/STORY-DRIVEN-DEVELOPMENT.md +1 -1
- package/framework/workflows/docs/enforcement-pipeline.md +18 -19
- package/framework/workflows/docs/full-morph.md +69 -76
- package/framework/workflows/docs/standard.md +49 -44
- package/framework/workflows/docs/ui-refresh.md +1 -1
- package/package.json +3 -3
- package/src/commands/agents/dispatch-agents.js +55 -116
- package/src/commands/context/context-refresh.js +79 -0
- package/src/commands/phase/phase-reset.js +1 -1
- package/src/commands/project/doctor.js +10 -32
- package/src/commands/project/init.js +12 -0
- package/src/commands/project/status.js +6 -12
- package/src/commands/scaffold/scaffold.js +131 -0
- package/src/commands/scope/escalate.js +1 -1
- package/src/commands/state/advance-phase.js +15 -29
- package/src/commands/state/state.js +20 -5
- package/src/commands/tasks/task.js +0 -30
- package/src/commands/validation/validate-feature.js +3 -10
- package/src/core/paths/output-schema.js +12 -13
- package/src/core/state/phase-state-machine.js +211 -217
- package/src/core/state/state-manager.js +9 -9
- package/src/lib/agents/agents-manager.js +2 -2
- package/src/lib/agents/output-collector.js +1 -2
- package/src/lib/detectors/design-system-detector.js +4 -4
- package/src/lib/detectors/index.js +1 -11
- package/src/lib/generators/architecture-scanner.js +640 -0
- package/src/lib/generators/context-generator.js +3 -3
- package/src/lib/generators/design-system-generator.js +508 -587
- package/src/lib/generators/index.js +12 -10
- package/src/lib/generators/metadata-extractor.js +386 -387
- package/src/lib/generators/recap-generator.js +4 -4
- package/src/lib/generators/scaffold-generator.js +317 -0
- package/src/lib/generators/settings-generator.js +0 -1
- package/src/lib/phase-chain/phase-validator.js +64 -42
- package/src/lib/stack/stack-profile.js +2 -2
- package/src/lib/standards/digest-builder.js +72 -285
- package/src/lib/tasks/task-parser.js +11 -5
- package/src/lib/validators/architecture/architecture-validator.js +259 -387
- package/src/lib/validators/content/content-validator.js +287 -287
- package/src/lib/validators/css/css-validator.js +340 -352
- package/src/lib/validators/packages/package-validator.js +347 -360
- package/src/lib/validators/shared/issue-counter.js +14 -18
- package/src/lib/validators/validation-runner.js +3 -19
- package/src/scripts/setup-infra.js +1 -1
- package/src/utils/agents-installer.js +61 -10
- package/src/utils/file-copier.js +1 -0
- package/src/utils/hooks-installer.js +11 -19
- package/src/utils/skills-installer.js +178 -178
- package/framework/agents/architecture/prompt-engineer.md +0 -195
- package/framework/agents/backend/api-designer.md +0 -106
- package/framework/agents/frontend/blazor-builder.md +0 -229
- package/framework/agents/frontend/nextjs-ui-specialist.md +0 -218
- package/framework/agents/infrastructure/azure-architect.md +0 -150
- package/framework/agents/infrastructure/azure-deploy-specialist.md +0 -707
- package/framework/agents/infrastructure/bicep-architect.md +0 -132
- package/framework/agents/infrastructure/container-specialist.md +0 -137
- package/framework/agents/infrastructure/devops-engineer.md +0 -126
- package/framework/agents/integrations/azure-identity.md +0 -148
- package/framework/agents/quality/code-analyzer.md +0 -239
- package/framework/agents/quality/testing-specialist.md +0 -130
- package/framework/hooks/claude-code/notification/approval-reminder.js +0 -57
- package/framework/hooks/claude-code/post-tool-use/context-refresh.js +0 -109
- package/framework/hooks/claude-code/post-tool-use/skill-reminder.js +0 -78
- package/framework/index/troubleshooting-index.json +0 -184
- package/framework/rules/testing-standards.md +0 -14
- package/framework/skills/level-0-meta/morph-replicate/SKILL.md +0 -230
- package/framework/skills/level-0-meta/morph-replicate/references/blazor-html-mapping.md +0 -70
- package/framework/skills/level-1-workflows/morph-phase-clarify/SKILL.md +0 -256
- package/framework/skills/level-1-workflows/morph-phase-clarify/references/clarifications-example.md +0 -117
- package/framework/skills/level-1-workflows/morph-phase-setup/SKILL.md +0 -269
- package/framework/standards/ai-agents/blazor-ui.md +0 -364
- package/framework/standards/architecture/ddd/aggregates.md +0 -120
- package/framework/standards/architecture/ddd/bounded-contexts.md +0 -105
- package/framework/standards/architecture/ddd/complexity-levels.md +0 -108
- package/framework/standards/architecture/ddd/entities.md +0 -99
- package/framework/standards/architecture/ddd/ubiquitous-language.md +0 -58
- package/framework/standards/architecture/ddd/value-objects.md +0 -124
- package/framework/standards/backend/api/minimal-api.md +0 -494
- package/framework/standards/backend/api/rest.md +0 -492
- package/framework/standards/backend/authentication/passkeys.md +0 -428
- package/framework/standards/backend/database/ef-core.md +0 -199
- package/framework/standards/backend/database/migrations.md +0 -393
- package/framework/standards/backend/database/repository-patterns.md +0 -528
- package/framework/standards/backend/dotnet/async.md +0 -366
- package/framework/standards/backend/dotnet/core.md +0 -117
- package/framework/standards/backend/dotnet/di.md +0 -439
- package/framework/standards/backend/dotnet/program-cs-checklist.md +0 -92
- package/framework/standards/context/analytics.md +0 -96
- package/framework/standards/context/bundles.md +0 -110
- package/framework/standards/context/priming.md +0 -78
- package/framework/standards/core/architecture.md +0 -185
- package/framework/standards/core/coding.md +0 -214
- package/framework/standards/core/git-branching-strategy.md +0 -403
- package/framework/standards/core/git.md +0 -185
- package/framework/standards/core/testing.md +0 -295
- package/framework/standards/data/nosql/blob-storage.md +0 -102
- package/framework/standards/data/vector-search/azure-ai-search.md +0 -121
- package/framework/standards/frontend/blazor/design-checklist.md +0 -222
- package/framework/standards/frontend/blazor/fluent-ui-setup.md +0 -595
- package/framework/standards/frontend/blazor/fluent-ui.md +0 -137
- package/framework/standards/frontend/blazor/html-conversion.md +0 -184
- package/framework/standards/frontend/blazor/lifecycle.md +0 -195
- package/framework/standards/frontend/blazor/pitfalls.md +0 -198
- package/framework/standards/frontend/blazor/state.md +0 -191
- package/framework/standards/frontend/design-system/aesthetic-direction.md +0 -266
- package/framework/standards/frontend/design-system/design-trends.md +0 -171
- package/framework/standards/infrastructure/azure/azure.md +0 -624
- package/framework/standards/infrastructure/azure/bicep/bicep-patterns.md +0 -422
- package/framework/standards/infrastructure/azure/devops/azure-devops-setup.md +0 -516
- package/framework/standards/infrastructure/azure/devops/local-development.md +0 -520
- package/framework/standards/infrastructure/azure/services/functions.md +0 -486
- package/framework/standards/infrastructure/azure/services/service-bus.md +0 -459
- package/framework/standards/infrastructure/azure/services/storage.md +0 -407
- package/framework/standards/infrastructure/vercel/vercel-database.md +0 -106
- package/framework/standards/integration/api/graphql.md +0 -91
- package/framework/standards/integration/api/grpc.md +0 -114
- package/framework/standards/integration/api/rest-design.md +0 -95
- package/framework/standards/integration/event-driven/cqrs.md +0 -101
- package/framework/standards/integration/event-driven/event-sourcing.md +0 -124
- package/framework/standards/integration/event-driven/service-bus.md +0 -95
- package/framework/standards/observability/logging.md +0 -131
- package/framework/standards/observability/metrics.md +0 -121
- package/framework/standards/observability/monitoring.md +0 -114
- package/framework/standards/observability/tracing.md +0 -132
- package/framework/standards/workflows/parallel-execution.md +0 -112
- package/framework/standards/workflows/thread-management.md +0 -113
- package/framework/templates/code/dotnet/backend/service.cs +0 -139
- package/framework/templates/code/dotnet/contracts/Commands.cs +0 -74
- package/framework/templates/code/dotnet/contracts/Entities.cs +0 -25
- package/framework/templates/code/dotnet/contracts/Queries.cs +0 -74
- package/framework/templates/code/dotnet/contracts/api-contracts.cs +0 -173
- package/framework/templates/code/dotnet/contracts/contracts-level1.cs +0 -69
- package/framework/templates/code/dotnet/contracts/contracts-level2.cs +0 -86
- package/framework/templates/code/dotnet/contracts/contracts-level3.cs +0 -41
- package/framework/templates/code/dotnet/frontend/component.razor +0 -239
- package/framework/templates/infrastructure/azure/Dockerfile.example +0 -82
- package/framework/templates/infrastructure/azure/README.md +0 -286
- package/framework/templates/infrastructure/azure/app-insights.bicep +0 -63
- package/framework/templates/infrastructure/azure/app-service.bicep +0 -164
- package/framework/templates/infrastructure/azure/container-app-env.bicep +0 -49
- package/framework/templates/infrastructure/azure/container-app.bicep +0 -156
- package/framework/templates/infrastructure/azure/deploy-checklist.md +0 -426
- package/framework/templates/infrastructure/azure/deploy.ps1 +0 -229
- package/framework/templates/infrastructure/azure/deploy.sh +0 -208
- package/framework/templates/infrastructure/azure/key-vault.bicep +0 -91
- package/framework/templates/infrastructure/azure/main.bicep +0 -189
- package/framework/templates/infrastructure/azure/parameters.dev.json +0 -29
- package/framework/templates/infrastructure/azure/parameters.prod.json +0 -29
- package/framework/templates/infrastructure/azure/parameters.staging.json +0 -29
- package/framework/templates/infrastructure/azure/sql-database.bicep +0 -103
- package/framework/templates/infrastructure/azure/storage.bicep +0 -106
- package/framework/templates/infrastructure/github/actions/azure-auth/action.yml.hbs +0 -22
- package/framework/templates/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs +0 -61
- package/framework/templates/integrations/azure-identity-config.cs +0 -288
- package/framework/templates/project-structure/dotnet-ddd.md +0 -70
- package/framework/templates/saas/subscription.cs +0 -347
- package/framework/templates/saas/tenant.cs +0 -338
- package/framework/templates/ui/FluentDesignTheme.cs +0 -149
- package/framework/templates/ui/MudTheme.cs +0 -281
- package/framework/workflows/configs/nodejs-cli.json +0 -40
- package/src/commands/standards/context-budget.js +0 -89
- package/src/lib/standards/index.js +0 -7
- package/src/lib/standards/standards-context-injector.js +0 -302
- package/src/lib/validators/blazor/blazor-concurrency-analyzer.js +0 -316
- package/src/lib/validators/blazor/blazor-state-validator.js +0 -279
- package/src/lib/validators/blazor/blazor-validator.js +0 -369
- package/src/lib/validators/blazor/index.js +0 -9
|
@@ -1,217 +1,211 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Phase State Machine - Enforces valid phase transitions
|
|
3
|
-
*
|
|
4
|
-
* Prevents invalid workflow jumps and ensures sequential phase progression.
|
|
5
|
-
* Based on the MORPH 5-phase workflow.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Valid phase transitions map
|
|
10
|
-
* Each phase can only transition to specific next phases
|
|
11
|
-
*/
|
|
12
|
-
const VALID_TRANSITIONS = {
|
|
13
|
-
'proposal': ['
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
if (!
|
|
95
|
-
throw new Error('
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
if (!toPhase) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
'
|
|
125
|
-
'
|
|
126
|
-
'
|
|
127
|
-
'
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
order: getPhaseOrder(phase),
|
|
213
|
-
isOptional: isOptionalPhase(phase),
|
|
214
|
-
validNextPhases: getValidNextPhases(phase),
|
|
215
|
-
canTransitionTo: (targetPhase) => isValidTransition(phase, targetPhase)
|
|
216
|
-
};
|
|
217
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Phase State Machine - Enforces valid phase transitions
|
|
3
|
+
*
|
|
4
|
+
* Prevents invalid workflow jumps and ensures sequential phase progression.
|
|
5
|
+
* Based on the MORPH 5-phase workflow.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Valid phase transitions map
|
|
10
|
+
* Each phase can only transition to specific next phases
|
|
11
|
+
*/
|
|
12
|
+
const VALID_TRANSITIONS = {
|
|
13
|
+
'proposal': ['uiux', 'design'], // Can skip UI/UX if no frontend
|
|
14
|
+
'uiux': ['design'],
|
|
15
|
+
'design': ['plan'],
|
|
16
|
+
'plan': ['tasks'],
|
|
17
|
+
'tasks': ['implement'],
|
|
18
|
+
'implement': ['sync', 'archived'], // Can skip sync
|
|
19
|
+
'sync': ['archived']
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Phase display names for error messages
|
|
24
|
+
*/
|
|
25
|
+
const PHASE_NAMES = {
|
|
26
|
+
'proposal': 'Proposal (Phase 0)',
|
|
27
|
+
'uiux': 'UI/UX Design (Phase 1)',
|
|
28
|
+
'design': 'Design (Phase 2)',
|
|
29
|
+
'plan': 'Plan (Phase 3)',
|
|
30
|
+
'tasks': 'Tasks (Phase 4)',
|
|
31
|
+
'implement': 'Implement (Phase 5)',
|
|
32
|
+
'sync': 'Sync (Phase 6)',
|
|
33
|
+
'archived': 'Archived'
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Optional phases that can be skipped
|
|
38
|
+
*/
|
|
39
|
+
const OPTIONAL_PHASES = ['uiux', 'sync'];
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Validate if a phase transition is allowed
|
|
43
|
+
* @param {string} fromPhase - Current phase
|
|
44
|
+
* @param {string} toPhase - Target phase
|
|
45
|
+
* @returns {boolean} True if transition is valid
|
|
46
|
+
*/
|
|
47
|
+
export function isValidTransition(fromPhase, toPhase) {
|
|
48
|
+
if (!fromPhase || !toPhase) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const validNextPhases = VALID_TRANSITIONS[fromPhase];
|
|
53
|
+
return validNextPhases ? validNextPhases.includes(toPhase) : false;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get list of valid next phases for a given phase
|
|
58
|
+
* @param {string} currentPhase - Current phase
|
|
59
|
+
* @returns {string[]} Array of valid next phase names
|
|
60
|
+
*/
|
|
61
|
+
export function getValidNextPhases(currentPhase) {
|
|
62
|
+
return VALID_TRANSITIONS[currentPhase] || [];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Get display name for a phase
|
|
67
|
+
* @param {string} phase - Phase identifier
|
|
68
|
+
* @returns {string} Human-readable phase name
|
|
69
|
+
*/
|
|
70
|
+
export function getPhaseDisplayName(phase) {
|
|
71
|
+
return PHASE_NAMES[phase] || phase;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Check if a phase is optional
|
|
76
|
+
* @param {string} phase - Phase identifier
|
|
77
|
+
* @returns {boolean} True if phase is optional
|
|
78
|
+
*/
|
|
79
|
+
export function isOptionalPhase(phase) {
|
|
80
|
+
return OPTIONAL_PHASES.includes(phase);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Validate transition and throw error if invalid
|
|
85
|
+
* @param {string} fromPhase - Current phase
|
|
86
|
+
* @param {string} toPhase - Target phase
|
|
87
|
+
* @throws {Error} If transition is invalid
|
|
88
|
+
*/
|
|
89
|
+
export function validateTransition(fromPhase, toPhase) {
|
|
90
|
+
if (!fromPhase) {
|
|
91
|
+
throw new Error('Current phase is undefined. Cannot validate transition.');
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (!toPhase) {
|
|
95
|
+
throw new Error('Target phase is undefined. Cannot validate transition.');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (!isValidTransition(fromPhase, toPhase)) {
|
|
99
|
+
const validPhases = getValidNextPhases(fromPhase);
|
|
100
|
+
const fromDisplay = getPhaseDisplayName(fromPhase);
|
|
101
|
+
const toDisplay = getPhaseDisplayName(toPhase);
|
|
102
|
+
|
|
103
|
+
throw new Error(
|
|
104
|
+
`Invalid phase transition: ${fromDisplay} → ${toDisplay}\n\n` +
|
|
105
|
+
`Valid next phases from ${fromDisplay}:\n` +
|
|
106
|
+
validPhases.map(p => ` • ${getPhaseDisplayName(p)}`).join('\n') +
|
|
107
|
+
'\n\n' +
|
|
108
|
+
'You cannot skip phases in the MORPH workflow.\n' +
|
|
109
|
+
'To override this check, use the --force flag (not recommended).'
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Get the sequential order of phases
|
|
116
|
+
* @returns {string[]} Ordered list of phases
|
|
117
|
+
*/
|
|
118
|
+
export function getPhaseSequence() {
|
|
119
|
+
return [
|
|
120
|
+
'proposal',
|
|
121
|
+
'uiux', // optional
|
|
122
|
+
'design',
|
|
123
|
+
'plan',
|
|
124
|
+
'tasks',
|
|
125
|
+
'implement',
|
|
126
|
+
'sync', // optional
|
|
127
|
+
'archived'
|
|
128
|
+
];
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Get phase order index (for comparison)
|
|
133
|
+
* @param {string} phase - Phase identifier
|
|
134
|
+
* @returns {number} Index in sequence (-1 if not found)
|
|
135
|
+
*/
|
|
136
|
+
export function getPhaseOrder(phase) {
|
|
137
|
+
return getPhaseSequence().indexOf(phase);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Check if target phase is ahead of current phase
|
|
142
|
+
* @param {string} currentPhase - Current phase
|
|
143
|
+
* @param {string} targetPhase - Target phase
|
|
144
|
+
* @returns {boolean} True if target is ahead
|
|
145
|
+
*/
|
|
146
|
+
export function isPhaseAhead(currentPhase, targetPhase) {
|
|
147
|
+
return getPhaseOrder(targetPhase) > getPhaseOrder(currentPhase);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Check if target phase is behind current phase (rollback scenario)
|
|
152
|
+
* @param {string} currentPhase - Current phase
|
|
153
|
+
* @param {string} targetPhase - Target phase
|
|
154
|
+
* @returns {boolean} True if target is behind
|
|
155
|
+
*/
|
|
156
|
+
export function isPhaseRollback(currentPhase, targetPhase) {
|
|
157
|
+
return getPhaseOrder(targetPhase) < getPhaseOrder(currentPhase);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Get all skipped phases between two phases
|
|
162
|
+
* @param {string} fromPhase - Starting phase
|
|
163
|
+
* @param {string} toPhase - Ending phase
|
|
164
|
+
* @returns {string[]} Array of skipped phases
|
|
165
|
+
*/
|
|
166
|
+
export function getSkippedPhases(fromPhase, toPhase) {
|
|
167
|
+
const sequence = getPhaseSequence();
|
|
168
|
+
const fromIndex = sequence.indexOf(fromPhase);
|
|
169
|
+
const toIndex = sequence.indexOf(toPhase);
|
|
170
|
+
|
|
171
|
+
if (fromIndex === -1 || toIndex === -1 || toIndex <= fromIndex) {
|
|
172
|
+
return [];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return sequence.slice(fromIndex + 1, toIndex);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Validate that no required phases were skipped
|
|
180
|
+
* @param {string} fromPhase - Starting phase
|
|
181
|
+
* @param {string} toPhase - Ending phase
|
|
182
|
+
* @throws {Error} If required phases were skipped
|
|
183
|
+
*/
|
|
184
|
+
export function validateNoRequiredPhasesSkipped(fromPhase, toPhase) {
|
|
185
|
+
const skipped = getSkippedPhases(fromPhase, toPhase);
|
|
186
|
+
const requiredSkipped = skipped.filter(p => !isOptionalPhase(p));
|
|
187
|
+
|
|
188
|
+
if (requiredSkipped.length > 0) {
|
|
189
|
+
throw new Error(
|
|
190
|
+
`Cannot skip required phases:\n` +
|
|
191
|
+
requiredSkipped.map(p => ` • ${getPhaseDisplayName(p)}`).join('\n') +
|
|
192
|
+
'\n\nYou must complete each required phase in sequence.'
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Get comprehensive phase information
|
|
199
|
+
* @param {string} phase - Phase identifier
|
|
200
|
+
* @returns {Object} Phase metadata
|
|
201
|
+
*/
|
|
202
|
+
export function getPhaseInfo(phase) {
|
|
203
|
+
return {
|
|
204
|
+
id: phase,
|
|
205
|
+
displayName: getPhaseDisplayName(phase),
|
|
206
|
+
order: getPhaseOrder(phase),
|
|
207
|
+
isOptional: isOptionalPhase(phase),
|
|
208
|
+
validNextPhases: getValidNextPhases(phase),
|
|
209
|
+
canTransitionTo: (targetPhase) => isValidTransition(phase, targetPhase)
|
|
210
|
+
};
|
|
211
|
+
}
|
|
@@ -27,21 +27,21 @@ export function getStatePath() {
|
|
|
27
27
|
* Returns the phase corresponding to the highest-numbered folder present.
|
|
28
28
|
*
|
|
29
29
|
* @param {string} featurePath - Absolute path to .morph/features/{feature}/
|
|
30
|
-
* @returns {string} Phase name: 'implement' | 'tasks' | 'plan' | 'uiux' | 'design' | 'proposal'
|
|
30
|
+
* @returns {string} Phase name: 'implement' | 'tasks' | 'plan' | 'uiux' | 'design' | 'proposal'
|
|
31
31
|
*/
|
|
32
32
|
export function derivePhase(featurePath) {
|
|
33
33
|
const phaseMap = [
|
|
34
34
|
['5-implement', 'implement'],
|
|
35
35
|
['4-tasks', 'tasks'],
|
|
36
36
|
['3-plan', 'plan'],
|
|
37
|
-
['2-
|
|
38
|
-
['1-
|
|
37
|
+
['2-design', 'design'],
|
|
38
|
+
['1-ui', 'uiux'],
|
|
39
39
|
['0-proposal', 'proposal'],
|
|
40
40
|
];
|
|
41
41
|
for (const [folder, phase] of phaseMap) {
|
|
42
42
|
if (existsSync(join(featurePath, folder))) return phase;
|
|
43
43
|
}
|
|
44
|
-
return '
|
|
44
|
+
return 'proposal';
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/**
|
|
@@ -168,11 +168,11 @@ export function saveState(state) {
|
|
|
168
168
|
* @param {Object} options - Options
|
|
169
169
|
* @param {boolean} options.force - Overwrite existing file
|
|
170
170
|
* @param {string} options.projectName - Project name
|
|
171
|
-
* @param {string} options.projectType - Project type (e.g., '
|
|
171
|
+
* @param {string} options.projectType - Project type (e.g., 'dotnet-nextjs')
|
|
172
172
|
* @returns {Object} Initial state
|
|
173
173
|
*/
|
|
174
174
|
export function initState(options = {}) {
|
|
175
|
-
const { force = false, projectName = '{PROJECT_NAME}', projectType = '
|
|
175
|
+
const { force = false, projectName = '{PROJECT_NAME}', projectType = 'dotnet-nextjs' } = options;
|
|
176
176
|
|
|
177
177
|
if (stateExists() && !force) {
|
|
178
178
|
throw new Error('State file already exists. Use force=true to overwrite.');
|
|
@@ -362,7 +362,7 @@ export async function addCheckpoint(featureName, note) {
|
|
|
362
362
|
passed: true,
|
|
363
363
|
checkpointNum: feature.checkpoints.length + 1,
|
|
364
364
|
timestamp: new Date().toISOString(),
|
|
365
|
-
phase: feature.phase || '
|
|
365
|
+
phase: feature.phase || 'proposal',
|
|
366
366
|
results: [],
|
|
367
367
|
summary: {
|
|
368
368
|
note: note,
|
|
@@ -617,7 +617,7 @@ export async function trackFileChange(featureName, filePath, action, phase) {
|
|
|
617
617
|
state.features[featureName].fileChanges.push({
|
|
618
618
|
path: filePath,
|
|
619
619
|
action,
|
|
620
|
-
phase: phase || state.features[featureName].phase || '
|
|
620
|
+
phase: phase || state.features[featureName].phase || 'proposal',
|
|
621
621
|
timestamp: new Date().toISOString()
|
|
622
622
|
});
|
|
623
623
|
|
|
@@ -783,7 +783,7 @@ export function isPendingApproval(featureName) {
|
|
|
783
783
|
return false;
|
|
784
784
|
}
|
|
785
785
|
|
|
786
|
-
const currentPhase = feature.phase || '
|
|
786
|
+
const currentPhase = feature.phase || 'proposal';
|
|
787
787
|
|
|
788
788
|
// Check if current phase has an approval gate
|
|
789
789
|
const phaseGateMap = {
|
|
@@ -16,8 +16,8 @@ import { dirname } from 'node:path';
|
|
|
16
16
|
|
|
17
17
|
/** Known valid phases for active_phases validation */
|
|
18
18
|
export const KNOWN_PHASES = [
|
|
19
|
-
'proposal', '
|
|
20
|
-
'
|
|
19
|
+
'proposal', 'uiux', 'design',
|
|
20
|
+
'plan', 'tasks', 'implement', 'sync',
|
|
21
21
|
];
|
|
22
22
|
|
|
23
23
|
/** Tier labels for display and validation */
|
|
@@ -19,7 +19,6 @@ export const SOURCE_WEIGHTS = {
|
|
|
19
19
|
contracts: 1.0,
|
|
20
20
|
contractsTs: 1.0,
|
|
21
21
|
contractsVsa: 1.0,
|
|
22
|
-
clarifications: 1.0,
|
|
23
22
|
decisions: 1.0,
|
|
24
23
|
plan: 1.2,
|
|
25
24
|
tasks: 1.3,
|
|
@@ -31,7 +30,7 @@ export const SOURCE_WEIGHTS = {
|
|
|
31
30
|
};
|
|
32
31
|
|
|
33
32
|
/** Phase order for sorting collected outputs */
|
|
34
|
-
const PHASE_ORDER = ['proposal', 'uiux', 'design', '
|
|
33
|
+
const PHASE_ORDER = ['proposal', 'uiux', 'design', 'plan', 'tasks', 'implement'];
|
|
35
34
|
|
|
36
35
|
/**
|
|
37
36
|
* Collect all existing phase output files for a feature.
|
|
@@ -64,7 +64,7 @@ export function detectDesignSystem(projectPath, featureName = null) {
|
|
|
64
64
|
projectPath,
|
|
65
65
|
'.morph/features',
|
|
66
66
|
featureName,
|
|
67
|
-
'
|
|
67
|
+
'1-ui',
|
|
68
68
|
'design-system.md'
|
|
69
69
|
);
|
|
70
70
|
|
|
@@ -179,7 +179,7 @@ export function hasUIAgentsActive(projectPath, featureName) {
|
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
// UI design agents that require a design system before implement phase.
|
|
182
|
-
// Implementation-only agents (
|
|
182
|
+
// Implementation-only agents (nextjs-expert, css-specialist)
|
|
183
183
|
// build from existing designs and do NOT trigger this gate.
|
|
184
184
|
const uiAgents = [
|
|
185
185
|
'ui-designer',
|
|
@@ -208,10 +208,10 @@ export function getRecommendedLocations(projectPath) {
|
|
|
208
208
|
projectType = config.project?.type || 'unknown';
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
// Default locations
|
|
211
|
+
// Default locations
|
|
212
212
|
const locations = {
|
|
213
213
|
markdown: '.morph/context/design-system.md',
|
|
214
|
-
css: '
|
|
214
|
+
css: 'public/design-system.css',
|
|
215
215
|
description: 'Project-level design system (shared across features)'
|
|
216
216
|
};
|
|
217
217
|
|
|
@@ -68,10 +68,6 @@ export function detectProject(targetPath, opts = {}) {
|
|
|
68
68
|
// UI library detection
|
|
69
69
|
if (existsSync(join(targetPath, 'components.json')) || existsSync(join(targetPath, structure.frontendPath || '.', 'components.json')) || depNames.includes('@shadcn/ui')) {
|
|
70
70
|
structure.uiLibrary = 'shadcn';
|
|
71
|
-
} else if (depNames.some(d => d.includes('mudblazor'))) {
|
|
72
|
-
structure.uiLibrary = 'mudblazor';
|
|
73
|
-
} else if (depNames.some(d => d.includes('fluent'))) {
|
|
74
|
-
structure.uiLibrary = 'fluent-ui';
|
|
75
71
|
}
|
|
76
72
|
|
|
77
73
|
// Integrations
|
|
@@ -93,16 +89,12 @@ export function detectProject(targetPath, opts = {}) {
|
|
|
93
89
|
|
|
94
90
|
// ── .csproj detection ──────────────────────────────────────────────────
|
|
95
91
|
let hasDotnet = false;
|
|
96
|
-
let hasBlazer = false;
|
|
97
92
|
const csprojLocations = ['.', 'src', 'src/Api', 'src/Web', 'src/backend'];
|
|
98
93
|
|
|
99
94
|
function checkCsproj(filePath) {
|
|
100
95
|
hasDotnet = true;
|
|
101
96
|
try {
|
|
102
97
|
const content = readFileSync(filePath, 'utf8');
|
|
103
|
-
if (content.includes('Microsoft.AspNetCore.Components') || content.includes('Blazor')) {
|
|
104
|
-
hasBlazer = true;
|
|
105
|
-
}
|
|
106
98
|
if (content.includes('Hangfire')) {
|
|
107
99
|
if (!structure.integrations.includes('hangfire')) structure.integrations.push('hangfire');
|
|
108
100
|
}
|
|
@@ -128,13 +120,11 @@ export function detectProject(targetPath, opts = {}) {
|
|
|
128
120
|
} catch { /* ignore */ }
|
|
129
121
|
}
|
|
130
122
|
|
|
131
|
-
// Determine stack: monorepo (nextjs+dotnet),
|
|
123
|
+
// Determine stack: monorepo (nextjs+dotnet), dotnet, or keep frontend stack
|
|
132
124
|
if (hasDotnet) {
|
|
133
125
|
if (structure.stack === 'nextjs' || structure.stack === 'react' || structure.stack === 'vue') {
|
|
134
126
|
// Monorepo: frontend + .NET backend
|
|
135
127
|
structure.stack = `${structure.stack}+dotnet`;
|
|
136
|
-
} else if (hasBlazer) {
|
|
137
|
-
structure.stack = 'blazor';
|
|
138
128
|
} else if (structure.stack === 'unknown') {
|
|
139
129
|
structure.stack = 'dotnet';
|
|
140
130
|
}
|