@polymorphism-tech/morph-spec 4.7.2 → 4.8.1
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/.morph/analytics/threads-log.jsonl +54 -5
- package/.morph/state.json +152 -2
- package/LICENSE +1 -2
- package/README.md +379 -414
- package/bin/morph-spec.js +57 -394
- package/bin/validate.js +2 -26
- package/claude-plugin.json +2 -2
- package/docs/ARCHITECTURE.md +43 -46
- package/docs/CHEATSHEET.md +203 -221
- package/docs/COMMAND-FLOWS.md +319 -289
- package/docs/QUICKSTART.md +2 -8
- package/docs/plans/2026-02-22-claude-docs-morph-alignment-analysis.md +2 -0
- package/docs/plans/2026-02-22-claude-settings.md +2 -0
- package/docs/plans/2026-02-22-morph-cc-alignment-impl.md +2 -0
- package/docs/plans/2026-02-22-morph-spec-next.md +2 -0
- package/docs/plans/2026-02-22-native-alignment-design.md +2 -0
- package/docs/plans/2026-02-22-native-alignment-impl.md +2 -0
- package/docs/plans/2026-02-22-native-enrichment-design.md +2 -0
- package/docs/plans/2026-02-22-native-enrichment.md +2 -0
- package/docs/plans/2026-02-23-ddd-architecture-refactor.md +2 -0
- package/docs/plans/2026-02-23-ddd-nextsteps.md +2 -0
- package/docs/plans/2026-02-23-infra-architect-refactor.md +2 -0
- package/docs/plans/2026-02-23-nextjs-code-review-design.md +2 -1
- package/docs/plans/2026-02-23-nextjs-code-review-impl.md +2 -0
- package/docs/plans/2026-02-23-nextjs-standards-design.md +2 -1
- package/docs/plans/2026-02-23-nextjs-standards-impl.md +2 -0
- package/docs/plans/2026-02-24-cli-radical-simplification.md +592 -0
- package/docs/plans/2026-02-24-framework-failure-points.md +125 -0
- package/docs/plans/2026-02-24-morph-init-design.md +337 -0
- package/docs/plans/2026-02-24-morph-init-impl.md +1269 -0
- package/docs/plans/2026-02-24-tutorial-command-design.md +71 -0
- package/docs/plans/2026-02-24-tutorial-command.md +298 -0
- package/framework/CLAUDE.md +1 -1
- package/framework/commands/morph-proposal.md +3 -3
- package/framework/hooks/README.md +2 -5
- package/framework/hooks/claude-code/pre-tool-use/protect-readonly-files.js +4 -55
- package/framework/hooks/claude-code/session-start/inject-morph-context.js +20 -5
- package/framework/hooks/claude-code/statusline.py +6 -1
- package/framework/hooks/dev/check-sync-health.js +117 -0
- package/framework/hooks/dev/guard-version-numbers.js +57 -0
- package/framework/hooks/dev/sync-standards-registry.js +60 -0
- package/framework/hooks/dev/sync-template-registry.js +60 -0
- package/framework/hooks/dev/validate-skill-format.js +70 -0
- package/framework/hooks/dev/validate-standard-format.js +73 -0
- package/framework/hooks/shared/payload-utils.js +39 -0
- package/framework/hooks/shared/state-reader.js +25 -1
- package/framework/rules/morph-workflow.md +1 -1
- package/framework/skills/level-0-meta/morph-init/SKILL.md +216 -0
- package/framework/skills/level-0-meta/morph-replicate/SKILL.md +4 -4
- package/framework/skills/level-0-meta/tool-usage-guide/SKILL.md +4 -4
- package/framework/skills/level-0-meta/verification-before-completion/SKILL.md +1 -1
- package/framework/skills/level-1-workflows/phase-clarify/SKILL.md +192 -191
- package/framework/skills/level-1-workflows/phase-codebase-analysis/SKILL.md +181 -180
- package/framework/skills/level-1-workflows/phase-design/SKILL.md +339 -338
- package/framework/skills/level-1-workflows/phase-implement/SKILL.md +254 -253
- package/framework/skills/level-1-workflows/phase-setup/SKILL.md +168 -170
- package/framework/skills/level-1-workflows/phase-tasks/SKILL.md +284 -283
- package/framework/skills/level-1-workflows/phase-uiux/SKILL.md +246 -245
- package/framework/templates/examples/design-system-examples.md +1 -1
- package/framework/templates/ui/FluentDesignTheme.cs +1 -1
- package/framework/templates/ui/MudTheme.cs +1 -1
- package/framework/templates/ui/design-system.css +1 -1
- package/package.json +4 -2
- package/scripts/bump-version.js +248 -0
- package/scripts/install-dev-hooks.js +138 -0
- package/src/commands/agents/index.js +1 -2
- package/src/commands/index.js +13 -16
- package/src/commands/project/doctor.js +100 -14
- package/src/commands/project/index.js +7 -10
- package/src/commands/project/init.js +398 -528
- package/src/commands/project/install-plugin-cmd.js +28 -0
- package/src/commands/project/setup-infra-cmd.js +12 -0
- package/src/commands/project/tutorial.js +115 -0
- package/src/commands/state/approve.js +213 -221
- package/src/commands/state/index.js +0 -1
- package/src/commands/state/state.js +337 -365
- package/src/commands/templates/index.js +0 -4
- package/src/commands/trust/trust.js +1 -93
- package/src/commands/utils/index.js +1 -5
- package/src/commands/validation/index.js +1 -5
- package/src/core/registry/command-registry.js +11 -285
- package/src/core/state/state-manager.js +5 -2
- package/src/lib/detectors/index.js +81 -87
- package/src/lib/detectors/structure-detector.js +275 -273
- package/src/lib/generators/recap-generator.js +232 -225
- package/src/scripts/global-install.js +34 -0
- package/src/scripts/install-plugin.js +126 -0
- package/src/scripts/setup-infra.js +203 -0
- package/src/utils/agents-installer.js +10 -1
- package/src/utils/hooks-installer.js +66 -3
- package/.morph/.morphversion +0 -5
- package/.morph/config/config.json +0 -8
- package/.morph/framework/agents.json +0 -1815
- package/.morph/framework/hooks/README.md +0 -205
- package/.morph/framework/hooks/claude-code/notification/approval-reminder.js +0 -54
- package/.morph/framework/hooks/claude-code/post-tool-use/dispatch.js +0 -83
- package/.morph/framework/hooks/claude-code/post-tool-use/handle-tool-failure.js +0 -42
- package/.morph/framework/hooks/claude-code/pre-compact/save-morph-context.js +0 -61
- package/.morph/framework/hooks/claude-code/pre-tool-use/enforce-phase-writes.js +0 -71
- package/.morph/framework/hooks/claude-code/pre-tool-use/protect-readonly-files.js +0 -58
- package/.morph/framework/hooks/claude-code/pre-tool-use/protect-spec-files.js +0 -64
- package/.morph/framework/hooks/claude-code/session-start/inject-morph-context.js +0 -94
- package/.morph/framework/hooks/claude-code/statusline.py +0 -538
- package/.morph/framework/hooks/claude-code/statusline.sh +0 -7
- package/.morph/framework/hooks/claude-code/stop/validate-completion.js +0 -88
- package/.morph/framework/hooks/claude-code/user-prompt/enrich-prompt.js +0 -91
- package/.morph/framework/hooks/git/commit-msg/conventional-commits.sh +0 -33
- package/.morph/framework/hooks/git/pre-commit/agents.sh +0 -25
- package/.morph/framework/hooks/git/pre-commit/orchestrator.sh +0 -64
- package/.morph/framework/hooks/git/pre-commit/specs.sh +0 -50
- package/.morph/framework/hooks/git/pre-push/run-tests.sh +0 -44
- package/.morph/framework/hooks/shared/hook-response.js +0 -45
- package/.morph/framework/hooks/shared/phase-utils.js +0 -129
- package/.morph/framework/hooks/shared/state-reader.js +0 -138
- package/.morph/framework/hooks/shared/stdin-reader.js +0 -26
- package/.morph/framework/standards/STANDARDS.json +0 -933
- package/.morph/framework/standards/ai-agents/blazor-ui.md +0 -364
- package/.morph/framework/standards/ai-agents/production.md +0 -415
- package/.morph/framework/standards/ai-agents/setup.md +0 -418
- package/.morph/framework/standards/ai-agents/team-orchestration.md +0 -479
- package/.morph/framework/standards/ai-agents/workflows.md +0 -354
- package/.morph/framework/standards/architecture/ddd/aggregates.md +0 -120
- package/.morph/framework/standards/architecture/ddd/bounded-contexts.md +0 -105
- package/.morph/framework/standards/architecture/ddd/complexity-levels.md +0 -108
- package/.morph/framework/standards/architecture/ddd/entities.md +0 -99
- package/.morph/framework/standards/architecture/ddd/ubiquitous-language.md +0 -58
- package/.morph/framework/standards/architecture/ddd/value-objects.md +0 -124
- package/.morph/framework/standards/backend/api/minimal-api.md +0 -494
- package/.morph/framework/standards/backend/api/rest.md +0 -492
- package/.morph/framework/standards/backend/api/validation.md +0 -88
- package/.morph/framework/standards/backend/authentication/passkeys.md +0 -428
- package/.morph/framework/standards/backend/database/ef-core.md +0 -199
- package/.morph/framework/standards/backend/database/migrations.md +0 -393
- package/.morph/framework/standards/backend/database/postgresql/database.md +0 -352
- package/.morph/framework/standards/backend/database/repository-patterns.md +0 -528
- package/.morph/framework/standards/backend/database/vector-search-rag.md +0 -541
- package/.morph/framework/standards/backend/dotnet/async.md +0 -366
- package/.morph/framework/standards/backend/dotnet/core.md +0 -117
- package/.morph/framework/standards/backend/dotnet/di.md +0 -439
- package/.morph/framework/standards/backend/dotnet/program-cs-checklist.md +0 -92
- package/.morph/framework/standards/backend/integrations/asaas/asaas-api.md +0 -216
- package/.morph/framework/standards/backend/integrations/clerk/clerk-auth.md +0 -290
- package/.morph/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +0 -350
- package/.morph/framework/standards/backend/integrations/resend/resend-email.md +0 -385
- package/.morph/framework/standards/context/analytics.md +0 -96
- package/.morph/framework/standards/context/bundles.md +0 -110
- package/.morph/framework/standards/context/priming.md +0 -78
- package/.morph/framework/standards/core/architecture.md +0 -185
- package/.morph/framework/standards/core/coding.md +0 -214
- package/.morph/framework/standards/core/git-branching-strategy.md +0 -403
- package/.morph/framework/standards/core/git.md +0 -185
- package/.morph/framework/standards/core/testing.md +0 -295
- package/.morph/framework/standards/data/nosql/blob-storage.md +0 -102
- package/.morph/framework/standards/data/nosql/cache/redis.md +0 -97
- package/.morph/framework/standards/data/nosql/cosmos-db.md +0 -118
- package/.morph/framework/standards/data/vector-search/azure-ai-search.md +0 -121
- package/.morph/framework/standards/data/vector-search/rag-chunking.md +0 -104
- package/.morph/framework/standards/frontend/blazor/design-checklist.md +0 -222
- package/.morph/framework/standards/frontend/blazor/fluent-ui-setup.md +0 -595
- package/.morph/framework/standards/frontend/blazor/fluent-ui.md +0 -137
- package/.morph/framework/standards/frontend/blazor/html-conversion.md +0 -184
- package/.morph/framework/standards/frontend/blazor/lifecycle.md +0 -195
- package/.morph/framework/standards/frontend/blazor/pitfalls.md +0 -198
- package/.morph/framework/standards/frontend/blazor/state.md +0 -191
- package/.morph/framework/standards/frontend/design-system/animations.md +0 -151
- package/.morph/framework/standards/frontend/design-system/naming.md +0 -64
- package/.morph/framework/standards/frontend/nextjs/app-router.md +0 -123
- package/.morph/framework/standards/frontend/nextjs/components.md +0 -132
- package/.morph/framework/standards/frontend/nextjs/data-fetching.md +0 -126
- package/.morph/framework/standards/frontend/nextjs/forms.md +0 -128
- package/.morph/framework/standards/frontend/nextjs/naming-conventions.md +0 -67
- package/.morph/framework/standards/frontend/nextjs/nextjs-patterns.md +0 -215
- package/.morph/framework/standards/frontend/nextjs/project-structure.md +0 -102
- package/.morph/framework/standards/frontend/nextjs/state-management.md +0 -72
- package/.morph/framework/standards/frontend/nextjs/testing.md +0 -111
- package/.morph/framework/standards/infrastructure/azure/azure.md +0 -624
- package/.morph/framework/standards/infrastructure/azure/bicep/bicep-patterns.md +0 -422
- package/.morph/framework/standards/infrastructure/azure/devops/azure-devops-setup.md +0 -516
- package/.morph/framework/standards/infrastructure/azure/devops/local-development.md +0 -520
- package/.morph/framework/standards/infrastructure/azure/services/functions.md +0 -486
- package/.morph/framework/standards/infrastructure/azure/services/service-bus.md +0 -459
- package/.morph/framework/standards/infrastructure/azure/services/storage.md +0 -407
- package/.morph/framework/standards/infrastructure/docker/easypanel-deploy.md +0 -196
- package/.morph/framework/standards/infrastructure/supabase/mcp-setup.md +0 -252
- package/.morph/framework/standards/infrastructure/supabase/supabase-auth.md +0 -176
- package/.morph/framework/standards/infrastructure/supabase/supabase-pgvector.md +0 -169
- package/.morph/framework/standards/infrastructure/supabase/supabase-rls.md +0 -184
- package/.morph/framework/standards/infrastructure/supabase/supabase-storage.md +0 -153
- package/.morph/framework/standards/integration/api/graphql.md +0 -91
- package/.morph/framework/standards/integration/api/grpc.md +0 -114
- package/.morph/framework/standards/integration/api/rest-design.md +0 -95
- package/.morph/framework/standards/integration/event-driven/cqrs.md +0 -101
- package/.morph/framework/standards/integration/event-driven/event-sourcing.md +0 -124
- package/.morph/framework/standards/integration/event-driven/service-bus.md +0 -95
- package/.morph/framework/standards/integration/mcp/mcp-tools.md +0 -384
- package/.morph/framework/standards/observability/logging.md +0 -131
- package/.morph/framework/standards/observability/metrics.md +0 -121
- package/.morph/framework/standards/observability/monitoring.md +0 -114
- package/.morph/framework/standards/observability/tracing.md +0 -132
- package/.morph/framework/standards/workflows/parallel-execution.md +0 -112
- package/.morph/framework/standards/workflows/thread-management.md +0 -113
- package/.morph/framework/templates/.idea/morph-templates.xml +0 -92
- package/.morph/framework/templates/.vscode/morph-templates.code-snippets +0 -186
- package/.morph/framework/templates/IDE-SNIPPETS.md +0 -266
- package/.morph/framework/templates/README.md +0 -814
- package/.morph/framework/templates/REGISTRY.json +0 -1888
- package/.morph/framework/templates/code/dotnet/backend/repository.cs +0 -141
- package/.morph/framework/templates/code/dotnet/backend/service.cs +0 -139
- package/.morph/framework/templates/code/dotnet/contracts/Commands.cs +0 -74
- package/.morph/framework/templates/code/dotnet/contracts/Entities.cs +0 -25
- package/.morph/framework/templates/code/dotnet/contracts/Queries.cs +0 -74
- package/.morph/framework/templates/code/dotnet/contracts/README.md +0 -74
- package/.morph/framework/templates/code/dotnet/contracts/api-contracts.cs +0 -173
- package/.morph/framework/templates/code/dotnet/contracts/contracts-level1.cs +0 -69
- package/.morph/framework/templates/code/dotnet/contracts/contracts-level2.cs +0 -86
- package/.morph/framework/templates/code/dotnet/contracts/contracts-level3.cs +0 -41
- package/.morph/framework/templates/code/dotnet/database/migration.cs +0 -83
- package/.morph/framework/templates/code/dotnet/frontend/component.razor +0 -239
- package/.morph/framework/templates/code/dotnet/jobs/agent.cs +0 -163
- package/.morph/framework/templates/code/dotnet/jobs/job.cs +0 -171
- package/.morph/framework/templates/code/dotnet/test.cs +0 -239
- package/.morph/framework/templates/code/sql/rls-policy.sql +0 -57
- package/.morph/framework/templates/code/sql/supabase-migration.sql +0 -100
- package/.morph/framework/templates/code/sql/supabase-migration.template.sql +0 -113
- package/.morph/framework/templates/code/typescript/contracts.ts +0 -168
- package/.morph/framework/templates/context/CONTEXT-FEATURE.md +0 -276
- package/.morph/framework/templates/context/CONTEXT.md +0 -181
- package/.morph/framework/templates/docs/clarifications.md +0 -253
- package/.morph/framework/templates/docs/onboarding.md +0 -123
- package/.morph/framework/templates/docs/proposal.md +0 -182
- package/.morph/framework/templates/docs/schema-analysis.md +0 -119
- package/.morph/framework/templates/docs/spec.md +0 -198
- package/.morph/framework/templates/docs/ui-components.md +0 -124
- package/.morph/framework/templates/docs/ui-design-system.md +0 -76
- package/.morph/framework/templates/docs/ui-flows.md +0 -167
- package/.morph/framework/templates/docs/ui-mockups.md +0 -98
- package/.morph/framework/templates/docs/user-stories.md +0 -34
- package/.morph/framework/templates/examples/design-system-examples.md +0 -357
- package/.morph/framework/templates/examples/spec-examples.md +0 -90
- package/.morph/framework/templates/feature/decisions.md +0 -187
- package/.morph/framework/templates/feature/recap.md +0 -146
- package/.morph/framework/templates/feature/tasks.md +0 -199
- package/.morph/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +0 -43
- package/.morph/framework/templates/frontend/nextjs/client-component.tsx.hbs +0 -26
- package/.morph/framework/templates/frontend/nextjs/env.mjs.hbs +0 -32
- package/.morph/framework/templates/frontend/nextjs/feature-form.tsx.hbs +0 -56
- package/.morph/framework/templates/frontend/nextjs/page.tsx.hbs +0 -22
- package/.morph/framework/templates/frontend/nextjs/tsconfig.json.hbs +0 -26
- package/.morph/framework/templates/frontend/nextjs/use-feature.ts.hbs +0 -54
- package/.morph/framework/templates/infrastructure/azure/Dockerfile.example +0 -82
- package/.morph/framework/templates/infrastructure/azure/README.md +0 -286
- package/.morph/framework/templates/infrastructure/azure/app-insights.bicep +0 -63
- package/.morph/framework/templates/infrastructure/azure/app-service.bicep +0 -164
- package/.morph/framework/templates/infrastructure/azure/container-app-env.bicep +0 -49
- package/.morph/framework/templates/infrastructure/azure/container-app.bicep +0 -156
- package/.morph/framework/templates/infrastructure/azure/deploy-checklist.md +0 -426
- package/.morph/framework/templates/infrastructure/azure/deploy.ps1 +0 -229
- package/.morph/framework/templates/infrastructure/azure/deploy.sh +0 -208
- package/.morph/framework/templates/infrastructure/azure/key-vault.bicep +0 -91
- package/.morph/framework/templates/infrastructure/azure/main.bicep +0 -189
- package/.morph/framework/templates/infrastructure/azure/parameters.dev.json +0 -29
- package/.morph/framework/templates/infrastructure/azure/parameters.prod.json +0 -29
- package/.morph/framework/templates/infrastructure/azure/parameters.staging.json +0 -29
- package/.morph/framework/templates/infrastructure/azure/sql-database.bicep +0 -103
- package/.morph/framework/templates/infrastructure/azure/storage.bicep +0 -106
- package/.morph/framework/templates/infrastructure/docker/Dockerfile.template +0 -58
- package/.morph/framework/templates/infrastructure/docker/docker-compose.template.yml +0 -67
- package/.morph/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +0 -38
- package/.morph/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +0 -48
- package/.morph/framework/templates/infrastructure/docker/easypanel.template.json +0 -54
- package/.morph/framework/templates/infrastructure/github/README.md +0 -593
- package/.morph/framework/templates/infrastructure/github/actions/azure-auth/action.yml.hbs +0 -22
- package/.morph/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +0 -45
- package/.morph/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +0 -27
- package/.morph/framework/templates/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs +0 -61
- package/.morph/framework/templates/infrastructure/github/workflows/deploy-easypanel.yml.hbs +0 -31
- package/.morph/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +0 -59
- package/.morph/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +0 -39
- package/.morph/framework/templates/integrations/asaas-client.cs +0 -387
- package/.morph/framework/templates/integrations/asaas-webhook.cs +0 -351
- package/.morph/framework/templates/integrations/azure-identity-config.cs +0 -288
- package/.morph/framework/templates/integrations/clerk-config.cs +0 -258
- package/.morph/framework/templates/meta-prompts/fusion/fusion-agent.md +0 -76
- package/.morph/framework/templates/meta-prompts/fusion/fusion-aggregator.md +0 -100
- package/.morph/framework/templates/meta-prompts/hops/hop-retry.md +0 -78
- package/.morph/framework/templates/meta-prompts/hops/hop-validation.md +0 -97
- package/.morph/framework/templates/meta-prompts/hops/hop-wrapper.md +0 -36
- package/.morph/framework/templates/meta-prompts/parallel-workers/parallel-coordinator.md +0 -113
- package/.morph/framework/templates/meta-prompts/parallel-workers/parallel-worker.md +0 -80
- package/.morph/framework/templates/meta-prompts/squad-leaders/backend-squad.md +0 -90
- package/.morph/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +0 -126
- package/.morph/framework/templates/meta-prompts/squad-leaders/squad-leader.md +0 -43
- package/.morph/framework/templates/meta-prompts/validators/checkpoint-validator.md +0 -107
- package/.morph/framework/templates/meta-prompts/validators/pre-commit-validator.md +0 -95
- package/.morph/framework/templates/project-structure/dotnet-ddd.md +0 -70
- package/.morph/framework/templates/saas/subscription.cs +0 -347
- package/.morph/framework/templates/saas/tenant.cs +0 -338
- package/.morph/framework/templates/state.template.json +0 -17
- package/.morph/framework/templates/ui/FluentDesignTheme.cs +0 -149
- package/.morph/framework/templates/ui/MudTheme.cs +0 -281
- package/.morph/framework/templates/ui/design-system.css +0 -226
- package/.morph/logs/tool-failures.log +0 -17
- package/.morph/memory/pre-compact-2026-02-24T17-43-30-049Z.json +0 -16
- package/.morph/plans/eager-watching-bunny.md +0 -105
- package/.morph/plans/temporal-seeking-nebula.md +0 -45
- package/CLAUDE.md +0 -77
- package/docs/claude-alignment-report.md +0 -137
- package/docs/examples/order-management/contracts.cs +0 -84
- package/docs/examples/order-management/proposal.md +0 -24
- package/docs/examples/order-management/spec.md +0 -162
- package/src/commands/feature/create-story.js +0 -362
- package/src/commands/feature/index.js +0 -6
- package/src/commands/feature/shard-spec.js +0 -225
- package/src/commands/feature/sprint-status.js +0 -250
- package/src/commands/generation/generate-onboarding.js +0 -169
- package/src/commands/generation/generate.js +0 -276
- package/src/commands/generation/index.js +0 -5
- package/src/commands/learning/capture-pattern.js +0 -121
- package/src/commands/learning/index.js +0 -5
- package/src/commands/learning/search-patterns.js +0 -126
- package/src/commands/mcp/mcp.js +0 -102
- package/src/commands/project/changes.js +0 -66
- package/src/commands/project/cost.js +0 -179
- package/src/commands/project/diff.js +0 -278
- package/src/commands/project/revert.js +0 -173
- package/src/commands/project/standards.js +0 -80
- package/src/commands/project/sync.js +0 -167
- package/src/commands/project/update-agents.js +0 -23
- package/src/commands/state/rollback-phase.js +0 -185
- package/src/commands/templates/template-customize.js +0 -87
- package/src/commands/templates/template-list.js +0 -114
- package/src/commands/templates/template-show.js +0 -129
- package/src/commands/templates/template-validate.js +0 -91
- package/src/commands/utils/troubleshoot.js +0 -222
- package/src/commands/validation/analyze-blazor-concurrency.js +0 -193
- package/src/commands/validation/lint-fluent.js +0 -352
- package/src/commands/validation/validate-blazor-state.js +0 -210
- package/src/commands/validation/validate-blazor.js +0 -156
- package/src/commands/validation/validate-css.js +0 -84
- package/src/lib/detectors/conversation-analyzer.js +0 -163
- package/src/lib/learning/index.js +0 -7
- package/src/lib/learning/learning-system.js +0 -520
- package/src/lib/troubleshooting/index.js +0 -8
- package/src/lib/troubleshooting/troubleshoot-grep.js +0 -198
- package/src/lib/troubleshooting/troubleshoot-index.js +0 -144
- package/src/llm/environment-detector.js +0 -43
|
@@ -1,278 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MORPH-SPEC Diff Command
|
|
3
|
-
*
|
|
4
|
-
* Track changes to specifications since last approval.
|
|
5
|
-
* Shows added/removed functional requirements, entity changes, and new decisions.
|
|
6
|
-
*
|
|
7
|
-
* Usage:
|
|
8
|
-
* morph-spec diff <feature-name> [output-file]
|
|
9
|
-
* morph-spec diff <feature-name> spec.md
|
|
10
|
-
* morph-spec diff <feature-name> --json
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import fs from 'fs';
|
|
14
|
-
import path from 'path';
|
|
15
|
-
import chalk from 'chalk';
|
|
16
|
-
import { getFeature } from '../../core/state/state-manager.js';
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Load snapshot from checkpoints directory
|
|
20
|
-
*/
|
|
21
|
-
function loadSnapshot(featureName, outputFile) {
|
|
22
|
-
const snapshotDir = path.join(process.cwd(), '.morph/checkpoints', featureName);
|
|
23
|
-
const snapshotPath = path.join(snapshotDir, outputFile);
|
|
24
|
-
|
|
25
|
-
if (!fs.existsSync(snapshotPath)) {
|
|
26
|
-
return null;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
return fs.readFileSync(snapshotPath, 'utf8');
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Load current version of output file
|
|
34
|
-
*/
|
|
35
|
-
function loadCurrent(featureName, outputFile) {
|
|
36
|
-
const currentPath = path.join(process.cwd(), '.morph/features', featureName, outputFile);
|
|
37
|
-
|
|
38
|
-
if (!fs.existsSync(currentPath)) {
|
|
39
|
-
return null;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
return fs.readFileSync(currentPath, 'utf8');
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Extract functional requirements from spec content
|
|
47
|
-
*/
|
|
48
|
-
function extractRequirements(content) {
|
|
49
|
-
const requirements = [];
|
|
50
|
-
const regex = /###\s+(FR[-_]?\d+):?\s*(.+)/gi;
|
|
51
|
-
let match;
|
|
52
|
-
while ((match = regex.exec(content)) !== null) {
|
|
53
|
-
requirements.push({ id: match[1], title: match[2].trim() });
|
|
54
|
-
}
|
|
55
|
-
return requirements;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/**
|
|
59
|
-
* Extract entities from spec or contracts
|
|
60
|
-
*/
|
|
61
|
-
function extractEntities(content) {
|
|
62
|
-
const entities = [];
|
|
63
|
-
// Markdown entities
|
|
64
|
-
const mdRegex = /###\s+(?:Entity|Table):?\s*(.+)/gi;
|
|
65
|
-
let match;
|
|
66
|
-
while ((match = mdRegex.exec(content)) !== null) {
|
|
67
|
-
entities.push(match[1].trim());
|
|
68
|
-
}
|
|
69
|
-
// C# records
|
|
70
|
-
const csRegex = /public\s+record\s+(\w+)/g;
|
|
71
|
-
while ((match = csRegex.exec(content)) !== null) {
|
|
72
|
-
entities.push(match[1]);
|
|
73
|
-
}
|
|
74
|
-
return entities;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Extract ADRs from decisions
|
|
79
|
-
*/
|
|
80
|
-
function extractDecisions(content) {
|
|
81
|
-
const decisions = [];
|
|
82
|
-
const regex = /###\s+ADR[-_]?\d*:?\s*(.+)/gi;
|
|
83
|
-
let match;
|
|
84
|
-
while ((match = regex.exec(content)) !== null) {
|
|
85
|
-
decisions.push(match[1].trim());
|
|
86
|
-
}
|
|
87
|
-
return decisions;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Compute diff between two content versions
|
|
92
|
-
*/
|
|
93
|
-
function computeDiff(oldContent, newContent, outputFile) {
|
|
94
|
-
const diff = {
|
|
95
|
-
file: outputFile,
|
|
96
|
-
added: [],
|
|
97
|
-
removed: [],
|
|
98
|
-
modified: []
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
if (!oldContent) {
|
|
102
|
-
diff.added.push('(entire file is new)');
|
|
103
|
-
return diff;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
if (!newContent) {
|
|
107
|
-
diff.removed.push('(file was deleted)');
|
|
108
|
-
return diff;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Compare requirements
|
|
112
|
-
if (outputFile.endsWith('spec.md')) {
|
|
113
|
-
const oldReqs = extractRequirements(oldContent);
|
|
114
|
-
const newReqs = extractRequirements(newContent);
|
|
115
|
-
|
|
116
|
-
const oldIds = new Set(oldReqs.map(r => r.id));
|
|
117
|
-
const newIds = new Set(newReqs.map(r => r.id));
|
|
118
|
-
|
|
119
|
-
for (const req of newReqs) {
|
|
120
|
-
if (!oldIds.has(req.id)) {
|
|
121
|
-
diff.added.push(`${req.id}: ${req.title}`);
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
for (const req of oldReqs) {
|
|
125
|
-
if (!newIds.has(req.id)) {
|
|
126
|
-
diff.removed.push(`${req.id}: ${req.title}`);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// Compare entities
|
|
131
|
-
const oldEntities = new Set(extractEntities(oldContent));
|
|
132
|
-
const newEntities = new Set(extractEntities(newContent));
|
|
133
|
-
|
|
134
|
-
for (const entity of newEntities) {
|
|
135
|
-
if (!oldEntities.has(entity)) {
|
|
136
|
-
diff.added.push(`Entity: ${entity}`);
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
for (const entity of oldEntities) {
|
|
140
|
-
if (!newEntities.has(entity)) {
|
|
141
|
-
diff.removed.push(`Entity: ${entity}`);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
// Compare decisions
|
|
147
|
-
if (outputFile.endsWith('decisions.md')) {
|
|
148
|
-
const oldDecisions = new Set(extractDecisions(oldContent));
|
|
149
|
-
const newDecisions = new Set(extractDecisions(newContent));
|
|
150
|
-
|
|
151
|
-
for (const decision of newDecisions) {
|
|
152
|
-
if (!oldDecisions.has(decision)) {
|
|
153
|
-
diff.added.push(`ADR: ${decision}`);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
for (const decision of oldDecisions) {
|
|
157
|
-
if (!newDecisions.has(decision)) {
|
|
158
|
-
diff.removed.push(`ADR: ${decision}`);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
// Line count change
|
|
164
|
-
const oldLines = oldContent.split('\n').length;
|
|
165
|
-
const newLines = newContent.split('\n').length;
|
|
166
|
-
if (oldLines !== newLines) {
|
|
167
|
-
const delta = newLines - oldLines;
|
|
168
|
-
diff.modified.push(`${delta > 0 ? '+' : ''}${delta} lines (${oldLines} → ${newLines})`);
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return diff;
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Save current version as snapshot for future diffs
|
|
176
|
-
*/
|
|
177
|
-
export function saveSnapshot(featureName) {
|
|
178
|
-
const outputDir = path.join(process.cwd(), '.morph/features', featureName);
|
|
179
|
-
const snapshotDir = path.join(process.cwd(), '.morph/checkpoints', featureName);
|
|
180
|
-
|
|
181
|
-
if (!fs.existsSync(outputDir)) return;
|
|
182
|
-
|
|
183
|
-
fs.mkdirSync(snapshotDir, { recursive: true });
|
|
184
|
-
|
|
185
|
-
const files = fs.readdirSync(outputDir).filter(f => f.endsWith('.md') || f.endsWith('.cs') || f.endsWith('.json'));
|
|
186
|
-
for (const file of files) {
|
|
187
|
-
const src = path.join(outputDir, file);
|
|
188
|
-
const dest = path.join(snapshotDir, file);
|
|
189
|
-
fs.copyFileSync(src, dest);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
/**
|
|
194
|
-
* Main diff command
|
|
195
|
-
*/
|
|
196
|
-
export async function diffCommand(featureName, outputFile, options = {}) {
|
|
197
|
-
if (!featureName) {
|
|
198
|
-
console.error(chalk.red('Error: Feature name required'));
|
|
199
|
-
console.error(chalk.gray('Usage: morph-spec diff <feature-name> [output-file]'));
|
|
200
|
-
process.exit(1);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
const outputDir = path.join(process.cwd(), '.morph/features', featureName);
|
|
204
|
-
if (!fs.existsSync(outputDir)) {
|
|
205
|
-
console.error(chalk.red(`Error: Feature directory not found: ${outputDir}`));
|
|
206
|
-
process.exit(1);
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Determine which files to diff
|
|
210
|
-
let files;
|
|
211
|
-
if (outputFile) {
|
|
212
|
-
files = [outputFile];
|
|
213
|
-
} else {
|
|
214
|
-
files = fs.readdirSync(outputDir).filter(f => f.endsWith('.md') || f.endsWith('.cs'));
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const diffs = files.map(file => {
|
|
218
|
-
const oldContent = loadSnapshot(featureName, file);
|
|
219
|
-
const newContent = loadCurrent(featureName, file);
|
|
220
|
-
return computeDiff(oldContent, newContent, file);
|
|
221
|
-
}).filter(d => d.added.length > 0 || d.removed.length > 0 || d.modified.length > 0);
|
|
222
|
-
|
|
223
|
-
// JSON output
|
|
224
|
-
if (options.json) {
|
|
225
|
-
console.log(JSON.stringify({ feature: featureName, diffs }, null, 2));
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
// Visual output
|
|
230
|
-
console.log(chalk.cyan('\n┌────────────────────────────────────────────────────────────┐'));
|
|
231
|
-
console.log(chalk.cyan('│ MORPH-SPEC DIFF │'));
|
|
232
|
-
console.log(chalk.cyan('└────────────────────────────────────────────────────────────┘\n'));
|
|
233
|
-
|
|
234
|
-
console.log(chalk.white.bold(`Feature: ${featureName}`));
|
|
235
|
-
console.log(chalk.gray('Changes since last snapshot:\n'));
|
|
236
|
-
|
|
237
|
-
if (diffs.length === 0) {
|
|
238
|
-
console.log(chalk.green(' No changes detected since last snapshot.'));
|
|
239
|
-
console.log(chalk.gray(' Run "morph-spec diff-save <feature>" to create a snapshot.\n'));
|
|
240
|
-
return;
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
for (const diff of diffs) {
|
|
244
|
-
console.log(chalk.white.bold(` ${diff.file}:`));
|
|
245
|
-
|
|
246
|
-
for (const item of diff.added) {
|
|
247
|
-
console.log(chalk.green(` + ${item}`));
|
|
248
|
-
}
|
|
249
|
-
for (const item of diff.removed) {
|
|
250
|
-
console.log(chalk.red(` - ${item}`));
|
|
251
|
-
}
|
|
252
|
-
for (const item of diff.modified) {
|
|
253
|
-
console.log(chalk.yellow(` ~ ${item}`));
|
|
254
|
-
}
|
|
255
|
-
console.log('');
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
const totalAdded = diffs.reduce((sum, d) => sum + d.added.length, 0);
|
|
259
|
-
const totalRemoved = diffs.reduce((sum, d) => sum + d.removed.length, 0);
|
|
260
|
-
console.log(chalk.gray('─'.repeat(60)));
|
|
261
|
-
console.log(chalk.gray(`${totalAdded} addition(s), ${totalRemoved} removal(s) across ${diffs.length} file(s)\n`));
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
/**
|
|
265
|
-
* Save snapshot command
|
|
266
|
-
*/
|
|
267
|
-
export async function diffSaveCommand(featureName) {
|
|
268
|
-
if (!featureName) {
|
|
269
|
-
console.error(chalk.red('Error: Feature name required'));
|
|
270
|
-
process.exit(1);
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
saveSnapshot(featureName);
|
|
274
|
-
console.log(chalk.green(`✓ Snapshot saved for '${featureName}'`));
|
|
275
|
-
console.log(chalk.gray(' Future "morph-spec diff" will compare against this snapshot.\n'));
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
export default diffCommand;
|
|
@@ -1,173 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MORPH-SPEC Revert Command
|
|
3
|
-
*
|
|
4
|
-
* Revert a feature to a previous phase, optionally deleting later-phase outputs.
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
* morph-spec revert <feature-name> --to <phase>
|
|
8
|
-
* morph-spec revert <feature-name> --to design
|
|
9
|
-
* morph-spec revert <feature-name> --to design --delete-outputs
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import fs from 'fs';
|
|
13
|
-
import path from 'path';
|
|
14
|
-
import chalk from 'chalk';
|
|
15
|
-
import { loadState, saveState, getFeature } from '../../core/state/state-manager.js';
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* Phase order for revert logic
|
|
19
|
-
*/
|
|
20
|
-
const PHASE_ORDER = [
|
|
21
|
-
{ key: 'proposal', order: 0, outputs: ['proposal.md'] },
|
|
22
|
-
{ key: 'setup', order: 1, outputs: [] },
|
|
23
|
-
{ key: 'uiux', order: 2, outputs: ['ui-design-system.md', 'ui-mockups.md', 'ui-components.md', 'ui-flows.md'] },
|
|
24
|
-
{ key: 'design', order: 3, outputs: ['spec.md', 'schema-analysis.md', 'contracts.cs', 'decisions.md'] },
|
|
25
|
-
{ key: 'clarify', order: 4, outputs: ['clarifications.md'] },
|
|
26
|
-
{ key: 'tasks', order: 5, outputs: ['tasks.md', 'tasks.json'] },
|
|
27
|
-
{ key: 'implement', order: 6, outputs: ['recap.md'] },
|
|
28
|
-
{ key: 'sync', order: 7, outputs: [] }
|
|
29
|
-
];
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Get outputs that would be affected by reverting to a phase
|
|
33
|
-
*/
|
|
34
|
-
function getAffectedOutputs(targetPhase) {
|
|
35
|
-
const targetOrder = PHASE_ORDER.find(p => p.key === targetPhase)?.order ?? -1;
|
|
36
|
-
const affected = [];
|
|
37
|
-
|
|
38
|
-
for (const phase of PHASE_ORDER) {
|
|
39
|
-
if (phase.order > targetOrder) {
|
|
40
|
-
affected.push(...phase.outputs.map(o => ({ phase: phase.key, file: o })));
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return affected;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* Main revert command
|
|
49
|
-
*/
|
|
50
|
-
export async function revertCommand(featureName, options = {}) {
|
|
51
|
-
if (!featureName) {
|
|
52
|
-
console.error(chalk.red('Error: Feature name required'));
|
|
53
|
-
console.error(chalk.gray('Usage: morph-spec revert <feature-name> --to <phase>'));
|
|
54
|
-
process.exit(1);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const targetPhase = options.to;
|
|
58
|
-
if (!targetPhase) {
|
|
59
|
-
console.error(chalk.red('Error: Target phase required (--to <phase>)'));
|
|
60
|
-
console.error(chalk.gray(`Valid phases: ${PHASE_ORDER.map(p => p.key).join(', ')}`));
|
|
61
|
-
process.exit(1);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const targetDef = PHASE_ORDER.find(p => p.key === targetPhase);
|
|
65
|
-
if (!targetDef) {
|
|
66
|
-
console.error(chalk.red(`Error: Unknown phase: ${targetPhase}`));
|
|
67
|
-
console.error(chalk.gray(`Valid phases: ${PHASE_ORDER.map(p => p.key).join(', ')}`));
|
|
68
|
-
process.exit(1);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
const feature = getFeature(featureName);
|
|
72
|
-
if (!feature) {
|
|
73
|
-
console.error(chalk.red(`Error: Feature '${featureName}' not found`));
|
|
74
|
-
process.exit(1);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const currentDef = PHASE_ORDER.find(p => p.key === feature.phase);
|
|
78
|
-
if (currentDef && targetDef.order >= currentDef.order) {
|
|
79
|
-
console.error(chalk.red(`Error: Cannot revert forward. Current phase: ${feature.phase}, target: ${targetPhase}`));
|
|
80
|
-
process.exit(1);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// Get affected outputs
|
|
84
|
-
const affected = getAffectedOutputs(targetPhase);
|
|
85
|
-
const outputDir = path.join(process.cwd(), '.morph/features', featureName);
|
|
86
|
-
const existingAffected = affected.filter(a =>
|
|
87
|
-
fs.existsSync(path.join(outputDir, a.file))
|
|
88
|
-
);
|
|
89
|
-
|
|
90
|
-
// Show what will happen
|
|
91
|
-
console.log(chalk.cyan('\n┌────────────────────────────────────────────────────────────┐'));
|
|
92
|
-
console.log(chalk.cyan('│ MORPH-SPEC REVERT │'));
|
|
93
|
-
console.log(chalk.cyan('└────────────────────────────────────────────────────────────┘\n'));
|
|
94
|
-
|
|
95
|
-
console.log(chalk.white.bold(`Feature: ${featureName}`));
|
|
96
|
-
console.log(chalk.gray(`Current phase: ${feature.phase} → Reverting to: ${targetPhase}\n`));
|
|
97
|
-
|
|
98
|
-
if (existingAffected.length > 0) {
|
|
99
|
-
if (options.deleteOutputs) {
|
|
100
|
-
console.log(chalk.yellow('The following files will be DELETED:'));
|
|
101
|
-
} else {
|
|
102
|
-
console.log(chalk.yellow('The following outputs will be marked as draft (files preserved):'));
|
|
103
|
-
}
|
|
104
|
-
for (const item of existingAffected) {
|
|
105
|
-
console.log(chalk.gray(` - ${item.file} (from ${item.phase} phase)`));
|
|
106
|
-
}
|
|
107
|
-
console.log('');
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
// Update state
|
|
111
|
-
const state = loadState();
|
|
112
|
-
const stateFeature = state.features[featureName];
|
|
113
|
-
|
|
114
|
-
// Revert phase
|
|
115
|
-
stateFeature.phase = targetPhase;
|
|
116
|
-
stateFeature.updatedAt = new Date().toISOString();
|
|
117
|
-
|
|
118
|
-
// Mark affected outputs as not created in state
|
|
119
|
-
const outputKeyMap = {
|
|
120
|
-
'proposal.md': 'proposal',
|
|
121
|
-
'spec.md': 'spec',
|
|
122
|
-
'schema-analysis.md': 'schemaAnalysis',
|
|
123
|
-
'contracts.cs': 'contracts',
|
|
124
|
-
'decisions.md': 'decisions',
|
|
125
|
-
'clarifications.md': 'clarifications',
|
|
126
|
-
'tasks.md': 'tasks',
|
|
127
|
-
'tasks.json': 'tasks',
|
|
128
|
-
'ui-design-system.md': 'uiDesignSystem',
|
|
129
|
-
'ui-mockups.md': 'uiMockups',
|
|
130
|
-
'ui-components.md': 'uiComponents',
|
|
131
|
-
'ui-flows.md': 'uiFlows',
|
|
132
|
-
'recap.md': 'recap'
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
for (const item of affected) {
|
|
136
|
-
const key = outputKeyMap[item.file];
|
|
137
|
-
if (key && stateFeature.outputs[key]) {
|
|
138
|
-
stateFeature.outputs[key].created = false;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Reset approval gates for later phases
|
|
143
|
-
for (const phase of PHASE_ORDER) {
|
|
144
|
-
if (phase.order > targetDef.order && stateFeature.approvalGates?.[phase.key]) {
|
|
145
|
-
stateFeature.approvalGates[phase.key].approved = false;
|
|
146
|
-
stateFeature.approvalGates[phase.key].timestamp = null;
|
|
147
|
-
stateFeature.approvalGates[phase.key].approvedBy = null;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Reset tasks if reverting before tasks phase
|
|
152
|
-
if (targetDef.order < 5) {
|
|
153
|
-
stateFeature.tasks = { total: 0, completed: 0, inProgress: 0, pending: 0 };
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
saveState(state);
|
|
157
|
-
|
|
158
|
-
// Delete files if requested
|
|
159
|
-
if (options.deleteOutputs && existingAffected.length > 0) {
|
|
160
|
-
for (const item of existingAffected) {
|
|
161
|
-
const filePath = path.join(outputDir, item.file);
|
|
162
|
-
if (fs.existsSync(filePath)) {
|
|
163
|
-
fs.unlinkSync(filePath);
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
console.log(chalk.yellow(`Deleted ${existingAffected.length} file(s).`));
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
console.log(chalk.green(`✓ Feature '${featureName}' reverted to phase: ${targetPhase}`));
|
|
170
|
-
console.log(chalk.gray(` State updated. Run 'morph-spec status ${featureName}' to see current status.\n`));
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
export default revertCommand;
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Standards CLI Commands
|
|
3
|
-
*
|
|
4
|
-
* Provides browsable access to the framework standards registry.
|
|
5
|
-
* Usage:
|
|
6
|
-
* morph-spec standards --list
|
|
7
|
-
* morph-spec standards --search <query>
|
|
8
|
-
* morph-spec standards --show <id>
|
|
9
|
-
* morph-spec standards --category <cat>
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { readFileSync } from 'fs';
|
|
13
|
-
import { join } from 'path';
|
|
14
|
-
import { fileURLToPath } from 'url';
|
|
15
|
-
import { logger } from '../../utils/logger.js';
|
|
16
|
-
|
|
17
|
-
const __dirname = fileURLToPath(new URL('.', import.meta.url));
|
|
18
|
-
const REGISTRY_PATH = join(__dirname, '..', '..', '..', 'framework', 'standards', 'STANDARDS.json');
|
|
19
|
-
|
|
20
|
-
function loadRegistry() {
|
|
21
|
-
return JSON.parse(readFileSync(REGISTRY_PATH, 'utf8')).standards;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* List all standards, optionally filtered by category.
|
|
26
|
-
* @param {{ json?: boolean, category?: string }} opts
|
|
27
|
-
* @returns {Promise<Array>}
|
|
28
|
-
*/
|
|
29
|
-
export async function listStandards({ json, category } = {}) {
|
|
30
|
-
let standards = loadRegistry();
|
|
31
|
-
if (category) {
|
|
32
|
-
standards = standards.filter(s => s.category === category);
|
|
33
|
-
}
|
|
34
|
-
if (json) return standards;
|
|
35
|
-
standards.forEach(s =>
|
|
36
|
-
logger.info(`${s.id.padEnd(55)} ${s.category}`)
|
|
37
|
-
);
|
|
38
|
-
return standards;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Search standards by query string (matches id, name, or tags).
|
|
43
|
-
* @param {string} query
|
|
44
|
-
* @param {{ json?: boolean }} opts
|
|
45
|
-
* @returns {Promise<Array>}
|
|
46
|
-
*/
|
|
47
|
-
export async function searchStandards(query, { json } = {}) {
|
|
48
|
-
const q = query.toLowerCase();
|
|
49
|
-
const results = loadRegistry().filter(s =>
|
|
50
|
-
s.name.toLowerCase().includes(q) ||
|
|
51
|
-
s.id.toLowerCase().includes(q) ||
|
|
52
|
-
s.tags.some(t => t.toLowerCase().includes(q))
|
|
53
|
-
);
|
|
54
|
-
if (json) return results;
|
|
55
|
-
if (results.length === 0) {
|
|
56
|
-
logger.warn(`No standards found matching "${query}"`);
|
|
57
|
-
} else {
|
|
58
|
-
results.forEach(s => logger.info(`${s.id}: ${s.name} [${s.category}]`));
|
|
59
|
-
}
|
|
60
|
-
return results;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* Show the full content of a standard by its id.
|
|
65
|
-
* @param {string} id
|
|
66
|
-
* @returns {Promise<string|null>}
|
|
67
|
-
*/
|
|
68
|
-
export async function showStandard(id) {
|
|
69
|
-
const standard = loadRegistry().find(s => s.id === id);
|
|
70
|
-
if (!standard) {
|
|
71
|
-
logger.error(`Standard '${id}' not found. Use --list to see available standards.`);
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
const content = readFileSync(
|
|
75
|
-
join(__dirname, '..', '..', '..', 'framework', 'standards', standard.path),
|
|
76
|
-
'utf8'
|
|
77
|
-
);
|
|
78
|
-
logger.info(content);
|
|
79
|
-
return content;
|
|
80
|
-
}
|
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
import { join } from 'path';
|
|
2
|
-
import { readdirSync, existsSync } from 'fs';
|
|
3
|
-
import ora from 'ora';
|
|
4
|
-
import chalk from 'chalk';
|
|
5
|
-
import { logger } from '../../utils/logger.js';
|
|
6
|
-
import { readFile, writeFile, ensureDir } from '../../utils/file-copier.js';
|
|
7
|
-
import { analyzeConversation } from '../../lib/detectors/conversation-analyzer.js';
|
|
8
|
-
|
|
9
|
-
export async function syncCommand(options) {
|
|
10
|
-
const targetPath = options.path || process.cwd();
|
|
11
|
-
|
|
12
|
-
logger.header('MORPH-SPEC Standards Sync');
|
|
13
|
-
logger.dim(`Project: ${targetPath}`);
|
|
14
|
-
logger.blank();
|
|
15
|
-
|
|
16
|
-
const spinner = ora('Analyzing feature decisions...').start();
|
|
17
|
-
|
|
18
|
-
try {
|
|
19
|
-
// 1. Find all decisions.md files
|
|
20
|
-
const outputsPath = join(targetPath, '.morph', 'project', 'outputs');
|
|
21
|
-
|
|
22
|
-
if (!existsSync(outputsPath)) {
|
|
23
|
-
spinner.warn('No features found');
|
|
24
|
-
logger.dim('Create features first using MORPH workflow.');
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const features = readdirSync(outputsPath, { withFileTypes: true })
|
|
29
|
-
.filter(dirent => dirent.isDirectory())
|
|
30
|
-
.map(dirent => dirent.name);
|
|
31
|
-
|
|
32
|
-
if (features.length === 0) {
|
|
33
|
-
spinner.warn('No features found');
|
|
34
|
-
return;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
spinner.text = `Found ${features.length} features, analyzing decisions...`;
|
|
38
|
-
|
|
39
|
-
// 2. Analyze all decisions
|
|
40
|
-
const conversation = await analyzeConversation(targetPath);
|
|
41
|
-
|
|
42
|
-
if (conversation.decisions.length === 0) {
|
|
43
|
-
spinner.warn('No decisions found to sync');
|
|
44
|
-
logger.dim('Features may not have decisions.md files yet.');
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
spinner.succeed(`Found ${conversation.decisions.length} decisions`);
|
|
49
|
-
logger.blank();
|
|
50
|
-
|
|
51
|
-
// 3. Group by category
|
|
52
|
-
const byCategory = groupByCategory(conversation.decisions);
|
|
53
|
-
|
|
54
|
-
// 4. Display candidates
|
|
55
|
-
logger.header('Decisions by Category:');
|
|
56
|
-
logger.blank();
|
|
57
|
-
|
|
58
|
-
let totalCandidates = 0;
|
|
59
|
-
|
|
60
|
-
for (const [category, decisions] of Object.entries(byCategory)) {
|
|
61
|
-
if (decisions.length > 0) {
|
|
62
|
-
logger.info(chalk.cyan(`${formatCategory(category)} (${decisions.length})`));
|
|
63
|
-
decisions.slice(0, 3).forEach(d => {
|
|
64
|
-
const preview = d.text.split('\n')[0].substring(0, 70);
|
|
65
|
-
logger.dim(` - ${preview}...`);
|
|
66
|
-
});
|
|
67
|
-
if (decisions.length > 3) {
|
|
68
|
-
logger.dim(` ... and ${decisions.length - 3} more`);
|
|
69
|
-
}
|
|
70
|
-
logger.blank();
|
|
71
|
-
totalCandidates += decisions.length;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// 5. Sync (for now, just report - interactive approval would be added later)
|
|
76
|
-
if (options.dryRun) {
|
|
77
|
-
logger.warn('Dry run mode - no files updated');
|
|
78
|
-
logger.dim(`Would update ${Object.keys(byCategory).length} standard files`);
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
spinner.start('Updating standards...');
|
|
83
|
-
|
|
84
|
-
const standardsDir = join(targetPath, '.morph', 'project', 'standards');
|
|
85
|
-
await ensureDir(standardsDir);
|
|
86
|
-
|
|
87
|
-
let updatedFiles = [];
|
|
88
|
-
|
|
89
|
-
for (const [category, decisions] of Object.entries(byCategory)) {
|
|
90
|
-
if (decisions.length === 0) continue;
|
|
91
|
-
|
|
92
|
-
const fileName = `${category}.md`;
|
|
93
|
-
const filePath = join(standardsDir, fileName);
|
|
94
|
-
|
|
95
|
-
// Read existing or create new
|
|
96
|
-
let content = '';
|
|
97
|
-
if (existsSync(filePath)) {
|
|
98
|
-
content = await readFile(filePath);
|
|
99
|
-
} else {
|
|
100
|
-
content = `# ${formatCategory(category)} Standards\n\n> Project-specific standards for ${category}\n\n`;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Append new decisions
|
|
104
|
-
content += `\n## Decisions from Features (${new Date().toISOString().split('T')[0]})\n\n`;
|
|
105
|
-
|
|
106
|
-
decisions.forEach((d, idx) => {
|
|
107
|
-
const preview = d.text.split('\n').slice(0, 5).join('\n');
|
|
108
|
-
content += `### Decision ${idx + 1}\n\n${preview}\n\n`;
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
await writeFile(filePath, content);
|
|
112
|
-
updatedFiles.push(fileName);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
spinner.succeed(`Updated ${updatedFiles.length} standard files`);
|
|
116
|
-
|
|
117
|
-
updatedFiles.forEach(file => {
|
|
118
|
-
logger.dim(` - ${file}`);
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
logger.blank();
|
|
122
|
-
logger.success('Standards sync complete!');
|
|
123
|
-
logger.dim('Commit these changes with a sync: message.');
|
|
124
|
-
|
|
125
|
-
} catch (error) {
|
|
126
|
-
spinner.fail('Sync failed');
|
|
127
|
-
logger.error(error.message);
|
|
128
|
-
process.exit(1);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/**
|
|
133
|
-
* Group decisions by category
|
|
134
|
-
*/
|
|
135
|
-
function groupByCategory(decisions) {
|
|
136
|
-
const categories = {
|
|
137
|
-
'coding': [],
|
|
138
|
-
'architecture': [],
|
|
139
|
-
'azure': [],
|
|
140
|
-
'integrations': [],
|
|
141
|
-
'ui-ux': []
|
|
142
|
-
};
|
|
143
|
-
|
|
144
|
-
decisions.forEach(decision => {
|
|
145
|
-
const category = decision.category || 'coding';
|
|
146
|
-
if (categories[category]) {
|
|
147
|
-
categories[category].push(decision);
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
return categories;
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
/**
|
|
155
|
-
* Format category name
|
|
156
|
-
*/
|
|
157
|
-
function formatCategory(category) {
|
|
158
|
-
const names = {
|
|
159
|
-
'coding': 'Coding Standards',
|
|
160
|
-
'architecture': 'Architecture Patterns',
|
|
161
|
-
'azure': 'Azure & Infrastructure',
|
|
162
|
-
'integrations': 'Integration Patterns',
|
|
163
|
-
'ui-ux': 'UI/UX Standards'
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
return names[category] || category;
|
|
167
|
-
}
|