@polymorphism-tech/morph-spec 3.0.1 → 3.2.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 +561 -63
- package/LICENSE +72 -72
- package/README.md +275 -79
- package/bin/detect-agents.js +3 -1
- package/bin/morph-spec.js +60 -1
- package/bin/render-template.js +61 -14
- package/bin/semantic-detect-agents.js +2 -1
- package/bin/{task-manager.js → task-manager.cjs} +113 -8
- package/bin/validate-agents-skills.js +10 -4
- package/bin/validate-agents.js +4 -3
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-light-webfont.svg +977 -977
- package/docs/api/fonts/Source-Sans-Pro/sourcesanspro-regular-webfont.svg +1048 -1048
- package/docs/api/scripts/collapse.js +38 -38
- package/docs/api/scripts/commonNav.js +28 -28
- package/docs/api/scripts/linenumber.js +25 -25
- package/docs/api/scripts/nav.js +12 -12
- package/docs/api/scripts/polyfill.js +3 -3
- package/docs/api/scripts/prettify/Apache-License-2.0.txt +202 -202
- package/docs/api/scripts/prettify/lang-css.js +2 -2
- package/docs/api/scripts/prettify/prettify.js +28 -28
- package/docs/api/scripts/search.js +98 -98
- package/docs/api/styles/jsdoc.css +776 -776
- package/docs/api/styles/prettify.css +80 -80
- package/docs/cli-auto-detection.md +219 -0
- package/docs/examples.md +328 -328
- package/docs/getting-started.md +3 -3
- package/docs/llm-interaction-config.md +735 -0
- package/docs/templates.md +418 -418
- package/docs/troubleshooting.md +269 -0
- package/package.json +7 -3
- package/scripts/postinstall.js +132 -132
- package/scripts/reorganize-skills.cjs +1 -1
- package/scripts/validate-agents-structure.cjs +1 -1
- package/scripts/validate-skills.cjs +2 -2
- package/src/commands/advance-phase.js +93 -2
- package/src/commands/analyze-blazor-concurrency.js +193 -193
- package/src/commands/approve.js +221 -0
- package/src/commands/capture-pattern.js +121 -0
- package/src/commands/create-story.js +5 -2
- package/src/commands/deploy.js +780 -780
- package/src/commands/detect-agents.js +4 -2
- package/src/commands/generate.js +276 -149
- package/src/commands/init.js +37 -0
- package/src/commands/lint-fluent.js +352 -352
- package/src/commands/migrate-state.js +158 -0
- package/src/commands/rollback-phase.js +185 -185
- package/src/commands/search-patterns.js +126 -0
- package/src/commands/session-summary.js +291 -291
- package/src/commands/shard-spec.js +224 -224
- package/src/commands/spawn-team.js +172 -0
- package/src/commands/sprint-status.js +250 -250
- package/src/commands/task.js +3 -3
- package/src/commands/troubleshoot.js +222 -222
- package/src/commands/update.js +36 -0
- package/src/commands/upgrade.js +346 -0
- package/src/commands/validate-blazor-state.js +210 -210
- package/src/commands/validate-blazor.js +156 -156
- package/src/commands/validate-css.js +84 -84
- package/src/commands/validate-phase.js +221 -221
- package/src/generator/.gitkeep +0 -0
- package/src/generator/config-generator.js +206 -0
- package/src/generator/templates/config.json.template +40 -0
- package/src/generator/templates/project.md.template +67 -0
- package/src/lib/blazor-concurrency-analyzer.js +288 -288
- package/src/lib/blazor-state-validator.js +291 -291
- package/src/lib/blazor-validator.js +374 -374
- package/src/lib/checkpoint-hooks.js +258 -0
- package/src/lib/context-generator.js +7 -4
- package/src/lib/css-validator.js +352 -352
- package/src/lib/design-system-generator.js +298 -298
- package/src/lib/hook-executor.js +2 -1
- package/src/lib/learning-system.js +520 -520
- package/src/lib/metadata-extractor.js +380 -0
- package/src/lib/mockup-generator.js +366 -366
- package/src/lib/phase-state-machine.js +214 -0
- package/src/lib/stack-resolver.js +148 -0
- package/src/lib/standards-context-injector.js +4 -3
- package/src/lib/state-manager.js +120 -0
- package/src/lib/team-orchestrator.js +2 -1
- package/src/lib/template-data-sources.js +325 -0
- package/src/lib/troubleshoot-grep.js +204 -194
- package/src/lib/troubleshoot-index.js +144 -144
- package/src/lib/ui-detector.js +350 -350
- package/src/lib/validation-runner.js +2 -1
- package/src/lib/validators/architecture-validator.js +387 -387
- package/src/lib/validators/content-validator.js +351 -0
- package/src/lib/validators/package-validator.js +360 -360
- package/src/lib/validators/ui-contrast-validator.js +422 -422
- package/src/llm/.gitkeep +0 -0
- package/src/llm/analyzer.js +215 -0
- package/src/llm/environment-detector.js +43 -0
- package/src/llm/few-shot-examples.js +216 -0
- package/src/llm/project-config-schema.json +188 -0
- package/src/llm/prompt-builder.js +96 -0
- package/src/llm/schema-validator.js +121 -0
- package/src/orchestrator.js +206 -0
- package/src/sanitizer/.gitkeep +0 -0
- package/src/sanitizer/context-sanitizer.js +221 -0
- package/src/sanitizer/patterns.js +163 -0
- package/src/scanner/.gitkeep +0 -0
- package/src/scanner/project-scanner.js +242 -0
- package/src/types/index.js +477 -0
- package/src/ui/.gitkeep +0 -0
- package/src/ui/diff-display.js +91 -0
- package/src/ui/interactive-wizard.js +96 -0
- package/src/ui/user-review.js +211 -0
- package/src/ui/wizard-questions.js +190 -0
- package/src/utils/file-copier.js +3 -1
- package/src/utils/logger.js +32 -32
- package/src/utils/version-checker.js +175 -175
- package/src/writer/.gitkeep +0 -0
- package/src/writer/file-writer.js +86 -0
- package/{content → stacks/blazor-azure}/.azure/README.md +2 -2
- package/{content → stacks/blazor-azure}/.azure/pipelines/pipeline-variables.yml +1 -1
- package/{content → stacks/blazor-azure}/.azure/pipelines/prod-pipeline.yml +1 -1
- package/{content → stacks/blazor-azure}/.azure/pipelines/staging-pipeline.yml +1 -1
- package/{content → stacks/blazor-azure}/.claude/commands/morph-preflight.md +227 -227
- package/{content → stacks/blazor-azure}/.claude/commands/morph-troubleshoot.md +122 -122
- package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-setup.md +1 -1
- package/{content → stacks/blazor-azure}/.morph/docs/workflows/enforcement-pipeline.md +3 -3
- package/{content → stacks/blazor-azure}/.morph/hooks/README.md +12 -12
- package/{content → stacks/blazor-azure}/.morph/standards/agent-teams-workflow.md +2 -2
- package/{content → stacks/blazor-azure}/.morph/standards/migration-guide.md +2 -2
- package/{content → stacks/blazor-azure}/.morph/templates/infra/deploy-checklist.md +426 -426
- package/stacks/nextjs-supabase/.claude/skills/level-2-domains/backend/dotnet-supabase.md +244 -0
- package/stacks/nextjs-supabase/.claude/skills/level-2-domains/frontend/nextjs-supabase.md +335 -0
- package/stacks/nextjs-supabase/.claude/skills/level-2-domains/infrastructure/easypanel-deployer.md +189 -0
- package/stacks/nextjs-supabase/.claude/skills/level-2-domains/integrations/supabase-expert.md +170 -0
- package/stacks/nextjs-supabase/.morph/config/agents.json +345 -0
- package/stacks/nextjs-supabase/.morph/config/config.template.json +92 -0
- package/stacks/nextjs-supabase/.morph/docs/easypanel-setup.md +169 -0
- package/stacks/nextjs-supabase/.morph/docs/supabase-mcp-setup.md +247 -0
- package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/README.md +697 -0
- package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/spec.md +85 -0
- package/stacks/nextjs-supabase/.morph/examples/crud-nextjs-supabase/tasks.md +86 -0
- package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/README.md +498 -0
- package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/decisions.md +121 -0
- package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/spec.md +138 -0
- package/stacks/nextjs-supabase/.morph/examples/saas-nextjs-supabase/tasks.md +162 -0
- package/stacks/nextjs-supabase/.morph/project.md +168 -0
- package/stacks/nextjs-supabase/.morph/standards/easypanel-deploy.md +191 -0
- package/stacks/nextjs-supabase/.morph/standards/nextjs-patterns.md +193 -0
- package/stacks/nextjs-supabase/.morph/standards/supabase-auth.md +171 -0
- package/stacks/nextjs-supabase/.morph/standards/supabase-pgvector.md +164 -0
- package/stacks/nextjs-supabase/.morph/standards/supabase-rls.md +179 -0
- package/stacks/nextjs-supabase/.morph/standards/supabase-storage.md +148 -0
- package/stacks/nextjs-supabase/.morph/templates/contracts.cs +173 -0
- package/stacks/nextjs-supabase/.morph/templates/contracts.ts +168 -0
- package/stacks/nextjs-supabase/.morph/templates/decisions.md +115 -0
- package/stacks/nextjs-supabase/.morph/templates/dockerfile-api.dockerfile +38 -0
- package/stacks/nextjs-supabase/.morph/templates/dockerfile-web.dockerfile +48 -0
- package/stacks/nextjs-supabase/.morph/templates/proposal.md +145 -0
- package/stacks/nextjs-supabase/.morph/templates/recap.md +134 -0
- package/stacks/nextjs-supabase/.morph/templates/rls-policy.sql +57 -0
- package/stacks/nextjs-supabase/.morph/templates/spec.md +231 -0
- package/stacks/nextjs-supabase/.morph/templates/supabase-migration.sql +100 -0
- package/stacks/nextjs-supabase/.morph/templates/tasks.md +257 -0
- package/stacks/nextjs-supabase/CLAUDE.md +149 -0
- package/stacks/nextjs-supabase/README.md +112 -0
- /package/{content → stacks/blazor-azure}/.azure/docs/azure-devops-setup.md +0 -0
- /package/{content → stacks/blazor-azure}/.azure/docs/branch-strategy.md +0 -0
- /package/{content → stacks/blazor-azure}/.azure/docs/local-development.md +0 -0
- /package/{content → stacks/blazor-azure}/.azure/pipelines/templates/build-dotnet.yml +0 -0
- /package/{content → stacks/blazor-azure}/.azure/pipelines/templates/deploy-app-service.yml +0 -0
- /package/{content → stacks/blazor-azure}/.azure/pipelines/templates/deploy-container-app.yml +0 -0
- /package/{content → stacks/blazor-azure}/.azure/pipelines/templates/infra-deploy.yml +0 -0
- /package/{content → stacks/blazor-azure}/.claude/commands/morph-apply.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/commands/morph-archive.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/commands/morph-deploy.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/commands/morph-infra.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/commands/morph-proposal.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/commands/morph-status.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/settings.local.json +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/README.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/code-review.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/morph-checklist.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-0-meta/simulation-checklist.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/README.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/morph-replicate.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-clarify.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-design.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-tasks.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-1-workflows/phase-uiux.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/README.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/ai-agents/ai-system-architect.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/architecture/po-pm-advisor.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/architecture/prompt-engineer.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/architecture/seo-growth-hacker.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/architecture/standards-architect.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/dotnet-senior.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/ef-modeler.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/hangfire-orchestrator.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/backend/ms-agent-expert.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/frontend/blazor-builder.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/frontend/nextjs-expert.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/frontend/ui-ux-designer.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/azure-architect.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/azure-deploy-specialist.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/bicep-architect.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/container-specialist.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/infrastructure/devops-engineer.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/asaas-financial.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/azure-identity.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/clerk-auth.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/integrations/resend-email.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/quality/code-analyzer.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-2-domains/quality/testing-specialist.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-3-technologies/README.md +0 -0
- /package/{content → stacks/blazor-azure}/.claude/skills/level-4-patterns/README.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/.morphversion +0 -0
- /package/{content → stacks/blazor-azure}/.morph/archive/.gitkeep +0 -0
- /package/{content → stacks/blazor-azure}/.morph/config/agents.json +0 -0
- /package/{content → stacks/blazor-azure}/.morph/config/config.template.json +0 -0
- /package/{content → stacks/blazor-azure}/.morph/docs/STORY-DRIVEN-DEVELOPMENT.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/docs/workflows/design-impl.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/docs/workflows/fast-track.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/docs/workflows/full-morph.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/docs/workflows/standard.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/docs/workflows/ui-refresh.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/README.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/contracts.ts +0 -0
- /package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/spec.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/examples/api-nextjs/tasks.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/README.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/contracts.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/decisions.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/spec.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/examples/micro-saas/tasks.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/README.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/contracts.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/spec.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/examples/multi-agent/tasks.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/examples/scheduled-reports/decisions.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/examples/scheduled-reports/proposal.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/examples/scheduled-reports/spec.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/examples/state-v3.json +0 -0
- /package/{content → stacks/blazor-azure}/.morph/features/.gitkeep +0 -0
- /package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-agents.sh +0 -0
- /package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-all.sh +0 -0
- /package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-specs.sh +0 -0
- /package/{content → stacks/blazor-azure}/.morph/hooks/pre-commit-tests.sh +0 -0
- /package/{content → stacks/blazor-azure}/.morph/hooks/task-completed.js +0 -0
- /package/{content → stacks/blazor-azure}/.morph/hooks/teammate-idle.js +0 -0
- /package/{content → stacks/blazor-azure}/.morph/project.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/schemas/agent.schema.json +0 -0
- /package/{content → stacks/blazor-azure}/.morph/schemas/tasks.schema.json +0 -0
- /package/{content → stacks/blazor-azure}/.morph/specs/.gitkeep +0 -0
- /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-blazor-ui.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-production.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-setup.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/standards/agent-framework-workflows.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/standards/architecture.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/standards/azure.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/standards/coding.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/standards/dotnet10-migration.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/standards/fluent-ui-setup.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/standards/passkeys-auth.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/standards/vector-search-rag.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/state.json +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/CONTEXT-FEATURE.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/CONTEXT.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/FluentDesignTheme.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/MudTheme.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/agent.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/clarify-questions.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/component.razor +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/contracts/Commands.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/contracts/Entities.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/contracts/Queries.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/contracts/README.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/contracts.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/decisions.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/design-system.css +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/infra/.dockerignore.example +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/infra/Dockerfile.example +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/infra/README.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/infra/app-insights.bicep +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/infra/app-service.bicep +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/infra/azure-pipelines-deploy.yml +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/infra/container-app-env.bicep +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/infra/container-app.bicep +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/infra/deploy.ps1 +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/infra/deploy.sh +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/infra/key-vault.bicep +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/infra/main.bicep +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/infra/parameters.dev.json +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/infra/parameters.prod.json +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/infra/parameters.staging.json +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/infra/sql-database.bicep +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/infra/storage.bicep +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/integrations/asaas-client.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/integrations/asaas-webhook.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/integrations/azure-identity-config.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/integrations/clerk-config.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/job.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/migration.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/proposal.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/recap.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/repository.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/saas/subscription.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/saas/tenant.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/service.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/simulation.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/spec.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/sprint-status.yaml +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/state.template.json +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/story.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/tasks.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/test.cs +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/ui-components.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/ui-design-system.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/ui-flows.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/templates/ui-mockups.md +0 -0
- /package/{content → stacks/blazor-azure}/.morph/test-infra/example.bicep +0 -0
- /package/{content → stacks/blazor-azure}/CLAUDE.md +0 -0
- /package/{content → stacks/blazor-azure}/README.md +0 -0
|
@@ -1,221 +1,221 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MORPH-SPEC Phase Validator Command
|
|
3
|
-
*
|
|
4
|
-
* Validates that required previous phases have been completed before advancing.
|
|
5
|
-
* Prevents skipping phases accidentally.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* morph-spec validate-phase <feature-name> <target-phase>
|
|
9
|
-
*
|
|
10
|
-
* Example:
|
|
11
|
-
* morph-spec validate-phase scheduled-reports implement
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import fs from 'fs';
|
|
15
|
-
import path from 'path';
|
|
16
|
-
import chalk from 'chalk';
|
|
17
|
-
import { loadState, getFeature } from '../lib/state-manager.js';
|
|
18
|
-
|
|
19
|
-
// Phase definitions with requirements
|
|
20
|
-
const PHASES = {
|
|
21
|
-
'proposal': {
|
|
22
|
-
order: 0,
|
|
23
|
-
name: 'FASE 0: PROPOSAL',
|
|
24
|
-
requiredOutputs: [],
|
|
25
|
-
description: 'Initial proposal and agent detection'
|
|
26
|
-
},
|
|
27
|
-
'setup': {
|
|
28
|
-
order: 1,
|
|
29
|
-
name: 'FASE 1: SETUP',
|
|
30
|
-
requiredOutputs: ['proposal.md'],
|
|
31
|
-
description: 'Load context and standards'
|
|
32
|
-
},
|
|
33
|
-
'uiux': {
|
|
34
|
-
order: 2,
|
|
35
|
-
name: 'FASE 1.5: UI/UX DESIGN',
|
|
36
|
-
requiredOutputs: ['proposal.md'],
|
|
37
|
-
optionalOutputs: ['ui-design-system.md', 'ui-mockups.md', 'ui-components.md', 'ui-flows.md'],
|
|
38
|
-
description: 'UI/UX design (conditional - only if frontend)',
|
|
39
|
-
optional: true
|
|
40
|
-
},
|
|
41
|
-
'design': {
|
|
42
|
-
order: 3,
|
|
43
|
-
name: 'FASE 2: DESIGN',
|
|
44
|
-
requiredOutputs: ['proposal.md'],
|
|
45
|
-
description: 'Technical specification and contracts'
|
|
46
|
-
},
|
|
47
|
-
'clarify': {
|
|
48
|
-
order: 4,
|
|
49
|
-
name: 'FASE 3: CLARIFY',
|
|
50
|
-
requiredOutputs: ['proposal.md', 'spec.md'],
|
|
51
|
-
description: 'Clarify ambiguities and edge cases'
|
|
52
|
-
},
|
|
53
|
-
'tasks': {
|
|
54
|
-
order: 5,
|
|
55
|
-
name: 'FASE 4: TASKS',
|
|
56
|
-
requiredOutputs: ['proposal.md', 'spec.md'],
|
|
57
|
-
description: 'Break down into executable tasks'
|
|
58
|
-
},
|
|
59
|
-
'implement': {
|
|
60
|
-
order: 6,
|
|
61
|
-
name: 'FASE 5: IMPLEMENT',
|
|
62
|
-
requiredOutputs: ['proposal.md', 'spec.md'],
|
|
63
|
-
description: 'Execute tasks and implement code'
|
|
64
|
-
},
|
|
65
|
-
'sync': {
|
|
66
|
-
order: 7,
|
|
67
|
-
name: 'FASE 6: SYNC',
|
|
68
|
-
requiredOutputs: ['proposal.md', 'spec.md', 'decisions.md'],
|
|
69
|
-
description: 'Sync decisions to project standards',
|
|
70
|
-
optional: true
|
|
71
|
-
}
|
|
72
|
-
};
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Check if output file exists
|
|
76
|
-
*/
|
|
77
|
-
function checkOutput(featurePath, outputFile) {
|
|
78
|
-
const filePath = path.join(featurePath, outputFile);
|
|
79
|
-
return fs.existsSync(filePath);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Validate phase requirements
|
|
84
|
-
*/
|
|
85
|
-
function validatePhase(featureName, targetPhase) {
|
|
86
|
-
const featurePath = path.join(process.cwd(), '.morph/project/outputs', featureName);
|
|
87
|
-
|
|
88
|
-
// Check if feature directory exists
|
|
89
|
-
if (!fs.existsSync(featurePath)) {
|
|
90
|
-
return {
|
|
91
|
-
valid: false,
|
|
92
|
-
error: `Feature directory not found: ${featurePath}`,
|
|
93
|
-
suggestion: `Run 'morph-spec state set ${featureName} phase proposal' to start`,
|
|
94
|
-
missingOutputs: [],
|
|
95
|
-
phase: null
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Get target phase definition
|
|
100
|
-
const phaseDefinition = PHASES[targetPhase];
|
|
101
|
-
if (!phaseDefinition) {
|
|
102
|
-
return {
|
|
103
|
-
valid: false,
|
|
104
|
-
error: `Unknown phase: ${targetPhase}`,
|
|
105
|
-
validPhases: Object.keys(PHASES),
|
|
106
|
-
missingOutputs: [],
|
|
107
|
-
phase: null
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Check required outputs
|
|
112
|
-
const missingOutputs = [];
|
|
113
|
-
for (const output of phaseDefinition.requiredOutputs) {
|
|
114
|
-
if (!checkOutput(featurePath, output)) {
|
|
115
|
-
missingOutputs.push(output);
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Check state.json for current phase
|
|
120
|
-
let stateWarning = null;
|
|
121
|
-
try {
|
|
122
|
-
const feature = getFeature(featureName);
|
|
123
|
-
if (feature) {
|
|
124
|
-
const currentPhaseOrder = PHASES[feature.phase]?.order ?? -1;
|
|
125
|
-
const targetPhaseOrder = phaseDefinition.order;
|
|
126
|
-
|
|
127
|
-
if (targetPhaseOrder > currentPhaseOrder + 1) {
|
|
128
|
-
stateWarning = `Skipping phases: current is '${feature.phase}' (order ${currentPhaseOrder}), target is '${targetPhase}' (order ${targetPhaseOrder})`;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
} catch {
|
|
132
|
-
// State file may not exist, that's OK
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Special validation: if target is 'implement', check tasks exist in state
|
|
136
|
-
if (targetPhase === 'implement') {
|
|
137
|
-
try {
|
|
138
|
-
const feature = getFeature(featureName);
|
|
139
|
-
if (feature && (!feature.tasks || feature.tasks.total === 0)) {
|
|
140
|
-
missingOutputs.push('tasks in state.json (run morph-spec task to add tasks)');
|
|
141
|
-
}
|
|
142
|
-
} catch {
|
|
143
|
-
// State file may not exist
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
return {
|
|
148
|
-
valid: missingOutputs.length === 0,
|
|
149
|
-
error: null,
|
|
150
|
-
missingOutputs,
|
|
151
|
-
phase: phaseDefinition,
|
|
152
|
-
featurePath,
|
|
153
|
-
stateWarning
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Main command handler
|
|
159
|
-
*/
|
|
160
|
-
export async function validatePhaseCommand(feature, phase, options = {}) {
|
|
161
|
-
console.log(chalk.cyan('\n╔════════════════════════════════════════════════╗'));
|
|
162
|
-
console.log(chalk.cyan('║ MORPH-SPEC PHASE VALIDATOR ║'));
|
|
163
|
-
console.log(chalk.cyan('╚════════════════════════════════════════════════╝\n'));
|
|
164
|
-
|
|
165
|
-
const result = validatePhase(feature, phase);
|
|
166
|
-
|
|
167
|
-
console.log(chalk.gray('Feature:'), feature);
|
|
168
|
-
console.log(chalk.gray('Target Phase:'), result.phase ? result.phase.name : phase);
|
|
169
|
-
|
|
170
|
-
if (result.phase) {
|
|
171
|
-
console.log(chalk.gray('Description:'), result.phase.description);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
if (result.stateWarning) {
|
|
175
|
-
console.log(chalk.yellow(`\n⚠️ Warning: ${result.stateWarning}`));
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (result.valid) {
|
|
179
|
-
console.log(chalk.green('\n✓ VALIDATION PASSED'));
|
|
180
|
-
console.log(chalk.green(' All required outputs are present.'));
|
|
181
|
-
console.log(chalk.green(` Safe to proceed to ${result.phase.name}\n`));
|
|
182
|
-
|
|
183
|
-
if (options.verbose) {
|
|
184
|
-
console.log(chalk.gray('Required outputs found:'));
|
|
185
|
-
result.phase.requiredOutputs.forEach(output => {
|
|
186
|
-
console.log(chalk.gray(` ✓ ${output}`));
|
|
187
|
-
});
|
|
188
|
-
console.log('');
|
|
189
|
-
}
|
|
190
|
-
} else {
|
|
191
|
-
console.log(chalk.red('\n✗ VALIDATION FAILED'));
|
|
192
|
-
|
|
193
|
-
if (result.error) {
|
|
194
|
-
console.log(chalk.red(` Error: ${result.error}\n`));
|
|
195
|
-
|
|
196
|
-
if (result.suggestion) {
|
|
197
|
-
console.log(chalk.yellow(` Suggestion: ${result.suggestion}\n`));
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (result.validPhases) {
|
|
201
|
-
console.log(chalk.yellow('Valid phases:'));
|
|
202
|
-
result.validPhases.forEach(p => {
|
|
203
|
-
const def = PHASES[p];
|
|
204
|
-
console.log(chalk.gray(` - ${p}: ${def.name}${def.optional ? ' (optional)' : ''}`));
|
|
205
|
-
});
|
|
206
|
-
}
|
|
207
|
-
} else {
|
|
208
|
-
console.log(chalk.red(' Missing required outputs:'));
|
|
209
|
-
result.missingOutputs.forEach(output => {
|
|
210
|
-
console.log(chalk.gray(` - ${output}`));
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
console.log(chalk.yellow(`\n Action required:`));
|
|
214
|
-
console.log(chalk.yellow(` Complete the missing outputs before advancing to ${result.phase.name}`));
|
|
215
|
-
}
|
|
216
|
-
console.log('');
|
|
217
|
-
process.exit(1);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
export { PHASES, validatePhase };
|
|
1
|
+
/**
|
|
2
|
+
* MORPH-SPEC Phase Validator Command
|
|
3
|
+
*
|
|
4
|
+
* Validates that required previous phases have been completed before advancing.
|
|
5
|
+
* Prevents skipping phases accidentally.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* morph-spec validate-phase <feature-name> <target-phase>
|
|
9
|
+
*
|
|
10
|
+
* Example:
|
|
11
|
+
* morph-spec validate-phase scheduled-reports implement
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import fs from 'fs';
|
|
15
|
+
import path from 'path';
|
|
16
|
+
import chalk from 'chalk';
|
|
17
|
+
import { loadState, getFeature } from '../lib/state-manager.js';
|
|
18
|
+
|
|
19
|
+
// Phase definitions with requirements
|
|
20
|
+
const PHASES = {
|
|
21
|
+
'proposal': {
|
|
22
|
+
order: 0,
|
|
23
|
+
name: 'FASE 0: PROPOSAL',
|
|
24
|
+
requiredOutputs: [],
|
|
25
|
+
description: 'Initial proposal and agent detection'
|
|
26
|
+
},
|
|
27
|
+
'setup': {
|
|
28
|
+
order: 1,
|
|
29
|
+
name: 'FASE 1: SETUP',
|
|
30
|
+
requiredOutputs: ['proposal.md'],
|
|
31
|
+
description: 'Load context and standards'
|
|
32
|
+
},
|
|
33
|
+
'uiux': {
|
|
34
|
+
order: 2,
|
|
35
|
+
name: 'FASE 1.5: UI/UX DESIGN',
|
|
36
|
+
requiredOutputs: ['proposal.md'],
|
|
37
|
+
optionalOutputs: ['ui-design-system.md', 'ui-mockups.md', 'ui-components.md', 'ui-flows.md'],
|
|
38
|
+
description: 'UI/UX design (conditional - only if frontend)',
|
|
39
|
+
optional: true
|
|
40
|
+
},
|
|
41
|
+
'design': {
|
|
42
|
+
order: 3,
|
|
43
|
+
name: 'FASE 2: DESIGN',
|
|
44
|
+
requiredOutputs: ['proposal.md'],
|
|
45
|
+
description: 'Technical specification and contracts'
|
|
46
|
+
},
|
|
47
|
+
'clarify': {
|
|
48
|
+
order: 4,
|
|
49
|
+
name: 'FASE 3: CLARIFY',
|
|
50
|
+
requiredOutputs: ['proposal.md', 'spec.md'],
|
|
51
|
+
description: 'Clarify ambiguities and edge cases'
|
|
52
|
+
},
|
|
53
|
+
'tasks': {
|
|
54
|
+
order: 5,
|
|
55
|
+
name: 'FASE 4: TASKS',
|
|
56
|
+
requiredOutputs: ['proposal.md', 'spec.md'],
|
|
57
|
+
description: 'Break down into executable tasks'
|
|
58
|
+
},
|
|
59
|
+
'implement': {
|
|
60
|
+
order: 6,
|
|
61
|
+
name: 'FASE 5: IMPLEMENT',
|
|
62
|
+
requiredOutputs: ['proposal.md', 'spec.md'],
|
|
63
|
+
description: 'Execute tasks and implement code'
|
|
64
|
+
},
|
|
65
|
+
'sync': {
|
|
66
|
+
order: 7,
|
|
67
|
+
name: 'FASE 6: SYNC',
|
|
68
|
+
requiredOutputs: ['proposal.md', 'spec.md', 'decisions.md'],
|
|
69
|
+
description: 'Sync decisions to project standards',
|
|
70
|
+
optional: true
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Check if output file exists
|
|
76
|
+
*/
|
|
77
|
+
function checkOutput(featurePath, outputFile) {
|
|
78
|
+
const filePath = path.join(featurePath, outputFile);
|
|
79
|
+
return fs.existsSync(filePath);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Validate phase requirements
|
|
84
|
+
*/
|
|
85
|
+
function validatePhase(featureName, targetPhase) {
|
|
86
|
+
const featurePath = path.join(process.cwd(), '.morph/project/outputs', featureName);
|
|
87
|
+
|
|
88
|
+
// Check if feature directory exists
|
|
89
|
+
if (!fs.existsSync(featurePath)) {
|
|
90
|
+
return {
|
|
91
|
+
valid: false,
|
|
92
|
+
error: `Feature directory not found: ${featurePath}`,
|
|
93
|
+
suggestion: `Run 'morph-spec state set ${featureName} phase proposal' to start`,
|
|
94
|
+
missingOutputs: [],
|
|
95
|
+
phase: null
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Get target phase definition
|
|
100
|
+
const phaseDefinition = PHASES[targetPhase];
|
|
101
|
+
if (!phaseDefinition) {
|
|
102
|
+
return {
|
|
103
|
+
valid: false,
|
|
104
|
+
error: `Unknown phase: ${targetPhase}`,
|
|
105
|
+
validPhases: Object.keys(PHASES),
|
|
106
|
+
missingOutputs: [],
|
|
107
|
+
phase: null
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Check required outputs
|
|
112
|
+
const missingOutputs = [];
|
|
113
|
+
for (const output of phaseDefinition.requiredOutputs) {
|
|
114
|
+
if (!checkOutput(featurePath, output)) {
|
|
115
|
+
missingOutputs.push(output);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Check state.json for current phase
|
|
120
|
+
let stateWarning = null;
|
|
121
|
+
try {
|
|
122
|
+
const feature = getFeature(featureName);
|
|
123
|
+
if (feature) {
|
|
124
|
+
const currentPhaseOrder = PHASES[feature.phase]?.order ?? -1;
|
|
125
|
+
const targetPhaseOrder = phaseDefinition.order;
|
|
126
|
+
|
|
127
|
+
if (targetPhaseOrder > currentPhaseOrder + 1) {
|
|
128
|
+
stateWarning = `Skipping phases: current is '${feature.phase}' (order ${currentPhaseOrder}), target is '${targetPhase}' (order ${targetPhaseOrder})`;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
} catch {
|
|
132
|
+
// State file may not exist, that's OK
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Special validation: if target is 'implement', check tasks exist in state
|
|
136
|
+
if (targetPhase === 'implement') {
|
|
137
|
+
try {
|
|
138
|
+
const feature = getFeature(featureName);
|
|
139
|
+
if (feature && (!feature.tasks || feature.tasks.total === 0)) {
|
|
140
|
+
missingOutputs.push('tasks in state.json (run morph-spec task to add tasks)');
|
|
141
|
+
}
|
|
142
|
+
} catch {
|
|
143
|
+
// State file may not exist
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
valid: missingOutputs.length === 0,
|
|
149
|
+
error: null,
|
|
150
|
+
missingOutputs,
|
|
151
|
+
phase: phaseDefinition,
|
|
152
|
+
featurePath,
|
|
153
|
+
stateWarning
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Main command handler
|
|
159
|
+
*/
|
|
160
|
+
export async function validatePhaseCommand(feature, phase, options = {}) {
|
|
161
|
+
console.log(chalk.cyan('\n╔════════════════════════════════════════════════╗'));
|
|
162
|
+
console.log(chalk.cyan('║ MORPH-SPEC PHASE VALIDATOR ║'));
|
|
163
|
+
console.log(chalk.cyan('╚════════════════════════════════════════════════╝\n'));
|
|
164
|
+
|
|
165
|
+
const result = validatePhase(feature, phase);
|
|
166
|
+
|
|
167
|
+
console.log(chalk.gray('Feature:'), feature);
|
|
168
|
+
console.log(chalk.gray('Target Phase:'), result.phase ? result.phase.name : phase);
|
|
169
|
+
|
|
170
|
+
if (result.phase) {
|
|
171
|
+
console.log(chalk.gray('Description:'), result.phase.description);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
if (result.stateWarning) {
|
|
175
|
+
console.log(chalk.yellow(`\n⚠️ Warning: ${result.stateWarning}`));
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (result.valid) {
|
|
179
|
+
console.log(chalk.green('\n✓ VALIDATION PASSED'));
|
|
180
|
+
console.log(chalk.green(' All required outputs are present.'));
|
|
181
|
+
console.log(chalk.green(` Safe to proceed to ${result.phase.name}\n`));
|
|
182
|
+
|
|
183
|
+
if (options.verbose) {
|
|
184
|
+
console.log(chalk.gray('Required outputs found:'));
|
|
185
|
+
result.phase.requiredOutputs.forEach(output => {
|
|
186
|
+
console.log(chalk.gray(` ✓ ${output}`));
|
|
187
|
+
});
|
|
188
|
+
console.log('');
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
console.log(chalk.red('\n✗ VALIDATION FAILED'));
|
|
192
|
+
|
|
193
|
+
if (result.error) {
|
|
194
|
+
console.log(chalk.red(` Error: ${result.error}\n`));
|
|
195
|
+
|
|
196
|
+
if (result.suggestion) {
|
|
197
|
+
console.log(chalk.yellow(` Suggestion: ${result.suggestion}\n`));
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (result.validPhases) {
|
|
201
|
+
console.log(chalk.yellow('Valid phases:'));
|
|
202
|
+
result.validPhases.forEach(p => {
|
|
203
|
+
const def = PHASES[p];
|
|
204
|
+
console.log(chalk.gray(` - ${p}: ${def.name}${def.optional ? ' (optional)' : ''}`));
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
console.log(chalk.red(' Missing required outputs:'));
|
|
209
|
+
result.missingOutputs.forEach(output => {
|
|
210
|
+
console.log(chalk.gray(` - ${output}`));
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
console.log(chalk.yellow(`\n Action required:`));
|
|
214
|
+
console.log(chalk.yellow(` Complete the missing outputs before advancing to ${result.phase.name}`));
|
|
215
|
+
}
|
|
216
|
+
console.log('');
|
|
217
|
+
process.exit(1);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export { PHASES, validatePhase };
|
|
File without changes
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview ConfigGenerator - Renders templates and generates config files
|
|
3
|
+
* @module morph-spec/generator/config-generator
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readFile, access, copyFile } from 'fs/promises';
|
|
7
|
+
import { join, dirname } from 'path';
|
|
8
|
+
import Handlebars from 'handlebars';
|
|
9
|
+
import { fileURLToPath } from 'url';
|
|
10
|
+
import Ajv from 'ajv';
|
|
11
|
+
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
13
|
+
const __dirname = dirname(__filename);
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* @typedef {import('../types/index.js').ProjectConfig} ProjectConfig
|
|
17
|
+
* @typedef {import('../types/index.js').GeneratedConfigs} GeneratedConfigs
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Validation Error
|
|
22
|
+
*/
|
|
23
|
+
export class ValidationError extends Error {
|
|
24
|
+
constructor(message, field, value) {
|
|
25
|
+
super(message);
|
|
26
|
+
this.name = 'ValidationError';
|
|
27
|
+
this.field = field;
|
|
28
|
+
this.value = value;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* ConfigGenerator - Generates configuration files from ProjectConfig
|
|
34
|
+
* @class
|
|
35
|
+
*/
|
|
36
|
+
export class ConfigGenerator {
|
|
37
|
+
constructor() {
|
|
38
|
+
this.projectMdTemplate = null;
|
|
39
|
+
this.configJsonTemplate = null;
|
|
40
|
+
this.ajv = new Ajv({ allErrors: true });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Load templates from filesystem
|
|
45
|
+
* @private
|
|
46
|
+
*/
|
|
47
|
+
async loadTemplates() {
|
|
48
|
+
if (this.projectMdTemplate && this.configJsonTemplate) {
|
|
49
|
+
return; // Already loaded
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const templatesDir = join(__dirname, 'templates');
|
|
53
|
+
|
|
54
|
+
const [projectMdSource, configJsonSource] = await Promise.all([
|
|
55
|
+
readFile(join(templatesDir, 'project.md.template'), 'utf-8'),
|
|
56
|
+
readFile(join(templatesDir, 'config.json.template'), 'utf-8')
|
|
57
|
+
]);
|
|
58
|
+
|
|
59
|
+
this.projectMdTemplate = Handlebars.compile(projectMdSource);
|
|
60
|
+
this.configJsonTemplate = Handlebars.compile(configJsonSource);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Generate configuration files from project config
|
|
65
|
+
* @param {ProjectConfig} projectConfig - Detected project config
|
|
66
|
+
* @returns {Promise<GeneratedConfigs>}
|
|
67
|
+
*/
|
|
68
|
+
async generate(projectConfig) {
|
|
69
|
+
// Load templates if not already loaded
|
|
70
|
+
await this.loadTemplates();
|
|
71
|
+
|
|
72
|
+
// Add generation timestamp
|
|
73
|
+
const context = {
|
|
74
|
+
...projectConfig,
|
|
75
|
+
generatedAt: new Date().toISOString()
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
// Render templates
|
|
79
|
+
const projectMd = this.renderProjectMd(context);
|
|
80
|
+
const configJson = this.renderConfigJson(context);
|
|
81
|
+
|
|
82
|
+
// Parse config.json to object
|
|
83
|
+
const configObject = JSON.parse(configJson);
|
|
84
|
+
|
|
85
|
+
// Validate config.json (optional, but good practice)
|
|
86
|
+
// Note: agent-schema.json validation would happen here if we had the schema
|
|
87
|
+
// For now, we just ensure it's valid JSON
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
projectMd,
|
|
91
|
+
configJson,
|
|
92
|
+
configObject
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Render project.md template
|
|
98
|
+
* @param {ProjectConfig} config - Project config
|
|
99
|
+
* @returns {string} Rendered markdown
|
|
100
|
+
*/
|
|
101
|
+
renderProjectMd(config) {
|
|
102
|
+
if (!this.projectMdTemplate) {
|
|
103
|
+
throw new Error('Templates not loaded. Call loadTemplates() first.');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return this.projectMdTemplate(config);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Render config.json template
|
|
111
|
+
* @param {ProjectConfig} config - Project config
|
|
112
|
+
* @returns {string} Rendered JSON string
|
|
113
|
+
*/
|
|
114
|
+
renderConfigJson(config) {
|
|
115
|
+
if (!this.configJsonTemplate) {
|
|
116
|
+
throw new Error('Templates not loaded. Call loadTemplates() first.');
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const rendered = this.configJsonTemplate(config);
|
|
120
|
+
|
|
121
|
+
// Validate that rendered output is valid JSON
|
|
122
|
+
try {
|
|
123
|
+
JSON.parse(rendered);
|
|
124
|
+
return rendered;
|
|
125
|
+
} catch (error) {
|
|
126
|
+
throw new ValidationError(
|
|
127
|
+
`Rendered config.json is not valid JSON: ${error.message}`,
|
|
128
|
+
'configJson',
|
|
129
|
+
rendered
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Validate config.json against agent schema
|
|
136
|
+
* @param {string} configJson - JSON string
|
|
137
|
+
* @returns {boolean} True if valid
|
|
138
|
+
* @throws {ValidationError} If validation fails
|
|
139
|
+
*/
|
|
140
|
+
validateConfigJson(configJson) {
|
|
141
|
+
// Parse JSON
|
|
142
|
+
let parsed;
|
|
143
|
+
try {
|
|
144
|
+
parsed = JSON.parse(configJson);
|
|
145
|
+
} catch (error) {
|
|
146
|
+
throw new ValidationError(
|
|
147
|
+
`Invalid JSON: ${error.message}`,
|
|
148
|
+
'configJson',
|
|
149
|
+
configJson
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Basic validation - ensure required fields exist
|
|
154
|
+
const requiredFields = ['name', 'type', 'description', 'stack', 'architecture'];
|
|
155
|
+
for (const field of requiredFields) {
|
|
156
|
+
if (!parsed[field]) {
|
|
157
|
+
throw new ValidationError(
|
|
158
|
+
`Missing required field: ${field}`,
|
|
159
|
+
field,
|
|
160
|
+
parsed
|
|
161
|
+
);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Validate stack.backend is required
|
|
166
|
+
if (!parsed.stack || !parsed.stack.backend) {
|
|
167
|
+
throw new ValidationError(
|
|
168
|
+
'stack.backend is required',
|
|
169
|
+
'stack.backend',
|
|
170
|
+
parsed
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
return true;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Backup existing configuration files
|
|
179
|
+
* @param {string} cwd - Current working directory
|
|
180
|
+
* @returns {Promise<void>}
|
|
181
|
+
*/
|
|
182
|
+
async backupExisting(cwd) {
|
|
183
|
+
const projectMdPath = join(cwd, '.morph', 'project.md');
|
|
184
|
+
const configJsonPath = join(cwd, '.morph', 'config', 'config.json');
|
|
185
|
+
|
|
186
|
+
const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
|
|
187
|
+
|
|
188
|
+
// Backup project.md if exists
|
|
189
|
+
try {
|
|
190
|
+
await access(projectMdPath);
|
|
191
|
+
const backupPath = join(cwd, '.morph', `project.md.${timestamp}.backup`);
|
|
192
|
+
await copyFile(projectMdPath, backupPath);
|
|
193
|
+
} catch (error) {
|
|
194
|
+
// File doesn't exist, no need to backup
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Backup config.json if exists
|
|
198
|
+
try {
|
|
199
|
+
await access(configJsonPath);
|
|
200
|
+
const backupPath = join(cwd, '.morph', 'config', `config.json.${timestamp}.backup`);
|
|
201
|
+
await copyFile(configJsonPath, backupPath);
|
|
202
|
+
} catch (error) {
|
|
203
|
+
// File doesn't exist, no need to backup
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../schema/agent-schema.json",
|
|
3
|
+
"name": "{{name}}",
|
|
4
|
+
"type": "{{type}}",
|
|
5
|
+
"description": "{{description}}",
|
|
6
|
+
"stack": {
|
|
7
|
+
{{#if stack.frontend}}
|
|
8
|
+
"frontend": {
|
|
9
|
+
"tech": "{{stack.frontend.tech}}",
|
|
10
|
+
"version": "{{stack.frontend.version}}"{{#if stack.frontend.details}},
|
|
11
|
+
"details": "{{stack.frontend.details}}"{{/if}}
|
|
12
|
+
},
|
|
13
|
+
{{/if}}
|
|
14
|
+
"backend": {
|
|
15
|
+
"tech": "{{stack.backend.tech}}",
|
|
16
|
+
"version": "{{stack.backend.version}}"{{#if stack.backend.details}},
|
|
17
|
+
"details": "{{stack.backend.details}}"{{/if}}
|
|
18
|
+
}{{#if stack.database}},
|
|
19
|
+
"database": {
|
|
20
|
+
"tech": "{{stack.database.tech}}",
|
|
21
|
+
"version": "{{stack.database.version}}"{{#if stack.database.details}},
|
|
22
|
+
"details": "{{stack.database.details}}"{{/if}}
|
|
23
|
+
}{{/if}}{{#if stack.hosting}},
|
|
24
|
+
"hosting": "{{stack.hosting}}"{{/if}}
|
|
25
|
+
},
|
|
26
|
+
"architecture": "{{architecture}}",
|
|
27
|
+
"conventions": "{{conventions}}",
|
|
28
|
+
"infrastructure": {
|
|
29
|
+
"azure": {{hasAzure}},
|
|
30
|
+
"docker": {{hasDocker}},
|
|
31
|
+
"devops": {{hasDevOps}}
|
|
32
|
+
}{{#if repository}},
|
|
33
|
+
"repository": "{{repository}}"{{/if}},
|
|
34
|
+
"meta": {
|
|
35
|
+
"generatedBy": "morph-spec-cli",
|
|
36
|
+
"generatedAt": "{{generatedAt}}",
|
|
37
|
+
"llmConfidence": {{confidence}},
|
|
38
|
+
"autoDetected": true
|
|
39
|
+
}
|
|
40
|
+
}
|