@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
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Migrate State Command - Upgrade state.json to v3.0 schema
|
|
8
|
+
*
|
|
9
|
+
* Adds approval gates to existing features
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const program = new Command();
|
|
13
|
+
|
|
14
|
+
program
|
|
15
|
+
.name('migrate-state')
|
|
16
|
+
.description('Migrate state.json to v3.0 schema (add approval gates)')
|
|
17
|
+
.option('--dry-run', 'Preview changes without writing')
|
|
18
|
+
.option('--force', 'Skip confirmation')
|
|
19
|
+
.action(async (options) => {
|
|
20
|
+
try {
|
|
21
|
+
const statePath = join(process.cwd(), '.morph/state.json');
|
|
22
|
+
|
|
23
|
+
if (!existsSync(statePath)) {
|
|
24
|
+
console.error(chalk.red(`\n❌ No state.json found at ${statePath}`));
|
|
25
|
+
console.log(chalk.yellow('This project may not be initialized with MORPH-SPEC.\n'));
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Read current state
|
|
30
|
+
const state = JSON.parse(readFileSync(statePath, 'utf8'));
|
|
31
|
+
|
|
32
|
+
console.log(chalk.cyan('\n🔄 Migrating state.json to v3.0 schema...\n'));
|
|
33
|
+
|
|
34
|
+
// Check if already migrated
|
|
35
|
+
if (state.version === '3.0.0') {
|
|
36
|
+
console.log(chalk.green('✅ State already at v3.0.0 - no migration needed\n'));
|
|
37
|
+
process.exit(0);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Track changes
|
|
41
|
+
let featuresUpdated = 0;
|
|
42
|
+
const changes = [];
|
|
43
|
+
|
|
44
|
+
// Migrate each feature
|
|
45
|
+
Object.entries(state.features || {}).forEach(([featureName, feature]) => {
|
|
46
|
+
// Skip if already has approvalGates
|
|
47
|
+
if (feature.approvalGates) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Determine which gates to auto-approve based on current phase
|
|
52
|
+
const currentPhase = feature.phase || 'proposal';
|
|
53
|
+
const approvalGates = {
|
|
54
|
+
proposal: { approved: false, timestamp: null, approvedBy: null },
|
|
55
|
+
uiux: { approved: false, timestamp: null, approvedBy: null },
|
|
56
|
+
design: { approved: false, timestamp: null, approvedBy: null },
|
|
57
|
+
tasks: { approved: false, timestamp: null, approvedBy: null }
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
// Auto-approve past gates
|
|
61
|
+
const phaseOrder = ['proposal', 'setup', 'uiux', 'design', 'clarify', 'tasks', 'implement', 'sync', 'archived'];
|
|
62
|
+
const currentPhaseIndex = phaseOrder.indexOf(currentPhase);
|
|
63
|
+
|
|
64
|
+
if (currentPhaseIndex >= phaseOrder.indexOf('proposal')) {
|
|
65
|
+
approvalGates.proposal.approved = true;
|
|
66
|
+
approvalGates.proposal.timestamp = feature.createdAt || new Date().toISOString();
|
|
67
|
+
approvalGates.proposal.approvedBy = 'auto-migration';
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (currentPhaseIndex >= phaseOrder.indexOf('design')) {
|
|
71
|
+
approvalGates.design.approved = true;
|
|
72
|
+
approvalGates.design.timestamp = feature.updatedAt || new Date().toISOString();
|
|
73
|
+
approvalGates.design.approvedBy = 'auto-migration';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (currentPhaseIndex >= phaseOrder.indexOf('tasks')) {
|
|
77
|
+
approvalGates.tasks.approved = true;
|
|
78
|
+
approvalGates.tasks.timestamp = feature.updatedAt || new Date().toISOString();
|
|
79
|
+
approvalGates.tasks.approvedBy = 'auto-migration';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Add approval gates to feature
|
|
83
|
+
feature.approvalGates = approvalGates;
|
|
84
|
+
|
|
85
|
+
featuresUpdated++;
|
|
86
|
+
changes.push({
|
|
87
|
+
feature: featureName,
|
|
88
|
+
phase: currentPhase,
|
|
89
|
+
approvedGates: Object.entries(approvalGates)
|
|
90
|
+
.filter(([_, gate]) => gate.approved)
|
|
91
|
+
.map(([name]) => name)
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
// Update state version
|
|
96
|
+
state.version = '3.0.0';
|
|
97
|
+
|
|
98
|
+
// Show changes
|
|
99
|
+
console.log(chalk.bold('📊 Migration Summary:\n'));
|
|
100
|
+
console.log(chalk.cyan(` Features to update: ${featuresUpdated}`));
|
|
101
|
+
|
|
102
|
+
if (changes.length > 0) {
|
|
103
|
+
console.log(chalk.gray('\n Changes:'));
|
|
104
|
+
changes.forEach(change => {
|
|
105
|
+
console.log(chalk.white(` - ${change.feature} (${change.phase})`));
|
|
106
|
+
console.log(chalk.gray(` Auto-approved gates: ${change.approvedGates.join(', ') || 'none'}`));
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
console.log('');
|
|
111
|
+
|
|
112
|
+
// Dry run
|
|
113
|
+
if (options.dryRun) {
|
|
114
|
+
console.log(chalk.yellow('🔍 DRY RUN - No changes written\n'));
|
|
115
|
+
console.log(chalk.gray('Run without --dry-run to apply migration.\n'));
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// Confirmation
|
|
120
|
+
if (!options.force) {
|
|
121
|
+
console.log(chalk.yellow('⚠️ This will modify .morph/state.json'));
|
|
122
|
+
console.log(chalk.gray(' A backup will be created at .morph/state.json.backup\n'));
|
|
123
|
+
console.log(chalk.gray(' Run with --force to skip this confirmation, or Ctrl+C to cancel.\n'));
|
|
124
|
+
|
|
125
|
+
// Wait for user confirmation (in CLI context, assume proceed for now)
|
|
126
|
+
// In real implementation, use inquirer for interactive confirmation
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Backup original
|
|
130
|
+
const backupPath = `${statePath}.backup`;
|
|
131
|
+
writeFileSync(backupPath, JSON.stringify(state, null, 2));
|
|
132
|
+
console.log(chalk.gray(`📦 Backup created: ${backupPath}\n`));
|
|
133
|
+
|
|
134
|
+
// Write migrated state
|
|
135
|
+
writeFileSync(statePath, JSON.stringify(state, null, 2));
|
|
136
|
+
|
|
137
|
+
console.log(chalk.green('✅ Migration complete!\n'));
|
|
138
|
+
console.log(chalk.bold('Next steps:\n'));
|
|
139
|
+
console.log(chalk.gray('1. Review .morph/config/llm-interaction.json (created on next init)'));
|
|
140
|
+
console.log(chalk.gray('2. Configure approval gates, checkpoints, patterns'));
|
|
141
|
+
console.log(chalk.gray('3. Continue working with v3.0 features\n'));
|
|
142
|
+
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error(chalk.red(`\n❌ Migration failed: ${error.message}\n`));
|
|
145
|
+
process.exit(1);
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
// Only parse if run directly (not imported as module)
|
|
150
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
151
|
+
if (process.argv.length > 2) {
|
|
152
|
+
program.parse(process.argv);
|
|
153
|
+
} else {
|
|
154
|
+
program.help();
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
export default program;
|
|
@@ -1,185 +1,185 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MORPH-SPEC Rollback Phase Command
|
|
3
|
-
*
|
|
4
|
-
* Rolls back a feature to a previous phase, marking outputs as draft.
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
* morph-spec rollback <feature-name> <target-phase>
|
|
8
|
-
*
|
|
9
|
-
* Example:
|
|
10
|
-
* morph-spec rollback scheduled-reports design
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import fs from 'fs';
|
|
14
|
-
import path from 'path';
|
|
15
|
-
import chalk from 'chalk';
|
|
16
|
-
import { loadState, saveState, getFeature, updateFeature } from '../lib/state-manager.js';
|
|
17
|
-
|
|
18
|
-
// Phase order
|
|
19
|
-
const PHASE_ORDER = ['proposal', 'setup', 'uiux', 'design', 'clarify', 'tasks', 'implement', 'sync'];
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Get phase index
|
|
23
|
-
*/
|
|
24
|
-
function getPhaseIndex(phase) {
|
|
25
|
-
return PHASE_ORDER.indexOf(phase);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Get outputs that should be marked as draft when rolling back
|
|
30
|
-
*/
|
|
31
|
-
function getOutputsToReset(fromPhase, toPhase) {
|
|
32
|
-
const fromIndex = getPhaseIndex(fromPhase);
|
|
33
|
-
const toIndex = getPhaseIndex(toPhase);
|
|
34
|
-
|
|
35
|
-
// Map phases to their outputs
|
|
36
|
-
const phaseOutputs = {
|
|
37
|
-
'proposal': ['proposal'],
|
|
38
|
-
'setup': [],
|
|
39
|
-
'uiux': ['uiDesignSystem', 'uiMockups', 'uiComponents', 'uiFlows'],
|
|
40
|
-
'design': ['spec', 'contracts', 'decisions'],
|
|
41
|
-
'clarify': [],
|
|
42
|
-
'tasks': ['tasks'],
|
|
43
|
-
'implement': ['recap'],
|
|
44
|
-
'sync': []
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
const outputsToReset = [];
|
|
48
|
-
|
|
49
|
-
// Collect all outputs from phases after target
|
|
50
|
-
for (let i = toIndex + 1; i <= fromIndex; i++) {
|
|
51
|
-
const phase = PHASE_ORDER[i];
|
|
52
|
-
if (phaseOutputs[phase]) {
|
|
53
|
-
outputsToReset.push(...phaseOutputs[phase]);
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return outputsToReset;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Main command handler
|
|
62
|
-
*/
|
|
63
|
-
export async function rollbackPhaseCommand(feature, targetPhase, options = {}) {
|
|
64
|
-
console.log(chalk.cyan('\n╔════════════════════════════════════════════════╗'));
|
|
65
|
-
console.log(chalk.cyan('║ MORPH-SPEC ROLLBACK ║'));
|
|
66
|
-
console.log(chalk.cyan('╚════════════════════════════════════════════════╝\n'));
|
|
67
|
-
|
|
68
|
-
// Validate target phase
|
|
69
|
-
if (!PHASE_ORDER.includes(targetPhase)) {
|
|
70
|
-
console.log(chalk.red(`❌ Invalid phase: ${targetPhase}`));
|
|
71
|
-
console.log(chalk.gray('\nValid phases:'));
|
|
72
|
-
PHASE_ORDER.forEach(p => console.log(chalk.gray(` - ${p}`)));
|
|
73
|
-
process.exit(1);
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
// Get current feature state
|
|
77
|
-
let featureState;
|
|
78
|
-
try {
|
|
79
|
-
featureState = getFeature(feature);
|
|
80
|
-
} catch (error) {
|
|
81
|
-
console.log(chalk.red(`❌ Feature not found: ${feature}`));
|
|
82
|
-
console.log(chalk.gray(' Run: morph-spec state list'));
|
|
83
|
-
process.exit(1);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
if (!featureState) {
|
|
87
|
-
console.log(chalk.red(`❌ Feature not found: ${feature}`));
|
|
88
|
-
process.exit(1);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const currentPhase = featureState.phase || 'proposal';
|
|
92
|
-
const currentIndex = getPhaseIndex(currentPhase);
|
|
93
|
-
const targetIndex = getPhaseIndex(targetPhase);
|
|
94
|
-
|
|
95
|
-
// Check if rollback makes sense
|
|
96
|
-
if (targetIndex >= currentIndex) {
|
|
97
|
-
console.log(chalk.yellow(`⚠️ Cannot rollback: target phase '${targetPhase}' is not before current phase '${currentPhase}'`));
|
|
98
|
-
process.exit(1);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
// Get outputs to reset
|
|
102
|
-
const outputsToReset = getOutputsToReset(currentPhase, targetPhase);
|
|
103
|
-
|
|
104
|
-
// Show what will happen
|
|
105
|
-
console.log(chalk.gray('Feature:'), feature);
|
|
106
|
-
console.log(chalk.gray('Current Phase:'), currentPhase);
|
|
107
|
-
console.log(chalk.gray('Target Phase:'), targetPhase);
|
|
108
|
-
console.log('');
|
|
109
|
-
|
|
110
|
-
if (outputsToReset.length > 0) {
|
|
111
|
-
console.log(chalk.yellow('Outputs that will be marked as draft:'));
|
|
112
|
-
outputsToReset.forEach(o => {
|
|
113
|
-
console.log(chalk.gray(` - ${o}`));
|
|
114
|
-
});
|
|
115
|
-
console.log('');
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Confirm unless --force
|
|
119
|
-
if (!options.force) {
|
|
120
|
-
console.log(chalk.yellow('⚠️ This will:'));
|
|
121
|
-
console.log(chalk.gray(' 1. Set phase back to: ' + targetPhase));
|
|
122
|
-
console.log(chalk.gray(' 2. Reset task progress'));
|
|
123
|
-
console.log(chalk.gray(' 3. Mark outputs as not created (files remain on disk)'));
|
|
124
|
-
console.log('');
|
|
125
|
-
console.log(chalk.gray('Run with --force to confirm.'));
|
|
126
|
-
process.exit(1);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Perform rollback
|
|
130
|
-
try {
|
|
131
|
-
const state = loadState();
|
|
132
|
-
|
|
133
|
-
// Update phase
|
|
134
|
-
state.features[feature].phase = targetPhase;
|
|
135
|
-
state.features[feature].status = 'in_progress';
|
|
136
|
-
state.features[feature].updatedAt = new Date().toISOString();
|
|
137
|
-
|
|
138
|
-
// Reset outputs
|
|
139
|
-
for (const output of outputsToReset) {
|
|
140
|
-
if (state.features[feature].outputs[output]) {
|
|
141
|
-
state.features[feature].outputs[output].created = false;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Reset tasks if rolling back before tasks phase
|
|
146
|
-
if (targetIndex < getPhaseIndex('tasks')) {
|
|
147
|
-
state.features[feature].tasks = {
|
|
148
|
-
total: 0,
|
|
149
|
-
completed: 0,
|
|
150
|
-
inProgress: 0,
|
|
151
|
-
pending: 0
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
// Add checkpoint for rollback
|
|
156
|
-
state.features[feature].checkpoints = state.features[feature].checkpoints || [];
|
|
157
|
-
state.features[feature].checkpoints.push({
|
|
158
|
-
timestamp: new Date().toISOString(),
|
|
159
|
-
phase: targetPhase,
|
|
160
|
-
completedTasks: 0,
|
|
161
|
-
note: `Rollback from ${currentPhase} to ${targetPhase}`
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
// Track skipped phases (if any were skipped)
|
|
165
|
-
if (!state.features[feature].skippedPhases) {
|
|
166
|
-
state.features[feature].skippedPhases = [];
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
saveState(state);
|
|
170
|
-
|
|
171
|
-
console.log(chalk.green('✅ Rollback completed!'));
|
|
172
|
-
console.log('');
|
|
173
|
-
console.log(chalk.gray('Current state:'));
|
|
174
|
-
console.log(chalk.gray(` Phase: ${targetPhase}`));
|
|
175
|
-
console.log(chalk.gray(` Status: in_progress`));
|
|
176
|
-
console.log('');
|
|
177
|
-
console.log(chalk.cyan('Next steps:'));
|
|
178
|
-
console.log(chalk.gray(` 1. Review and update outputs for phase: ${targetPhase}`));
|
|
179
|
-
console.log(chalk.gray(` 2. Run: morph-spec session-summary ${feature}`));
|
|
180
|
-
|
|
181
|
-
} catch (error) {
|
|
182
|
-
console.log(chalk.red(`❌ Rollback failed: ${error.message}`));
|
|
183
|
-
process.exit(1);
|
|
184
|
-
}
|
|
185
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* MORPH-SPEC Rollback Phase Command
|
|
3
|
+
*
|
|
4
|
+
* Rolls back a feature to a previous phase, marking outputs as draft.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* morph-spec rollback <feature-name> <target-phase>
|
|
8
|
+
*
|
|
9
|
+
* Example:
|
|
10
|
+
* morph-spec rollback scheduled-reports design
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import fs from 'fs';
|
|
14
|
+
import path from 'path';
|
|
15
|
+
import chalk from 'chalk';
|
|
16
|
+
import { loadState, saveState, getFeature, updateFeature } from '../lib/state-manager.js';
|
|
17
|
+
|
|
18
|
+
// Phase order
|
|
19
|
+
const PHASE_ORDER = ['proposal', 'setup', 'uiux', 'design', 'clarify', 'tasks', 'implement', 'sync'];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Get phase index
|
|
23
|
+
*/
|
|
24
|
+
function getPhaseIndex(phase) {
|
|
25
|
+
return PHASE_ORDER.indexOf(phase);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Get outputs that should be marked as draft when rolling back
|
|
30
|
+
*/
|
|
31
|
+
function getOutputsToReset(fromPhase, toPhase) {
|
|
32
|
+
const fromIndex = getPhaseIndex(fromPhase);
|
|
33
|
+
const toIndex = getPhaseIndex(toPhase);
|
|
34
|
+
|
|
35
|
+
// Map phases to their outputs
|
|
36
|
+
const phaseOutputs = {
|
|
37
|
+
'proposal': ['proposal'],
|
|
38
|
+
'setup': [],
|
|
39
|
+
'uiux': ['uiDesignSystem', 'uiMockups', 'uiComponents', 'uiFlows'],
|
|
40
|
+
'design': ['spec', 'contracts', 'decisions'],
|
|
41
|
+
'clarify': [],
|
|
42
|
+
'tasks': ['tasks'],
|
|
43
|
+
'implement': ['recap'],
|
|
44
|
+
'sync': []
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const outputsToReset = [];
|
|
48
|
+
|
|
49
|
+
// Collect all outputs from phases after target
|
|
50
|
+
for (let i = toIndex + 1; i <= fromIndex; i++) {
|
|
51
|
+
const phase = PHASE_ORDER[i];
|
|
52
|
+
if (phaseOutputs[phase]) {
|
|
53
|
+
outputsToReset.push(...phaseOutputs[phase]);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return outputsToReset;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Main command handler
|
|
62
|
+
*/
|
|
63
|
+
export async function rollbackPhaseCommand(feature, targetPhase, options = {}) {
|
|
64
|
+
console.log(chalk.cyan('\n╔════════════════════════════════════════════════╗'));
|
|
65
|
+
console.log(chalk.cyan('║ MORPH-SPEC ROLLBACK ║'));
|
|
66
|
+
console.log(chalk.cyan('╚════════════════════════════════════════════════╝\n'));
|
|
67
|
+
|
|
68
|
+
// Validate target phase
|
|
69
|
+
if (!PHASE_ORDER.includes(targetPhase)) {
|
|
70
|
+
console.log(chalk.red(`❌ Invalid phase: ${targetPhase}`));
|
|
71
|
+
console.log(chalk.gray('\nValid phases:'));
|
|
72
|
+
PHASE_ORDER.forEach(p => console.log(chalk.gray(` - ${p}`)));
|
|
73
|
+
process.exit(1);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Get current feature state
|
|
77
|
+
let featureState;
|
|
78
|
+
try {
|
|
79
|
+
featureState = getFeature(feature);
|
|
80
|
+
} catch (error) {
|
|
81
|
+
console.log(chalk.red(`❌ Feature not found: ${feature}`));
|
|
82
|
+
console.log(chalk.gray(' Run: morph-spec state list'));
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (!featureState) {
|
|
87
|
+
console.log(chalk.red(`❌ Feature not found: ${feature}`));
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const currentPhase = featureState.phase || 'proposal';
|
|
92
|
+
const currentIndex = getPhaseIndex(currentPhase);
|
|
93
|
+
const targetIndex = getPhaseIndex(targetPhase);
|
|
94
|
+
|
|
95
|
+
// Check if rollback makes sense
|
|
96
|
+
if (targetIndex >= currentIndex) {
|
|
97
|
+
console.log(chalk.yellow(`⚠️ Cannot rollback: target phase '${targetPhase}' is not before current phase '${currentPhase}'`));
|
|
98
|
+
process.exit(1);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Get outputs to reset
|
|
102
|
+
const outputsToReset = getOutputsToReset(currentPhase, targetPhase);
|
|
103
|
+
|
|
104
|
+
// Show what will happen
|
|
105
|
+
console.log(chalk.gray('Feature:'), feature);
|
|
106
|
+
console.log(chalk.gray('Current Phase:'), currentPhase);
|
|
107
|
+
console.log(chalk.gray('Target Phase:'), targetPhase);
|
|
108
|
+
console.log('');
|
|
109
|
+
|
|
110
|
+
if (outputsToReset.length > 0) {
|
|
111
|
+
console.log(chalk.yellow('Outputs that will be marked as draft:'));
|
|
112
|
+
outputsToReset.forEach(o => {
|
|
113
|
+
console.log(chalk.gray(` - ${o}`));
|
|
114
|
+
});
|
|
115
|
+
console.log('');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Confirm unless --force
|
|
119
|
+
if (!options.force) {
|
|
120
|
+
console.log(chalk.yellow('⚠️ This will:'));
|
|
121
|
+
console.log(chalk.gray(' 1. Set phase back to: ' + targetPhase));
|
|
122
|
+
console.log(chalk.gray(' 2. Reset task progress'));
|
|
123
|
+
console.log(chalk.gray(' 3. Mark outputs as not created (files remain on disk)'));
|
|
124
|
+
console.log('');
|
|
125
|
+
console.log(chalk.gray('Run with --force to confirm.'));
|
|
126
|
+
process.exit(1);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Perform rollback
|
|
130
|
+
try {
|
|
131
|
+
const state = loadState();
|
|
132
|
+
|
|
133
|
+
// Update phase
|
|
134
|
+
state.features[feature].phase = targetPhase;
|
|
135
|
+
state.features[feature].status = 'in_progress';
|
|
136
|
+
state.features[feature].updatedAt = new Date().toISOString();
|
|
137
|
+
|
|
138
|
+
// Reset outputs
|
|
139
|
+
for (const output of outputsToReset) {
|
|
140
|
+
if (state.features[feature].outputs[output]) {
|
|
141
|
+
state.features[feature].outputs[output].created = false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Reset tasks if rolling back before tasks phase
|
|
146
|
+
if (targetIndex < getPhaseIndex('tasks')) {
|
|
147
|
+
state.features[feature].tasks = {
|
|
148
|
+
total: 0,
|
|
149
|
+
completed: 0,
|
|
150
|
+
inProgress: 0,
|
|
151
|
+
pending: 0
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Add checkpoint for rollback
|
|
156
|
+
state.features[feature].checkpoints = state.features[feature].checkpoints || [];
|
|
157
|
+
state.features[feature].checkpoints.push({
|
|
158
|
+
timestamp: new Date().toISOString(),
|
|
159
|
+
phase: targetPhase,
|
|
160
|
+
completedTasks: 0,
|
|
161
|
+
note: `Rollback from ${currentPhase} to ${targetPhase}`
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// Track skipped phases (if any were skipped)
|
|
165
|
+
if (!state.features[feature].skippedPhases) {
|
|
166
|
+
state.features[feature].skippedPhases = [];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
saveState(state);
|
|
170
|
+
|
|
171
|
+
console.log(chalk.green('✅ Rollback completed!'));
|
|
172
|
+
console.log('');
|
|
173
|
+
console.log(chalk.gray('Current state:'));
|
|
174
|
+
console.log(chalk.gray(` Phase: ${targetPhase}`));
|
|
175
|
+
console.log(chalk.gray(` Status: in_progress`));
|
|
176
|
+
console.log('');
|
|
177
|
+
console.log(chalk.cyan('Next steps:'));
|
|
178
|
+
console.log(chalk.gray(` 1. Review and update outputs for phase: ${targetPhase}`));
|
|
179
|
+
console.log(chalk.gray(` 2. Run: morph-spec session-summary ${feature}`));
|
|
180
|
+
|
|
181
|
+
} catch (error) {
|
|
182
|
+
console.log(chalk.red(`❌ Rollback failed: ${error.message}`));
|
|
183
|
+
process.exit(1);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { Command } from 'commander';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { readFileSync, existsSync } from 'fs';
|
|
4
|
+
import { join } from 'path';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Search Patterns Command - Find relevant patterns
|
|
8
|
+
*
|
|
9
|
+
* Searches patterns-learned.md for keywords
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
const program = new Command();
|
|
13
|
+
|
|
14
|
+
program
|
|
15
|
+
.name('search-patterns')
|
|
16
|
+
.description('Search for patterns by keyword')
|
|
17
|
+
.argument('<keyword>', 'Keyword to search for')
|
|
18
|
+
.option('--category <category>', 'Filter by category')
|
|
19
|
+
.option('--limit <number>', 'Limit number of results', '10')
|
|
20
|
+
.option('--json', 'Output as JSON', false)
|
|
21
|
+
.action(async (keyword, options) => {
|
|
22
|
+
try {
|
|
23
|
+
// Get patterns file path
|
|
24
|
+
const patternsPath = join(process.cwd(), '.morph/memory/patterns-learned.md');
|
|
25
|
+
|
|
26
|
+
if (!existsSync(patternsPath)) {
|
|
27
|
+
console.error(chalk.red(`\n❌ Patterns file not found: ${patternsPath}`));
|
|
28
|
+
console.log(chalk.yellow('No patterns learned yet. Complete some features first!\n'));
|
|
29
|
+
process.exit(1);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// Read patterns file
|
|
33
|
+
const content = readFileSync(patternsPath, 'utf8');
|
|
34
|
+
|
|
35
|
+
// Split into pattern sections
|
|
36
|
+
const sections = content.split('---').filter(s => s.trim().length > 0);
|
|
37
|
+
|
|
38
|
+
// Search patterns
|
|
39
|
+
const keywordLower = keyword.toLowerCase();
|
|
40
|
+
const matches = [];
|
|
41
|
+
|
|
42
|
+
sections.forEach(section => {
|
|
43
|
+
if (section.toLowerCase().includes(keywordLower)) {
|
|
44
|
+
// Extract pattern name
|
|
45
|
+
const nameMatch = section.match(/## Pattern: (.+)/);
|
|
46
|
+
const categoryMatch = section.match(/\*\*Category:\*\* (.+)/);
|
|
47
|
+
const sourceMatch = section.match(/\*\*Source:\*\* (.+)/);
|
|
48
|
+
|
|
49
|
+
if (nameMatch) {
|
|
50
|
+
const patternName = nameMatch[1].trim();
|
|
51
|
+
const category = categoryMatch ? categoryMatch[1].trim() : 'Unknown';
|
|
52
|
+
const source = sourceMatch ? sourceMatch[1].trim() : 'Unknown';
|
|
53
|
+
|
|
54
|
+
// Filter by category if specified
|
|
55
|
+
if (options.category && !category.toLowerCase().includes(options.category.toLowerCase())) {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
matches.push({
|
|
60
|
+
name: patternName,
|
|
61
|
+
category,
|
|
62
|
+
source,
|
|
63
|
+
content: section.trim(),
|
|
64
|
+
preview: section.substring(0, 300).trim() + '...'
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
// Limit results
|
|
71
|
+
const limit = parseInt(options.limit, 10);
|
|
72
|
+
const limitedMatches = matches.slice(0, limit);
|
|
73
|
+
|
|
74
|
+
if (options.json) {
|
|
75
|
+
// JSON output
|
|
76
|
+
console.log(JSON.stringify({ keyword, matches: limitedMatches, total: matches.length }, null, 2));
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Pretty output
|
|
81
|
+
if (limitedMatches.length === 0) {
|
|
82
|
+
console.log(chalk.yellow(`\n⚠️ No patterns found for keyword: "${keyword}"\n`));
|
|
83
|
+
console.log(chalk.gray('Try a different keyword or broader search term.\n'));
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
console.log(chalk.bold(`\n🔍 Found ${matches.length} pattern(s) for: "${keyword}"`));
|
|
88
|
+
if (matches.length > limit) {
|
|
89
|
+
console.log(chalk.gray(`Showing first ${limit} results (use --limit to see more)\n`));
|
|
90
|
+
}
|
|
91
|
+
console.log('━'.repeat(60));
|
|
92
|
+
|
|
93
|
+
limitedMatches.forEach((match, index) => {
|
|
94
|
+
console.log(chalk.green(`\n${index + 1}. ${match.name}`));
|
|
95
|
+
console.log(chalk.cyan(` Category: ${match.category}`));
|
|
96
|
+
console.log(chalk.gray(` Source: ${match.source}`));
|
|
97
|
+
|
|
98
|
+
// Show first few lines of the pattern
|
|
99
|
+
const lines = match.content.split('\n').slice(0, 15);
|
|
100
|
+
console.log(chalk.gray('\n ' + lines.join('\n ')));
|
|
101
|
+
|
|
102
|
+
if (match.content.split('\n').length > 15) {
|
|
103
|
+
console.log(chalk.gray(` ... (see full pattern in ${patternsPath})`));
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
console.log('\n' + '━'.repeat(60));
|
|
108
|
+
console.log(chalk.bold('\n💡 Usage:'));
|
|
109
|
+
console.log(chalk.gray(` Edit ${patternsPath} to see full pattern details\n`));
|
|
110
|
+
|
|
111
|
+
} catch (error) {
|
|
112
|
+
console.error(chalk.red(`\n❌ Error searching patterns: ${error.message}\n`));
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
// Only parse if run directly (not imported as module)
|
|
118
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
119
|
+
if (process.argv.length > 2) {
|
|
120
|
+
program.parse(process.argv);
|
|
121
|
+
} else {
|
|
122
|
+
program.help();
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export default program;
|