@polymorphism-tech/morph-spec 4.7.2 → 4.8.4
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/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/CHEATSHEET.md +203 -221
- package/docs/QUICKSTART.md +2 -8
- 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 +7 -5
- 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/analytics/threads-log.jsonl +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/.morph/state.json +0 -48
- package/CLAUDE.md +0 -77
- package/docs/ARCHITECTURE.md +0 -331
- package/docs/COMMAND-FLOWS.md +0 -368
- 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/docs/plans/2026-02-22-claude-docs-morph-alignment-analysis.md +0 -512
- package/docs/plans/2026-02-22-claude-settings.md +0 -515
- package/docs/plans/2026-02-22-morph-cc-alignment-impl.md +0 -728
- package/docs/plans/2026-02-22-morph-spec-next.md +0 -478
- package/docs/plans/2026-02-22-native-alignment-design.md +0 -199
- package/docs/plans/2026-02-22-native-alignment-impl.md +0 -925
- package/docs/plans/2026-02-22-native-enrichment-design.md +0 -244
- package/docs/plans/2026-02-22-native-enrichment.md +0 -735
- package/docs/plans/2026-02-23-ddd-architecture-refactor.md +0 -1153
- package/docs/plans/2026-02-23-ddd-nextsteps.md +0 -682
- package/docs/plans/2026-02-23-infra-architect-refactor.md +0 -437
- package/docs/plans/2026-02-23-nextjs-code-review-design.md +0 -156
- package/docs/plans/2026-02-23-nextjs-code-review-impl.md +0 -1254
- package/docs/plans/2026-02-23-nextjs-standards-design.md +0 -149
- package/docs/plans/2026-02-23-nextjs-standards-impl.md +0 -1846
- package/scripts/generate-refs.js +0 -336
- package/scripts/generate-standards-registry.js +0 -44
- package/scripts/scan-nextjs.mjs +0 -169
- package/scripts/validate-real.mjs +0 -255
- 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
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Dev Stop Hook: Sync Health Check (Advisory)
|
|
5
|
+
*
|
|
6
|
+
* Event: Stop
|
|
7
|
+
* Scope: Framework codebase only (dev hook)
|
|
8
|
+
*
|
|
9
|
+
* When Claude stops, checks for out-of-sync conditions:
|
|
10
|
+
* 1. Templates not in REGISTRY.json
|
|
11
|
+
* 2. Standards not in STANDARDS.json
|
|
12
|
+
*
|
|
13
|
+
* Uses readdirSync (no git dependency, fast).
|
|
14
|
+
* Returns advisory context if out-of-sync items found.
|
|
15
|
+
*
|
|
16
|
+
* Fail-open: exits 0 on any error.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { readdirSync, readFileSync, existsSync } from 'fs';
|
|
20
|
+
import { join } from 'path';
|
|
21
|
+
import { injectContext, pass } from '../shared/hook-response.js';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Recursively collect .md files from a directory.
|
|
25
|
+
* @param {string} dir - Directory to scan
|
|
26
|
+
* @param {string} [base] - Base path for relative paths
|
|
27
|
+
* @returns {string[]} Relative paths
|
|
28
|
+
*/
|
|
29
|
+
function collectMdFiles(dir, base) {
|
|
30
|
+
base = base || dir;
|
|
31
|
+
const results = [];
|
|
32
|
+
if (!existsSync(dir)) return results;
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const entries = readdirSync(dir, { withFileTypes: true });
|
|
36
|
+
for (const entry of entries) {
|
|
37
|
+
const fullPath = join(dir, entry.name);
|
|
38
|
+
if (entry.isDirectory()) {
|
|
39
|
+
if (entry.name === 'node_modules') continue;
|
|
40
|
+
results.push(...collectMdFiles(fullPath, base));
|
|
41
|
+
} else if (entry.name.endsWith('.md') && entry.name !== 'README.md') {
|
|
42
|
+
const rel = fullPath.replace(base + '/', '').replace(base + '\\', '').replace(/\\/g, '/');
|
|
43
|
+
results.push(rel);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
} catch {
|
|
47
|
+
// Fail-open
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return results;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
try {
|
|
54
|
+
// Prevent infinite loop
|
|
55
|
+
if (process.env.MORPH_STOP_HOOK_ACTIVE === '1') pass();
|
|
56
|
+
|
|
57
|
+
const warnings = [];
|
|
58
|
+
|
|
59
|
+
// Check templates vs REGISTRY.json
|
|
60
|
+
const registryPath = 'framework/templates/REGISTRY.json';
|
|
61
|
+
if (existsSync(registryPath)) {
|
|
62
|
+
try {
|
|
63
|
+
const registry = JSON.parse(readFileSync(registryPath, 'utf-8'));
|
|
64
|
+
const registeredPaths = new Set((registry.templates || []).map(t => t.path));
|
|
65
|
+
const templateFiles = collectMdFiles('framework/templates');
|
|
66
|
+
|
|
67
|
+
const unregistered = templateFiles.filter(f => !registeredPaths.has(f));
|
|
68
|
+
if (unregistered.length > 0) {
|
|
69
|
+
warnings.push(`Templates not in REGISTRY.json (${unregistered.length}):`);
|
|
70
|
+
for (const f of unregistered.slice(0, 5)) {
|
|
71
|
+
warnings.push(` - ${f}`);
|
|
72
|
+
}
|
|
73
|
+
if (unregistered.length > 5) {
|
|
74
|
+
warnings.push(` ... and ${unregistered.length - 5} more`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
} catch {
|
|
78
|
+
// Skip on error
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Check standards vs STANDARDS.json
|
|
83
|
+
const standardsPath = 'framework/standards/STANDARDS.json';
|
|
84
|
+
if (existsSync(standardsPath)) {
|
|
85
|
+
try {
|
|
86
|
+
const registry = JSON.parse(readFileSync(standardsPath, 'utf-8'));
|
|
87
|
+
const registeredPaths = new Set((registry.standards || []).map(s => s.path));
|
|
88
|
+
const standardFiles = collectMdFiles('framework/standards');
|
|
89
|
+
|
|
90
|
+
const unregistered = standardFiles.filter(f => !registeredPaths.has(f));
|
|
91
|
+
if (unregistered.length > 0) {
|
|
92
|
+
warnings.push(`Standards not in STANDARDS.json (${unregistered.length}):`);
|
|
93
|
+
for (const f of unregistered.slice(0, 5)) {
|
|
94
|
+
warnings.push(` - ${f}`);
|
|
95
|
+
}
|
|
96
|
+
if (unregistered.length > 5) {
|
|
97
|
+
warnings.push(` ... and ${unregistered.length - 5} more`);
|
|
98
|
+
}
|
|
99
|
+
warnings.push(' Run: node scripts/generate-standards-registry.js');
|
|
100
|
+
}
|
|
101
|
+
} catch {
|
|
102
|
+
// Skip on error
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
if (warnings.length === 0) pass();
|
|
107
|
+
|
|
108
|
+
const message = [
|
|
109
|
+
'MORPH-SPEC Dev: Out-of-sync items detected:',
|
|
110
|
+
...warnings.map(w => ` ${w}`),
|
|
111
|
+
].join('\n');
|
|
112
|
+
|
|
113
|
+
injectContext(message);
|
|
114
|
+
} catch {
|
|
115
|
+
// Fail-open
|
|
116
|
+
process.exit(0);
|
|
117
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Dev PreToolUse Hook: Guard Version Numbers
|
|
5
|
+
*
|
|
6
|
+
* Event: PreToolUse | Matcher: Write|Edit
|
|
7
|
+
* Scope: Framework codebase only (dev hook)
|
|
8
|
+
*
|
|
9
|
+
* Blocks Write/Edit to files that contain hardcoded version patterns
|
|
10
|
+
* like "MORPH-SPEC v4.8.4". Version should only be in package.json.
|
|
11
|
+
*
|
|
12
|
+
* Checked extensions: .md, .cs, .css, .js (covers templates + source)
|
|
13
|
+
* Exceptions: CHANGELOG.md, node_modules/, test/, package.json, package-lock.json
|
|
14
|
+
*
|
|
15
|
+
* Fail-open: exits 0 on any error.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { readStdin } from '../shared/stdin-reader.js';
|
|
19
|
+
import { getFilePath, getContentToValidate } from '../shared/payload-utils.js';
|
|
20
|
+
import { block, pass } from '../shared/hook-response.js';
|
|
21
|
+
|
|
22
|
+
const VERSION_PATTERN = /MORPH-SPEC\s+v\d+\.\d+\.\d+/;
|
|
23
|
+
const CHECKED_EXTENSIONS = ['.md', '.cs', '.css', '.js', '.html', '.txt'];
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
const payload = await readStdin();
|
|
27
|
+
if (!payload) pass();
|
|
28
|
+
|
|
29
|
+
const filePath = getFilePath(payload);
|
|
30
|
+
if (!filePath) pass();
|
|
31
|
+
|
|
32
|
+
// Only check relevant file types
|
|
33
|
+
if (!CHECKED_EXTENSIONS.some(ext => filePath.endsWith(ext))) pass();
|
|
34
|
+
|
|
35
|
+
// Exceptions
|
|
36
|
+
if (filePath.includes('node_modules/')) pass();
|
|
37
|
+
if (filePath.endsWith('CHANGELOG.md')) pass();
|
|
38
|
+
if (filePath.includes('test/')) pass();
|
|
39
|
+
if (filePath.endsWith('package.json')) pass();
|
|
40
|
+
if (filePath.endsWith('package-lock.json')) pass();
|
|
41
|
+
|
|
42
|
+
const content = getContentToValidate(payload);
|
|
43
|
+
if (!content) pass();
|
|
44
|
+
|
|
45
|
+
if (VERSION_PATTERN.test(content)) {
|
|
46
|
+
block(
|
|
47
|
+
`MORPH-SPEC: Hardcoded version number detected in '${filePath}'.\n` +
|
|
48
|
+
`Version should only be in package.json. Use 'MORPH-SPEC by Polymorphism Tech' without version.\n` +
|
|
49
|
+
`Pattern found: ${content.match(VERSION_PATTERN)?.[0]}`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
pass();
|
|
54
|
+
} catch {
|
|
55
|
+
// Fail-open
|
|
56
|
+
process.exit(0);
|
|
57
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Dev PostToolUse Hook: Standards Registry Sync Advisory
|
|
5
|
+
*
|
|
6
|
+
* Event: PostToolUse | Matcher: Write
|
|
7
|
+
* Scope: Framework codebase only (dev hook)
|
|
8
|
+
*
|
|
9
|
+
* After a Write to framework/standards/**/*.md, checks if the file
|
|
10
|
+
* is registered in framework/standards/STANDARDS.json.
|
|
11
|
+
* If not, injects an advisory to regenerate the registry.
|
|
12
|
+
*
|
|
13
|
+
* Fail-open: exits 0 on any error.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { readFileSync, existsSync } from 'fs';
|
|
17
|
+
import { readStdin } from '../shared/stdin-reader.js';
|
|
18
|
+
import { getFilePath } from '../shared/payload-utils.js';
|
|
19
|
+
import { approve, pass } from '../shared/hook-response.js';
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const payload = await readStdin();
|
|
23
|
+
if (!payload) pass();
|
|
24
|
+
|
|
25
|
+
const filePath = getFilePath(payload);
|
|
26
|
+
if (!filePath) pass();
|
|
27
|
+
|
|
28
|
+
// Only check framework/standards/**/*.md
|
|
29
|
+
if (!filePath.includes('framework/standards/')) pass();
|
|
30
|
+
if (!filePath.endsWith('.md')) pass();
|
|
31
|
+
|
|
32
|
+
// Skip meta files
|
|
33
|
+
const basename = filePath.split('/').pop();
|
|
34
|
+
if (basename === 'README.md') pass();
|
|
35
|
+
if (basename === 'STANDARDS.json') pass();
|
|
36
|
+
|
|
37
|
+
// Extract relative path from framework/standards/
|
|
38
|
+
const standardsIdx = filePath.indexOf('framework/standards/');
|
|
39
|
+
if (standardsIdx === -1) pass();
|
|
40
|
+
const relativePath = filePath.slice(standardsIdx + 'framework/standards/'.length);
|
|
41
|
+
|
|
42
|
+
// Read STANDARDS.json
|
|
43
|
+
const registryPath = 'framework/standards/STANDARDS.json';
|
|
44
|
+
if (!existsSync(registryPath)) pass();
|
|
45
|
+
|
|
46
|
+
const registry = JSON.parse(readFileSync(registryPath, 'utf-8'));
|
|
47
|
+
const registeredPaths = (registry.standards || []).map(s => s.path);
|
|
48
|
+
|
|
49
|
+
if (!registeredPaths.includes(relativePath)) {
|
|
50
|
+
approve(
|
|
51
|
+
`MORPH-SPEC: Standard '${relativePath}' is not in STANDARDS.json.\n` +
|
|
52
|
+
`Run: node scripts/generate-standards-registry.js`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
pass();
|
|
57
|
+
} catch {
|
|
58
|
+
// Fail-open
|
|
59
|
+
process.exit(0);
|
|
60
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Dev PostToolUse Hook: Template Registry Sync Advisory
|
|
5
|
+
*
|
|
6
|
+
* Event: PostToolUse | Matcher: Write
|
|
7
|
+
* Scope: Framework codebase only (dev hook)
|
|
8
|
+
*
|
|
9
|
+
* After a Write to framework/templates/**/*.md, checks if the file
|
|
10
|
+
* is registered in framework/templates/REGISTRY.json.
|
|
11
|
+
* If not, injects an advisory to add the entry.
|
|
12
|
+
*
|
|
13
|
+
* Fail-open: exits 0 on any error.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { readFileSync, existsSync } from 'fs';
|
|
17
|
+
import { readStdin } from '../shared/stdin-reader.js';
|
|
18
|
+
import { getFilePath } from '../shared/payload-utils.js';
|
|
19
|
+
import { approve, pass } from '../shared/hook-response.js';
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const payload = await readStdin();
|
|
23
|
+
if (!payload) pass();
|
|
24
|
+
|
|
25
|
+
const filePath = getFilePath(payload);
|
|
26
|
+
if (!filePath) pass();
|
|
27
|
+
|
|
28
|
+
// Only check framework/templates/**/*.md
|
|
29
|
+
if (!filePath.includes('framework/templates/')) pass();
|
|
30
|
+
if (!filePath.endsWith('.md')) pass();
|
|
31
|
+
|
|
32
|
+
// Skip meta files
|
|
33
|
+
const basename = filePath.split('/').pop();
|
|
34
|
+
if (basename === 'README.md') pass();
|
|
35
|
+
if (basename === 'REGISTRY.json') pass();
|
|
36
|
+
|
|
37
|
+
// Extract relative path from framework/templates/
|
|
38
|
+
const templateIdx = filePath.indexOf('framework/templates/');
|
|
39
|
+
if (templateIdx === -1) pass();
|
|
40
|
+
const relativePath = filePath.slice(templateIdx + 'framework/templates/'.length);
|
|
41
|
+
|
|
42
|
+
// Read REGISTRY.json
|
|
43
|
+
const registryPath = 'framework/templates/REGISTRY.json';
|
|
44
|
+
if (!existsSync(registryPath)) pass();
|
|
45
|
+
|
|
46
|
+
const registry = JSON.parse(readFileSync(registryPath, 'utf-8'));
|
|
47
|
+
const registeredPaths = (registry.templates || []).map(t => t.path);
|
|
48
|
+
|
|
49
|
+
if (!registeredPaths.includes(relativePath)) {
|
|
50
|
+
approve(
|
|
51
|
+
`MORPH-SPEC: Template '${relativePath}' is not in REGISTRY.json.\n` +
|
|
52
|
+
`Add an entry to framework/templates/REGISTRY.json with id, path, phase, and outputName fields.`
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
pass();
|
|
57
|
+
} catch {
|
|
58
|
+
// Fail-open
|
|
59
|
+
process.exit(0);
|
|
60
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Dev PreToolUse Hook: Validate Skill Frontmatter Format
|
|
5
|
+
*
|
|
6
|
+
* Event: PreToolUse | Matcher: Write|Edit
|
|
7
|
+
* Scope: Framework codebase only (dev hook)
|
|
8
|
+
*
|
|
9
|
+
* Validates that SKILL.md files written to framework/skills/ have valid
|
|
10
|
+
* YAML frontmatter with required `name:` and `description:` fields.
|
|
11
|
+
*
|
|
12
|
+
* Only validates on Write (full content). Edit operations pass through.
|
|
13
|
+
* Simple regex parsing (no YAML library dependency).
|
|
14
|
+
*
|
|
15
|
+
* Fail-open: exits 0 on any error.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { readStdin } from '../shared/stdin-reader.js';
|
|
19
|
+
import { getFilePath, getContentToValidate, isWriteOperation } from '../shared/payload-utils.js';
|
|
20
|
+
import { block, pass } from '../shared/hook-response.js';
|
|
21
|
+
|
|
22
|
+
try {
|
|
23
|
+
const payload = await readStdin();
|
|
24
|
+
if (!payload) pass();
|
|
25
|
+
|
|
26
|
+
const filePath = getFilePath(payload);
|
|
27
|
+
if (!filePath) pass();
|
|
28
|
+
|
|
29
|
+
// Only check framework/skills/**/SKILL.md
|
|
30
|
+
if (!filePath.includes('framework/skills/')) pass();
|
|
31
|
+
if (!filePath.endsWith('SKILL.md')) pass();
|
|
32
|
+
|
|
33
|
+
// Only validate full Write operations (not Edit patches)
|
|
34
|
+
if (!isWriteOperation(payload)) pass();
|
|
35
|
+
|
|
36
|
+
const content = getContentToValidate(payload);
|
|
37
|
+
if (!content) pass();
|
|
38
|
+
|
|
39
|
+
// Check for YAML frontmatter delimiters
|
|
40
|
+
const frontmatterMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
41
|
+
if (!frontmatterMatch) {
|
|
42
|
+
block(
|
|
43
|
+
`MORPH-SPEC: SKILL.md at '${filePath}' is missing YAML frontmatter.\n` +
|
|
44
|
+
'All skill files must start with --- delimited YAML frontmatter containing name: and description: fields.'
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const frontmatter = frontmatterMatch[1];
|
|
49
|
+
const missing = [];
|
|
50
|
+
|
|
51
|
+
if (!/^name:/m.test(frontmatter)) {
|
|
52
|
+
missing.push('name:');
|
|
53
|
+
}
|
|
54
|
+
if (!/^description:/m.test(frontmatter)) {
|
|
55
|
+
missing.push('description:');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (missing.length > 0) {
|
|
59
|
+
block(
|
|
60
|
+
`MORPH-SPEC: SKILL.md at '${filePath}' is missing required frontmatter fields:\n` +
|
|
61
|
+
missing.map(m => ` - ${m}`).join('\n') + '\n\n' +
|
|
62
|
+
'All skill files must have name: and description: in their YAML frontmatter.'
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
pass();
|
|
67
|
+
} catch {
|
|
68
|
+
// Fail-open
|
|
69
|
+
process.exit(0);
|
|
70
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Dev PreToolUse Hook: Validate Standard Format
|
|
5
|
+
*
|
|
6
|
+
* Event: PreToolUse | Matcher: Write|Edit
|
|
7
|
+
* Scope: Framework codebase only (dev hook)
|
|
8
|
+
*
|
|
9
|
+
* Validates that files written to framework/standards/ follow the required format:
|
|
10
|
+
* - `> **Scope:**` metadata header
|
|
11
|
+
* - `> **Layer:**` metadata header
|
|
12
|
+
* - `> **Keywords:**` metadata header
|
|
13
|
+
* - Footer: `*MORPH-SPEC by Polymorphism Tech*`
|
|
14
|
+
*
|
|
15
|
+
* Only validates on Write (full content). Edit operations pass through.
|
|
16
|
+
*
|
|
17
|
+
* Fail-open: exits 0 on any error.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { readStdin } from '../shared/stdin-reader.js';
|
|
21
|
+
import { getFilePath, getContentToValidate, isWriteOperation } from '../shared/payload-utils.js';
|
|
22
|
+
import { block, pass } from '../shared/hook-response.js';
|
|
23
|
+
|
|
24
|
+
try {
|
|
25
|
+
const payload = await readStdin();
|
|
26
|
+
if (!payload) pass();
|
|
27
|
+
|
|
28
|
+
const filePath = getFilePath(payload);
|
|
29
|
+
if (!filePath) pass();
|
|
30
|
+
|
|
31
|
+
// Only check framework/standards/**/*.md
|
|
32
|
+
if (!filePath.includes('framework/standards/')) pass();
|
|
33
|
+
if (!filePath.endsWith('.md')) pass();
|
|
34
|
+
|
|
35
|
+
// Skip non-standard files
|
|
36
|
+
const basename = filePath.split('/').pop();
|
|
37
|
+
if (basename === 'README.md') pass();
|
|
38
|
+
if (basename === 'STANDARDS.json') pass();
|
|
39
|
+
|
|
40
|
+
// Only validate full Write operations (not Edit patches)
|
|
41
|
+
if (!isWriteOperation(payload)) pass();
|
|
42
|
+
|
|
43
|
+
const content = getContentToValidate(payload);
|
|
44
|
+
if (!content) pass();
|
|
45
|
+
|
|
46
|
+
const missing = [];
|
|
47
|
+
|
|
48
|
+
if (!/>\s*\*\*Scope:\*\*/.test(content)) {
|
|
49
|
+
missing.push('> **Scope:** metadata header');
|
|
50
|
+
}
|
|
51
|
+
if (!/>\s*\*\*Layer:\*\*/.test(content)) {
|
|
52
|
+
missing.push('> **Layer:** metadata header');
|
|
53
|
+
}
|
|
54
|
+
if (!/>\s*\*\*Keywords:\*\*/.test(content)) {
|
|
55
|
+
missing.push('> **Keywords:** metadata header');
|
|
56
|
+
}
|
|
57
|
+
if (!/\*MORPH-SPEC by Polymorphism Tech\*/.test(content)) {
|
|
58
|
+
missing.push('Footer: *MORPH-SPEC by Polymorphism Tech*');
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (missing.length > 0) {
|
|
62
|
+
block(
|
|
63
|
+
`MORPH-SPEC: Standard file '${basename}' is missing required format elements:\n` +
|
|
64
|
+
missing.map(m => ` - ${m}`).join('\n') + '\n\n' +
|
|
65
|
+
'All framework standards must include Scope/Layer/Keywords metadata headers and the standard footer.'
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
pass();
|
|
70
|
+
} catch {
|
|
71
|
+
// Fail-open
|
|
72
|
+
process.exit(0);
|
|
73
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared payload utilities for Claude Code Write/Edit hooks.
|
|
3
|
+
*
|
|
4
|
+
* Extracts file path and content from tool_input payloads,
|
|
5
|
+
* normalizing between Write (content, file_path) and Edit (new_string, old_string, file_path).
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Get the file path from a hook payload, normalizing backslashes.
|
|
10
|
+
* @param {Object} payload - Hook payload from stdin
|
|
11
|
+
* @returns {string} Normalized file path or empty string
|
|
12
|
+
*/
|
|
13
|
+
export function getFilePath(payload) {
|
|
14
|
+
const raw = payload?.tool_input?.file_path || payload?.tool_input?.path || '';
|
|
15
|
+
return raw.replace(/\\/g, '/');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Get the content being written or edited.
|
|
20
|
+
* For Write: returns `content` (full file content).
|
|
21
|
+
* For Edit: returns `new_string` (replacement text).
|
|
22
|
+
* @param {Object} payload - Hook payload from stdin
|
|
23
|
+
* @returns {string} Content string or empty string
|
|
24
|
+
*/
|
|
25
|
+
export function getContentToValidate(payload) {
|
|
26
|
+
const input = payload?.tool_input;
|
|
27
|
+
if (!input) return '';
|
|
28
|
+
// Write tool uses 'content', Edit tool uses 'new_string'
|
|
29
|
+
return input.content || input.new_string || '';
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Check if this is a Write operation (full file content available).
|
|
34
|
+
* @param {Object} payload - Hook payload from stdin
|
|
35
|
+
* @returns {boolean} True if Write (content exists), false if Edit or unknown
|
|
36
|
+
*/
|
|
37
|
+
export function isWriteOperation(payload) {
|
|
38
|
+
return typeof payload?.tool_input?.content === 'string';
|
|
39
|
+
}
|
|
@@ -73,15 +73,39 @@ export function getFeature(featureName, projectPath) {
|
|
|
73
73
|
return state?.features?.[featureName] || null;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
/**
|
|
77
|
+
* Derive phase from filesystem (v5.0.0+: phase deleted from state).
|
|
78
|
+
* Checks for phase folders in descending order, returns highest present.
|
|
79
|
+
* @param {string} featureName
|
|
80
|
+
* @param {string} [projectPath]
|
|
81
|
+
* @returns {string} Phase name
|
|
82
|
+
*/
|
|
83
|
+
export function derivePhaseForFeature(featureName, projectPath) {
|
|
84
|
+
const basePath = join(projectPath || process.cwd(), '.morph/features', featureName);
|
|
85
|
+
const phaseMap = [
|
|
86
|
+
['4-implement', 'implement'],
|
|
87
|
+
['3-tasks', 'tasks'],
|
|
88
|
+
['2-ui', 'uiux'],
|
|
89
|
+
['1-design', 'design'],
|
|
90
|
+
['0-proposal', 'proposal'],
|
|
91
|
+
];
|
|
92
|
+
for (const [folder, phase] of phaseMap) {
|
|
93
|
+
if (existsSync(join(basePath, folder))) return phase;
|
|
94
|
+
}
|
|
95
|
+
return 'setup';
|
|
96
|
+
}
|
|
97
|
+
|
|
76
98
|
/**
|
|
77
99
|
* Get the current phase of a feature.
|
|
100
|
+
* Falls back to filesystem derivation when phase is not in state (v5.0.0+).
|
|
78
101
|
* @param {string} featureName
|
|
79
102
|
* @param {string} [projectPath]
|
|
80
103
|
* @returns {string|null}
|
|
81
104
|
*/
|
|
82
105
|
export function getFeaturePhase(featureName, projectPath) {
|
|
83
106
|
const feature = getFeature(featureName, projectPath);
|
|
84
|
-
|
|
107
|
+
if (!feature) return null;
|
|
108
|
+
return feature.phase || derivePhaseForFeature(featureName, projectPath);
|
|
85
109
|
}
|
|
86
110
|
|
|
87
111
|
/**
|
|
@@ -58,7 +58,7 @@ Run a checkpoint every 3 completed tasks:
|
|
|
58
58
|
**Design Gate:** Before moving from Design → Tasks, spec must be approved.
|
|
59
59
|
**Implementation Gate:** Before starting implementation, task list must be approved.
|
|
60
60
|
|
|
61
|
-
Check approval status: `morph-spec
|
|
61
|
+
Check approval status: `morph-spec approval-status {feature}`
|
|
62
62
|
|
|
63
63
|
---
|
|
64
64
|
|