@polymorphism-tech/morph-spec 8.47.0 → 9.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +51 -43
- package/README.md +39 -38
- package/bin/morph-spec.js +41 -113
- package/bin/validate.js +1 -147
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +41 -101
- package/framework/MORPH.md +95 -252
- package/framework/agents.json +86 -21
- package/framework/commands/morph-apply.md +5 -28
- package/framework/commands/morph-archive.md +1 -1
- package/framework/commands/morph-hotfix.md +8 -8
- package/framework/commands/morph-infra.md +1 -1
- package/framework/commands/morph-preflight.md +2 -3
- package/framework/commands/morph-status.md +4 -4
- package/framework/docs/CLI.md +574 -286
- package/framework/evals/review-checklist.md +82 -41
- package/framework/hooks/README.md +10 -11
- package/framework/hooks/claude-code/core/block-destructive-worktree-removal.js +6 -49
- package/framework/hooks/claude-code/core/block-raw-worktree-add.js +2 -35
- package/framework/hooks/claude-code/core/chain.js +4 -65
- package/framework/hooks/claude-code/core/comment-guard.js +3 -17
- package/framework/hooks/claude-code/core/denylist.json +33 -3
- package/framework/hooks/claude-code/core/enforce-phase-writes.js +15 -63
- package/framework/hooks/claude-code/core/gate-guard.js +9 -78
- package/framework/hooks/claude-code/core/graph-refresh-kick.js +3 -24
- package/framework/hooks/claude-code/core/heavy-gate.js +3 -21
- package/framework/hooks/claude-code/core/heavy-release.js +2 -13
- package/framework/hooks/claude-code/core/loop-detect.js +2 -31
- package/framework/hooks/claude-code/core/pre-bash-denylist.js +36 -2
- package/framework/hooks/claude-code/core/protect-spec-files.js +25 -297
- package/framework/hooks/claude-code/core/state-sync.js +15 -85
- package/framework/hooks/claude-code/core/telemetry-log.js +15 -96
- package/framework/hooks/claude-code/core/validate-completion.js +37 -147
- package/framework/hooks/claude-code/core/warn-bash-source-write.js +23 -0
- package/framework/hooks/claude-code/core/worktree-context.js +15 -114
- package/framework/hooks/claude-code/core/worktree-create.js +6 -70
- package/framework/hooks/claude-code/core/worktree-env-inject.js +5 -56
- package/framework/hooks/claude-code/core/worktree-remove.js +5 -31
- package/framework/hooks/claude-code/statusline.py +55 -41
- package/framework/hooks/package.json +3 -0
- package/framework/hooks/shared/activity-logger.js +9 -89
- package/framework/hooks/shared/agent-reap.js +2 -17
- package/framework/hooks/shared/build-check.js +11 -76
- package/framework/hooks/shared/claim-registry.js +9 -119
- package/framework/hooks/shared/command-tokens.js +168 -44
- package/framework/hooks/shared/comment-rules.js +5 -20
- package/framework/hooks/shared/comment-scanner.js +11 -43
- package/framework/hooks/shared/comment-stripper.js +11 -85
- package/framework/hooks/shared/e2e-check.js +0 -0
- package/framework/hooks/shared/errata.js +59 -0
- package/framework/hooks/shared/feature-locator.js +11 -95
- package/framework/hooks/shared/frontend-locations.js +4 -0
- package/framework/hooks/shared/gate-question.js +12 -0
- package/framework/hooks/shared/git-exclude.js +3 -20
- package/framework/hooks/shared/git-paths.js +8 -104
- package/framework/hooks/shared/graph-freshness.js +22 -166
- package/framework/hooks/shared/graph-refresh.js +21 -149
- package/framework/hooks/shared/heavy-command.js +4 -12
- package/framework/hooks/shared/hook-response.js +8 -83
- package/framework/hooks/shared/morph-cli.js +8 -52
- package/framework/hooks/shared/payload-utils.js +10 -132
- package/framework/hooks/shared/phase-utils.js +14 -72
- package/framework/hooks/shared/redact-secrets.js +4 -15
- package/framework/hooks/shared/reparse-scan.js +6 -66
- package/framework/hooks/shared/slice-progress.js +99 -0
- package/framework/hooks/shared/source-files.js +4 -17
- package/framework/hooks/shared/spawn-command.js +23 -0
- package/framework/hooks/shared/state-reader.js +51 -247
- package/framework/hooks/shared/state-writer.js +9 -54
- package/framework/hooks/shared/stdin-reader.js +1 -11
- package/framework/hooks/shared/telemetry-logger.js +7 -67
- package/framework/hooks/shared/transcript-usage.js +7 -29
- package/framework/hooks/shared/worktree-root.js +7 -29
- package/framework/mcp/registry.json +3 -4
- package/framework/phases.json +23 -39
- package/framework/rules/csharp-standards.md +1 -1
- package/framework/rules/frontend-standards.md +1 -0
- package/framework/rules/hangfire-standards.md +1 -1
- package/framework/rules/neon-standards.md +1 -1
- package/framework/schemas/config.schema.json +14 -9
- package/framework/schemas/feature.schema.json +15 -50
- package/framework/skills/README.md +3 -4
- package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
- package/framework/skills/core/morph-apply/SKILL.md +149 -222
- package/framework/skills/core/morph-hotfix/SKILL.md +33 -42
- package/framework/skills/core/morph-machine/SKILL.md +2 -2
- package/framework/skills/core/morph-media/SKILL.md +1 -1
- package/framework/skills/core/morph-plan/SKILL.md +137 -299
- package/framework/skills/core/morph-review/SKILL.md +111 -136
- package/framework/skills/core/morph-standards/SKILL.md +27 -39
- package/framework/skills/core/morph-uiux/SKILL.md +94 -152
- package/framework/standards/STANDARDS.json +109 -1219
- package/framework/standards/STANDARDS.meta.json +1319 -0
- package/framework/standards/ai-agents/agent-archetypes.md +2 -2
- package/framework/standards/ai-agents/agent-session.md +1 -1
- package/framework/standards/ai-agents/conversational-agent-with-phases.md +4 -4
- package/framework/standards/ai-agents/durable-workflows-hitl.md +3 -3
- package/framework/standards/ai-agents/evals-with-cache.md +1 -2
- package/framework/standards/ai-agents/guardrails.md +1 -1
- package/framework/standards/ai-agents/multi-agent-patterns.md +2 -2
- package/framework/standards/ai-agents/observability-patterns.md +1 -1
- package/framework/standards/ai-agents/production.md +1 -1
- package/framework/standards/ai-agents/prompt-sources.md +2 -2
- package/framework/standards/ai-agents/providers/model-registry.md +1 -1
- package/framework/standards/ai-agents/rag-custom-pgvector.md +2 -2
- package/framework/standards/ai-agents/setup.md +3 -3
- package/framework/standards/ai-agents/sweet-spot.md +2 -2
- package/framework/standards/ai-agents/tool-adapters.md +0 -2
- package/framework/standards/ai-agents/vector-data-extensions.md +4 -4
- package/framework/standards/ai-agents/workflows.md +1 -1
- package/framework/standards/architecture/code-comments.md +7 -7
- package/framework/standards/architecture/vertical-slice/vertical-slice.md +1 -1
- package/framework/standards/backend/api/validation.md +1 -1
- package/framework/standards/backend/dotnet/vsa-handler-patterns.md +5 -5
- package/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +1 -1
- package/framework/standards/backend/integrations/neon-auth/neon-auth.md +2 -2
- package/framework/standards/data/nosql/cache/redis.md +1 -1
- package/framework/standards/data/nosql/cosmos-db.md +3 -3
- package/framework/standards/frontend/admin-app/forms.md +1 -1
- package/framework/standards/frontend/design-system/art-direction.md +88 -0
- package/framework/standards/frontend/design-system/premium-finish.md +77 -2
- package/framework/standards/infrastructure/neon/neon-pgvector.md +5 -5
- package/framework/standards/integration/mcp/mcp-tools.md +7 -7
- package/framework/templates/CLAUDE.md.core.template +3 -3
- package/framework/templates/README.md +2 -3
- package/framework/templates/REGISTRY.json +15 -179
- package/framework/templates/docs/plan.md +72 -0
- package/framework/templates/docs/ui-mockups.md +4 -0
- package/framework/templates/dotnet/ai-kit/README.md +1 -9
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Morph.AiKit.Tests.csproj +0 -10
- package/framework/templates/meta-prompts/squad-leaders/backend-squad.md +1 -1
- package/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +1 -1
- package/framework/templates/meta-prompts/squad-leaders/squad-leader.md +1 -1
- package/framework/templates/meta-prompts/validators/pre-commit-validator.md +3 -4
- package/package.json +1 -1
- package/src/commands/context/context-refresh.js +0 -16
- package/src/commands/dashboard/dashboard.js +2 -8
- package/src/commands/e2e/e2e.js +18 -105
- package/src/commands/graph/affected.js +0 -14
- package/src/commands/graph/build.js +11 -50
- package/src/commands/graph/explain.js +0 -16
- package/src/commands/graph/status.js +1 -12
- package/src/commands/mcp/mcp-setup.js +4 -62
- package/src/commands/observability/cost.js +17 -111
- package/src/commands/observability/telemetry.js +1 -14
- package/src/commands/project/branch.js +4 -45
- package/src/commands/project/claim.js +4 -48
- package/src/commands/project/doctor-procs.js +1 -1
- package/src/commands/project/doctor.js +53 -307
- package/src/commands/project/env.js +1 -27
- package/src/commands/project/fleet.js +6 -35
- package/src/commands/project/heavy.js +3 -3
- package/src/commands/project/init.js +8 -68
- package/src/commands/project/install-plugin-cmd.js +0 -1
- package/src/commands/project/setup-infra-cmd.js +2 -1
- package/src/commands/project/stack-scan.js +58 -0
- package/src/commands/project/standards.js +65 -72
- package/src/commands/project/status.js +28 -121
- package/src/commands/project/update.js +31 -223
- package/src/commands/project/worktree.js +109 -883
- package/src/commands/scaffold/scaffold.js +0 -25
- package/src/commands/state/advance.js +65 -120
- package/src/commands/state/approve.js +87 -229
- package/src/commands/state/archive.js +23 -139
- package/src/commands/state/auto-approval.js +65 -0
- package/src/commands/state/create.js +49 -109
- package/src/commands/state/delete.js +11 -63
- package/src/commands/state/finish.js +105 -494
- package/src/commands/state/gate-check.js +74 -183
- package/src/commands/state/gate-decision.js +8 -42
- package/src/commands/state/handoff.js +4 -31
- package/src/commands/state/list.js +21 -91
- package/src/commands/state/report-check.js +134 -338
- package/src/commands/state/retype.js +12 -28
- package/src/commands/validation/index.js +0 -3
- package/src/commands/validation/mutate.js +79 -19
- package/src/commands/validation/plan-check.js +81 -0
- package/src/commands/validation/validate-feature.js +52 -216
- package/src/commands/validation/verify.js +45 -160
- package/src/core/paths/output-schema.js +9 -155
- package/src/core/state/feature-identity.js +1 -25
- package/src/core/state/gate-order.js +2 -30
- package/src/core/state/lifecycle-audit.js +8 -100
- package/src/core/state/state-manager.js +32 -395
- package/src/core/templates/template-registry.js +2 -97
- package/src/core/templates/template-renderer.js +13 -93
- package/src/core/templates/template-seed.js +21 -0
- package/src/core/work-types.js +10 -45
- package/src/dashboard/app/App.jsx +1 -8
- package/src/dashboard/app/components/ActivityFeed.jsx +2 -8
- package/src/dashboard/app/components/CommandPalette.jsx +4 -11
- package/src/dashboard/app/components/DetailPanel.jsx +1 -5
- package/src/dashboard/app/components/EntityLink.jsx +0 -12
- package/src/dashboard/app/components/ErrorBoundary.jsx +1 -8
- package/src/dashboard/app/components/KnowledgeMarkdown.jsx +0 -11
- package/src/dashboard/app/components/Markdown.jsx +0 -9
- package/src/dashboard/app/components/PhaseRail.jsx +0 -11
- package/src/dashboard/app/components/SearchFilter.jsx +0 -4
- package/src/dashboard/app/components/Sidebar.jsx +0 -5
- package/src/dashboard/app/hooks/useMorphQuery.js +1 -11
- package/src/dashboard/app/hooks/usePref.js +1 -5
- package/src/dashboard/app/lib/format.js +0 -2
- package/src/dashboard/app/lib/phases.js +3 -9
- package/src/dashboard/app/lib/project.js +0 -12
- package/src/dashboard/app/pages/Activity.jsx +1 -1
- package/src/dashboard/app/pages/AgentMap.jsx +1 -8
- package/src/dashboard/app/pages/FeatureDetail.jsx +139 -133
- package/src/dashboard/app/pages/Features.jsx +9 -16
- package/src/dashboard/app/pages/Guide.jsx +2 -3
- package/src/dashboard/app/pages/HookInspector.jsx +2 -23
- package/src/dashboard/app/pages/PhasePipeline.jsx +3 -7
- package/src/dashboard/app/pages/Portfolio.jsx +0 -1
- package/src/dashboard/app/pages/RulesMap.jsx +1 -16
- package/src/dashboard/app/pages/SkillsLibrary.jsx +1 -16
- package/src/dashboard/app/pages/Standards.jsx +2 -17
- package/src/dashboard/scanner/activity-scanner.js +14 -83
- package/src/dashboard/scanner/agents-scanner.js +1 -23
- package/src/dashboard/scanner/docs-scanner.js +1 -7
- package/src/dashboard/scanner/feature-status.js +2 -5
- package/src/dashboard/scanner/features-scanner.js +92 -113
- package/src/dashboard/scanner/hooks-scanner.js +5 -28
- package/src/dashboard/scanner/index.js +0 -4
- package/src/dashboard/scanner/portfolio.js +5 -29
- package/src/dashboard/scanner/project-api.js +8 -54
- package/src/dashboard/scanner/rules-scanner.js +1 -2
- package/src/dashboard/scanner/skills-scanner.js +2 -12
- package/src/dashboard/scanner/standards-scanner.js +4 -7
- package/src/dashboard/vite-plugin-morph-data.js +5 -19
- package/src/lib/ai/ai-checks.js +7 -52
- package/src/lib/ai/ai-project-scan.js +14 -108
- package/src/lib/ai/code-audit.js +7 -63
- package/src/lib/ai/pin-drift.js +8 -51
- package/src/lib/ai/registry-audit.js +11 -90
- package/src/lib/ci/ci-verify.js +14 -13
- package/src/lib/ci/github-ci.js +9 -37
- package/src/lib/ci/workflow-scaffold.js +2 -10
- package/src/lib/detectors/claude-config-detector.js +13 -74
- package/src/lib/detectors/index.js +8 -59
- package/src/lib/e2e/compose-env.js +5 -66
- package/src/lib/e2e/stack-teardown.js +6 -40
- package/src/lib/generators/architecture-scanner.js +18 -156
- package/src/lib/generators/handoff-generator.js +37 -112
- package/src/lib/generators/scaffold-generator.js +5 -101
- package/src/lib/generators/settings-generator.js +11 -122
- package/src/lib/git/branch-classifier.js +11 -84
- package/src/lib/git/default-branch.js +14 -169
- package/src/lib/git/evidence-staleness.js +2 -1
- package/src/lib/git/gh.js +2 -17
- package/src/lib/git/pending-prs.js +6 -37
- package/src/lib/git/pr-files.js +3 -28
- package/src/lib/git/pr-index.js +3 -34
- package/src/lib/git/tree-fingerprint.js +17 -17
- package/src/lib/git/tree-state.js +6 -33
- package/src/lib/graph/god-nodes.js +2 -22
- package/src/lib/graph/graph-health.js +3 -24
- package/src/lib/graph/graph-loader.js +5 -56
- package/src/lib/graph/graphify-runtime.js +7 -37
- package/src/lib/graph/graphifyignore.js +8 -74
- package/src/lib/graph/sanitize.js +16 -136
- package/src/lib/heavy/cleanup.js +2 -6
- package/src/lib/installers/effects.js +8 -93
- package/src/lib/installers/mcp-installer.js +9 -169
- package/src/lib/installers/memory-installer.js +8 -33
- package/src/lib/installers/templates-reconcile.js +5 -60
- package/src/lib/mutation/commands.js +3 -2
- package/src/lib/mutation/dotnet-introspection.js +281 -0
- package/src/lib/mutation/plan.js +14 -6
- package/src/lib/mutation/runner.js +1 -1
- package/src/lib/mutation/subset.js +47 -13
- package/src/lib/plan/artifact-vocabulary.js +40 -0
- package/src/lib/plan/checks.js +208 -0
- package/src/lib/plan/plan-parser.js +204 -0
- package/src/lib/plan/plan-template.js +18 -0
- package/src/lib/projects/registry.js +7 -44
- package/src/lib/review-reports.js +204 -0
- package/src/lib/risk-detector.js +131 -274
- package/src/lib/specs/adr-index.js +38 -85
- package/src/lib/specs/design-seed.js +18 -0
- package/src/lib/specs/frontmatter.js +31 -0
- package/src/lib/specs/gfm-table.js +11 -0
- package/src/lib/specs/revocations.js +31 -102
- package/src/lib/specs/screen-checklist.js +56 -132
- package/src/lib/stack/dotnet-build-ignores.js +43 -0
- package/src/lib/stack/stack-profile.js +1 -28
- package/src/lib/stack/stack-scan.js +260 -0
- package/src/lib/stack-filter.js +4 -27
- package/src/lib/standards/registry.js +37 -0
- package/src/lib/standards/sections.js +47 -0
- package/src/lib/standards/verified-against.js +19 -191
- package/src/lib/tasks/eval-node.js +23 -179
- package/src/lib/tasks/linux-runner.js +18 -142
- package/src/lib/tasks/test-nodes.js +43 -313
- package/src/lib/tasks/test-runner.js +107 -447
- package/src/lib/telemetry/metrics.js +13 -103
- package/src/lib/telemetry/telemetry-reader.js +13 -238
- package/src/lib/telemetry/verify-event.js +4 -34
- package/src/lib/validators/code-budget/code-budget-validator.js +4 -44
- package/src/lib/validators/code-budget/index.js +0 -7
- package/src/lib/validators/contracts/contract-compliance-validator.js +4 -26
- package/src/lib/validators/contracts/index.js +0 -6
- package/src/lib/validators/nextjs/index.js +0 -5
- package/src/lib/validators/nextjs/next-component-validator.js +4 -81
- package/src/lib/validators/packages/index.js +0 -6
- package/src/lib/validators/packages/package-validator.js +6 -56
- package/src/lib/validators/reuse/index.js +0 -8
- package/src/lib/validators/reuse/reuse-validator.js +24 -137
- package/src/lib/validators/reuse/symbol-scanner.js +6 -62
- package/src/lib/validators/traceability-check.js +54 -156
- package/src/lib/validators/validation-runner.js +20 -125
- package/src/lib/validators/verify-runner.js +152 -575
- package/src/lib/work-type-detector.js +5 -67
- package/src/lib/worktree/docker-audit.js +17 -137
- package/src/lib/worktree/env-allocator.js +10 -98
- package/src/lib/worktree/feature-truth.js +12 -115
- package/src/lib/worktree/finish-backup.js +32 -242
- package/src/lib/worktree/fleet-scanner.js +31 -126
- package/src/lib/worktree/ignored-triage.js +15 -91
- package/src/lib/worktree/vscode-settings.js +2 -3
- package/src/lib/worktree/worktree-audit.js +21 -213
- package/src/lib/worktree/worktree-include.js +3 -5
- package/src/scripts/global-install.js +3 -9
- package/src/scripts/install-plugin.js +1 -13
- package/src/scripts/setup-infra.js +17 -138
- package/src/utils/agents-installer.js +92 -272
- package/src/utils/banner.js +4 -25
- package/src/utils/claude-md-injector.js +1 -37
- package/src/utils/claude-settings-manager.js +1 -87
- package/src/utils/file-copier.js +32 -90
- package/src/utils/hooks-installer.js +26 -296
- package/src/utils/skills-installer.js +4 -102
- package/src/utils/version-checker.js +4 -83
- package/framework/commands/morph-proposal.md +0 -57
- package/framework/evals/trace-schema.md +0 -67
- package/framework/hooks/claude-code/core/tasks-json-guard.js +0 -83
- package/framework/hooks/claude-code/core/trace-autogen.js +0 -277
- package/framework/hooks/git/pre-commit/specs.sh +0 -50
- package/framework/hooks/shared/tasks-validator.js +0 -111
- package/framework/rules/morph-task-tracking.md +0 -54
- package/framework/rules/morph-workflow.md +0 -244
- package/framework/schemas/tasks.schema.json +0 -79
- package/framework/skills/core/morph-brainstorming/SKILL.md +0 -161
- package/framework/skills/core/morph-implement/SKILL.md +0 -194
- package/framework/skills/core/morph-proposal/SKILL.md +0 -152
- package/framework/skills/core/morph-stack-scan/SKILL.md +0 -145
- package/framework/templates/docs/proposal.md +0 -192
- package/framework/templates/docs/spec.md +0 -57
- package/framework/templates/docs/ui-components.md +0 -52
- package/framework/templates/docs/ui-design-system.md +0 -76
- package/framework/templates/docs/ui-flows.md +0 -167
- package/framework/templates/examples/spec-examples.md +0 -91
- package/framework/templates/feature/decisions.md +0 -124
- package/framework/templates/feature/recap.md +0 -145
- package/framework/templates/tasks.template.json +0 -17
- package/src/commands/state/usecase.js +0 -143
- package/src/commands/tasks/dag.js +0 -181
- package/src/commands/utils/index.js +0 -3
- package/src/lib/agents/output-collector.js +0 -76
- package/src/lib/detectors/design-system-detector.js +0 -188
- package/src/lib/evaluator-report.js +0 -104
- package/src/lib/generators/design-system-generator.js +0 -508
- package/src/lib/specs/acervo-format.js +0 -70
- package/src/lib/specs/acervo-lifecycle.js +0 -264
- package/src/lib/specs/done-criteria-check.js +0 -200
- package/src/lib/specs/usecase-check.js +0 -301
- package/src/lib/specs/usecase-promoter.js +0 -301
- package/src/lib/specs/usecase-registry.js +0 -237
- package/src/lib/tasks/dispatch-planner.js +0 -319
- package/src/lib/tasks/dotnet-test-introspection.js +0 -632
- package/src/lib/tasks/mermaid-renderer.js +0 -132
- package/src/lib/tasks/task-classifier.js +0 -30
- package/src/lib/tasks/task-parser.js +0 -209
- package/src/lib/tasks/tasks-json-parser.js +0 -296
- package/src/lib/tasks/test-scope.js +0 -597
- package/src/utils/agent-id-mapper.js +0 -11
|
@@ -1,42 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
* lives, and how to read it from a place that isn't the feature's own tree.
|
|
4
|
-
*
|
|
5
|
-
* `create --worktree` writes a COMPLETE feature.json into the primary root
|
|
6
|
-
* (status, approvalGates, tasks, gateDecisions) and only then copies it into
|
|
7
|
-
* the worktree. From that instant the branch-committed copy (`morph/{f}`) is
|
|
8
|
-
* the truth and the root's copy never changes again — the root sees the
|
|
9
|
-
* feature exactly as it was at birth, forever, unless someone reads through.
|
|
10
|
-
*
|
|
11
|
-
* `branchToReadFrom`/`branchView` are moved verbatim from fleet-scanner.js —
|
|
12
|
-
* they already solved this (comments B3/B3b there), fleet just never shared
|
|
13
|
-
* them. `resolveFeatureTree` is the missing piece for CONSUMERS OTHER than
|
|
14
|
-
* fleet: "which tree/branch actually owns this feature's state", used by
|
|
15
|
-
* `list`, `handoff`, and the mutator guard (assertOwnerTree).
|
|
16
|
-
*
|
|
17
|
-
* Fail-open throughout: no repo, no branch, no blob, unparseable JSON never
|
|
18
|
-
* throws — callers get null/false and fall back to reading the disk.
|
|
19
|
-
*/
|
|
1
|
+
// After `create --worktree`, the root keeps the feature.json frozen at birth; the
|
|
2
|
+
// committed copy on `morph/{f}` is the truth. Fail-open: null means "read the disk".
|
|
20
3
|
|
|
21
4
|
import { execFileSync } from 'child_process';
|
|
22
5
|
import { existsSync, readFileSync } from 'fs';
|
|
23
6
|
import { join } from 'path';
|
|
24
7
|
import { isGitRepo, resolvePrimaryRoot, findWorktreeForFeature, buildBranchName } from '../../commands/project/worktree.js';
|
|
25
8
|
|
|
26
|
-
/**
|
|
27
|
-
* Which branch holds this feature's truth, when the working tree at `path` does
|
|
28
|
-
* NOT — or `null` when the working tree IS the feature's own checkout.
|
|
29
|
-
*
|
|
30
|
-
* The ONE place this condition lives. `tasks` (B3) and `phase`/`pendingGates`
|
|
31
|
-
* (B3b) are the same defect read through different files, so they must agree on
|
|
32
|
-
* when to look at the branch; two drifting copies of this test would resurrect
|
|
33
|
-
* the bug on one field while the other stayed fixed.
|
|
34
|
-
*
|
|
35
|
-
* A worktree entry is the feature's checkout by construction. A root entry is
|
|
36
|
-
* only the feature's checkout when the root happens to be ON `morph/{f}`.
|
|
37
|
-
*
|
|
38
|
-
* @returns {string|null} branch name to read from, or null for "read the disk"
|
|
39
|
-
*/
|
|
9
|
+
/** Branch holding the feature's truth, or `null` when this tree IS its checkout (read the disk). */
|
|
40
10
|
export function branchToReadFrom(root, feature, location, branch) {
|
|
41
11
|
if (location === 'worktree' || !root || !feature) return null;
|
|
42
12
|
const featureBranch = branch || `morph/${feature}`;
|
|
@@ -45,24 +15,12 @@ export function branchToReadFrom(root, feature, location, branch) {
|
|
|
45
15
|
.toString().trim();
|
|
46
16
|
return current === featureBranch ? null : featureBranch;
|
|
47
17
|
} catch {
|
|
48
|
-
return null;
|
|
18
|
+
return null;
|
|
49
19
|
}
|
|
50
20
|
}
|
|
51
21
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
* the set of files under its feature dir.
|
|
55
|
-
*
|
|
56
|
-
* `git ls-tree -z` is deliberate: without it git QUOTES paths containing
|
|
57
|
-
* non-ASCII bytes (`"a\303\247/…"`), which would silently fail the prefix strip
|
|
58
|
-
* and leave the artifact set empty — a predicate that is always false looks
|
|
59
|
-
* exactly like "this feature has no artifacts".
|
|
60
|
-
*
|
|
61
|
-
* Fail-open in layers: no blob → null (caller reads the disk); no tree → the
|
|
62
|
-
* gates alone still beat a stale working tree.
|
|
63
|
-
*
|
|
64
|
-
* @returns {{ fj: Object, files: Set<string> }|null}
|
|
65
|
-
*/
|
|
22
|
+
// `ls-tree -z` is load-bearing: without it git quotes non-ASCII paths, the prefix
|
|
23
|
+
// strip fails and the file set comes back silently empty.
|
|
66
24
|
export function branchView(root, feature, featureBranch) {
|
|
67
25
|
const prefix = `.morph/features/${feature}/`;
|
|
68
26
|
let fj;
|
|
@@ -83,12 +41,11 @@ export function branchView(root, feature, featureBranch) {
|
|
|
83
41
|
const p = raw.trim();
|
|
84
42
|
if (p.startsWith(prefix)) files.add(p.slice(prefix.length));
|
|
85
43
|
}
|
|
86
|
-
} catch { /*
|
|
44
|
+
} catch { /* the gates alone still beat a stale working tree */ }
|
|
87
45
|
|
|
88
46
|
return { fj, files };
|
|
89
47
|
}
|
|
90
48
|
|
|
91
|
-
/** All local `morph/*` branches, as bare feature names — one spawn, a pre-filter. */
|
|
92
49
|
export function morphBranches(root) {
|
|
93
50
|
try {
|
|
94
51
|
const out = execFileSync('git', ['for-each-ref', '--format=%(refname:short)', 'refs/heads/morph/'], {
|
|
@@ -105,7 +62,7 @@ export function morphBranches(root) {
|
|
|
105
62
|
}
|
|
106
63
|
}
|
|
107
64
|
|
|
108
|
-
/**
|
|
65
|
+
/** null on detached HEAD, no repo or no commits yet. */
|
|
109
66
|
export function currentBranch(cwd) {
|
|
110
67
|
try {
|
|
111
68
|
const out = execFileSync('git', ['rev-parse', '--abbrev-ref', 'HEAD'], { cwd, stdio: 'pipe' }).toString().trim();
|
|
@@ -115,7 +72,6 @@ export function currentBranch(cwd) {
|
|
|
115
72
|
}
|
|
116
73
|
}
|
|
117
74
|
|
|
118
|
-
/** Read a feature's local feature.json from `dir`, or null if missing/corrupt. */
|
|
119
75
|
function readLocalFeatureJson(dir, feature) {
|
|
120
76
|
const p = join(dir, '.morph', 'features', feature, 'feature.json');
|
|
121
77
|
if (!existsSync(p)) return null;
|
|
@@ -127,35 +83,9 @@ function readLocalFeatureJson(dir, feature) {
|
|
|
127
83
|
}
|
|
128
84
|
|
|
129
85
|
/**
|
|
130
|
-
*
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
* Six-step search, each step justified by what it's immune to:
|
|
134
|
-
*
|
|
135
|
-
* 1. cwd holds the feature AND cwd is that feature's registered worktree
|
|
136
|
-
* (git's own record, via findWorktreeForFeature) → running inside the
|
|
137
|
-
* owner never counts as a jump.
|
|
138
|
-
* 2. `findWorktreeForFeature` finds a live worktree elsewhere → the tree the
|
|
139
|
-
* GIT REGISTRY says is the owner, not the feature.json pointer — immune
|
|
140
|
-
* to a dangling/stale `feature.worktree` field.
|
|
141
|
-
* 3. the local feature.json's own `worktree.path` field, if it still exists
|
|
142
|
-
* on disk → covers a worktree living outside the conventional path or a
|
|
143
|
-
* registry `git worktree list` can't see for some reason.
|
|
144
|
-
* 4. cwd holds the feature with no worktree registered anywhere → the common
|
|
145
|
-
* case (no `--worktree`, or the worktree was already torn down).
|
|
146
|
-
* 5. no local copy, but `morph/{feature}` has the file committed → the truth
|
|
147
|
-
* exists, just not materialized into any tree right now.
|
|
148
|
-
* 6. nothing anywhere.
|
|
149
|
-
*
|
|
150
|
-
* @param {string} feature
|
|
151
|
-
* @param {string} [cwd]
|
|
152
|
-
* @returns {{
|
|
153
|
-
* source: 'cwd'|'registry'|'pointer'|'branch-only'|'none',
|
|
154
|
-
* tree: string|null,
|
|
155
|
-
* branch: string|null,
|
|
156
|
-
* worktree: {path:string, branch:string}|null,
|
|
157
|
-
* pointerDangling: boolean,
|
|
158
|
-
* }}
|
|
86
|
+
* Order: git's worktree registry, then the feature.json pointer, then cwd, then the branch.
|
|
87
|
+
* The registry comes first so a stale `feature.worktree` pointer never wins.
|
|
88
|
+
* @returns {{ source: 'cwd'|'registry'|'pointer'|'branch-only'|'none', tree: string|null, branch: string|null, worktree: {path:string, branch:string}|null, pointerDangling: boolean }}
|
|
159
89
|
*/
|
|
160
90
|
export function resolveFeatureTree(feature, cwd = process.cwd()) {
|
|
161
91
|
const localFj = readLocalFeatureJson(cwd, feature);
|
|
@@ -165,8 +95,6 @@ export function resolveFeatureTree(feature, cwd = process.cwd()) {
|
|
|
165
95
|
const inGit = isGitRepo(cwd);
|
|
166
96
|
const root = inGit ? resolvePrimaryRoot(cwd) : null;
|
|
167
97
|
|
|
168
|
-
// Step 1 + 2: git's own worktree registry is the source of truth for "is
|
|
169
|
-
// there a live worktree for this feature, and where".
|
|
170
98
|
if (inGit && root) {
|
|
171
99
|
const registered = findWorktreeForFeature(feature, root);
|
|
172
100
|
if (registered && existsSync(registered.path)) {
|
|
@@ -178,19 +106,15 @@ export function resolveFeatureTree(feature, cwd = process.cwd()) {
|
|
|
178
106
|
}
|
|
179
107
|
}
|
|
180
108
|
|
|
181
|
-
// Step 3: the local pointer names a worktree the registry didn't surface
|
|
182
|
-
// (unconventional location, or registry unreadable) but that still exists.
|
|
183
109
|
if (pointerPath && !pointerDangling) {
|
|
184
110
|
const branch = localFj?.worktree?.branch || buildBranchName(feature);
|
|
185
111
|
return { source: 'pointer', tree: pointerPath, branch, worktree: { path: pointerPath, branch }, pointerDangling };
|
|
186
112
|
}
|
|
187
113
|
|
|
188
|
-
// Step 4: this tree holds the feature and nothing else claims to own it.
|
|
189
114
|
if (localFj) {
|
|
190
115
|
return { source: 'cwd', tree: cwd, branch: null, worktree: null, pointerDangling };
|
|
191
116
|
}
|
|
192
117
|
|
|
193
|
-
// Step 5: no local copy anywhere in this tree, but the branch has one.
|
|
194
118
|
if (inGit && root) {
|
|
195
119
|
const branch = buildBranchName(feature);
|
|
196
120
|
const view = branchView(root, feature, branch);
|
|
@@ -199,43 +123,16 @@ export function resolveFeatureTree(feature, cwd = process.cwd()) {
|
|
|
199
123
|
}
|
|
200
124
|
}
|
|
201
125
|
|
|
202
|
-
// Step 6.
|
|
203
126
|
return { source: 'none', tree: null, branch: null, worktree: null, pointerDangling: false };
|
|
204
127
|
}
|
|
205
128
|
|
|
206
|
-
/**
|
|
207
|
-
* Should a mutator (approve/advance/score/gate-decision/gate-check) refuse to
|
|
208
|
-
* write this feature's `feature.json` from `cwd`?
|
|
209
|
-
*
|
|
210
|
-
* Blocked ONLY when a live worktree owns the feature and it is NOT cwd —
|
|
211
|
-
* `resolveFeatureTree` sources `'registry'`/`'pointer'`. `'cwd'` (cwd IS the
|
|
212
|
-
* owner, or no worktree exists at all) always passes. This is what stops
|
|
213
|
-
* `morph-spec approve <f> plan` run from the root, with the worktree still
|
|
214
|
-
* alive, from silently stamping the gate onto the root's birth-instant
|
|
215
|
-
* skeleton — branch-drift CREATED by a command, not merely left behind by one.
|
|
216
|
-
*
|
|
217
|
-
* @param {string} feature
|
|
218
|
-
* @param {string} [cwd]
|
|
219
|
-
* @returns {{ blocked: boolean, tree: string|null, branch: string|null }}
|
|
220
|
-
*/
|
|
129
|
+
/** Blocked only when a live worktree other than cwd owns the feature, so the root skeleton is never stamped. */
|
|
221
130
|
export function assertOwnerTree(feature, cwd = process.cwd()) {
|
|
222
131
|
const owner = resolveFeatureTree(feature, cwd);
|
|
223
132
|
const blocked = owner.source === 'registry' || owner.source === 'pointer';
|
|
224
133
|
return { blocked, tree: owner.tree, branch: owner.branch };
|
|
225
134
|
}
|
|
226
135
|
|
|
227
|
-
/**
|
|
228
|
-
* The refusal text every mutator prints on an owner-tree block — one place so
|
|
229
|
-
* `approve`/`advance`/`score`/`gate-decision`/`gate-check` can never drift
|
|
230
|
-
* into five different wordings for the same defect. `commandLine` is the
|
|
231
|
-
* exact command the caller should re-run inside the owner tree.
|
|
232
|
-
*
|
|
233
|
-
* @param {string} feature
|
|
234
|
-
* @param {string} tree
|
|
235
|
-
* @param {string|null} branch
|
|
236
|
-
* @param {string} commandLine
|
|
237
|
-
* @returns {Array<{tone: 'red'|'gray'|'cyan'|'yellow', text: string}>}
|
|
238
|
-
*/
|
|
239
136
|
export function ownerTreeRefusalLines(feature, tree, branch, commandLine) {
|
|
240
137
|
return [
|
|
241
138
|
{ tone: 'red', text: `\n❌ A feature "${feature}" não pode ser mutada A PARTIR DESTA ÁRVORE.` },
|