@polymorphism-tech/morph-spec 8.46.0 → 9.0.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 +53 -44
- package/README.md +3 -4
- package/bin/morph-spec.js +38 -55
- package/bin/validate.js +5 -134
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +2 -2
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +41 -101
- package/framework/MORPH.md +95 -252
- package/framework/agents.json +75 -18
- package/framework/commands/create-umbraco-lp.md +2 -0
- package/framework/commands/migrate-lp-to-umbraco.md +2 -0
- package/framework/commands/morph-apply.md +5 -28
- package/framework/commands/morph-archive.md +2 -2
- package/framework/commands/morph-hotfix.md +8 -8
- package/framework/commands/morph-infra.md +17 -203
- package/framework/commands/morph-media.md +3 -0
- package/framework/commands/morph-preflight.md +7 -31
- package/framework/commands/morph-proposal.md +2 -50
- package/framework/commands/morph-status.md +3 -3
- package/framework/commands/morph-troubleshoot.md +2 -14
- package/framework/docs/CLI.md +585 -286
- package/framework/evals/review-checklist.md +82 -41
- package/framework/hooks/README.md +10 -11
- package/framework/hooks/claude-code/core/comment-guard.js +1 -1
- package/framework/hooks/claude-code/core/denylist.json +33 -3
- package/framework/hooks/claude-code/core/enforce-phase-writes.js +16 -20
- package/framework/hooks/claude-code/core/gate-guard.js +2 -11
- package/framework/hooks/claude-code/core/pre-bash-denylist.js +38 -0
- package/framework/hooks/claude-code/core/protect-spec-files.js +30 -242
- package/framework/hooks/claude-code/core/state-sync.js +17 -19
- package/framework/hooks/claude-code/core/telemetry-log.js +3 -3
- package/framework/hooks/claude-code/core/validate-completion.js +33 -97
- package/framework/hooks/claude-code/core/warn-bash-source-write.js +31 -0
- package/framework/hooks/claude-code/core/worktree-context.js +5 -4
- package/framework/hooks/claude-code/statusline.py +55 -41
- package/framework/hooks/package.json +3 -0
- package/framework/hooks/shared/activity-logger.js +1 -1
- package/framework/hooks/shared/build-check.js +10 -6
- package/framework/hooks/shared/command-tokens.js +169 -0
- package/framework/hooks/shared/comment-rules.js +1 -1
- package/framework/hooks/shared/comment-scanner.js +10 -23
- package/framework/hooks/shared/comment-stripper.js +1 -1
- package/framework/hooks/shared/e2e-check.js +67 -31
- package/framework/hooks/shared/errata.js +72 -0
- package/framework/hooks/shared/feature-locator.js +1 -1
- package/framework/hooks/shared/frontend-locations.js +6 -0
- package/framework/hooks/shared/gate-question.js +18 -0
- package/framework/hooks/shared/phase-utils.js +15 -32
- package/framework/hooks/shared/slice-progress.js +118 -0
- package/framework/hooks/shared/spawn-command.js +23 -0
- package/framework/hooks/shared/state-reader.js +61 -87
- package/framework/hooks/shared/state-writer.js +3 -3
- package/framework/mcp/registry.json +3 -4
- package/framework/phases.json +23 -39
- package/framework/rules/ai-agents-standards.md +18 -16
- package/framework/rules/asaas-standards.md +3 -1
- package/framework/rules/csharp-standards.md +10 -8
- package/framework/rules/data-standards.md +5 -5
- package/framework/rules/dotnet-templates.md +1 -1
- package/framework/rules/frontend-standards.md +4 -2
- package/framework/rules/gsap-standards.md +10 -5
- package/framework/rules/hangfire-standards.md +3 -1
- package/framework/rules/infrastructure-standards.md +4 -2
- package/framework/rules/neon-auth-standards.md +3 -1
- package/framework/rules/neon-standards.md +6 -4
- package/framework/rules/nextjs-standards.md +13 -11
- package/framework/rules/nextjs-templates.md +1 -1
- package/framework/rules/resend-standards.md +3 -1
- package/framework/schemas/config.schema.json +14 -9
- package/framework/schemas/feature.schema.json +15 -52
- package/framework/skills/README.md +4 -5
- package/framework/skills/core/create-umbraco-lp/SKILL.md +3 -3
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +3 -3
- package/framework/skills/core/morph-apply/SKILL.md +150 -223
- package/framework/skills/core/morph-hotfix/SKILL.md +34 -43
- package/framework/skills/core/morph-machine/SKILL.md +4 -4
- package/framework/skills/core/morph-media/SKILL.md +3 -3
- package/framework/skills/core/morph-plan/SKILL.md +138 -300
- package/framework/skills/core/morph-review/SKILL.md +112 -137
- package/framework/skills/core/morph-standards/SKILL.md +29 -41
- package/framework/skills/core/morph-uiux/SKILL.md +78 -153
- package/framework/standards/STANDARDS.json +90 -1219
- package/framework/standards/STANDARDS.meta.json +1305 -0
- package/framework/standards/ai-agents/evals-with-cache.md +2 -3
- package/framework/standards/ai-agents/llm-runtime-defaults.md +1 -1
- package/framework/standards/ai-agents/modalities-speech-to-text.md +36 -26
- package/framework/standards/ai-agents/prompt-sources.md +6 -4
- package/framework/standards/ai-agents/providers/model-registry.md +1 -1
- package/framework/standards/ai-agents/rag-custom-pgvector.md +67 -39
- package/framework/standards/ai-agents/setup.md +2 -2
- package/framework/standards/ai-agents/structured-output.md +1 -1
- package/framework/standards/ai-agents/sweet-spot.md +1 -1
- package/framework/standards/architecture/code-comments.md +8 -8
- package/framework/standards/architecture/vertical-slice/vertical-slice.md +18 -9
- package/framework/standards/backend/api/validation.md +135 -47
- package/framework/standards/backend/database/postgresql/database.md +11 -7
- package/framework/standards/backend/database/vector-search-rag.md +207 -324
- package/framework/standards/backend/dotnet/fluent-validation-vsa.md +14 -8
- package/framework/standards/backend/dotnet/result-pattern.md +40 -6
- package/framework/standards/backend/dotnet/scalar-ui.md +13 -7
- package/framework/standards/backend/dotnet/scrutor.md +1 -1
- package/framework/standards/backend/dotnet/testing.md +1 -1
- package/framework/standards/backend/dotnet/vsa-handler-patterns.md +7 -7
- package/framework/standards/backend/integrations/asaas/asaas-api.md +309 -165
- package/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +134 -154
- package/framework/standards/data/nosql/cache/redis.md +120 -44
- package/framework/standards/data/nosql/cosmos-db.md +114 -71
- package/framework/standards/frontend/design-system/animations.md +1 -1
- package/framework/standards/frontend/design-system/naming.md +1 -1
- package/framework/standards/frontend/nextjs/motion-patterns.md +45 -29
- package/framework/standards/frontend/nextjs/naming-conventions.md +1 -1
- package/framework/standards/infrastructure/docker/coolify-deploy.md +8 -6
- package/framework/standards/infrastructure/neon/neon-pgvector.md +120 -75
- package/framework/standards/infrastructure/neon/neon-setup.md +53 -31
- package/framework/standards/integration/mcp/mcp-tools.md +7 -7
- package/framework/templates/README.md +2 -3
- package/framework/templates/REGISTRY.json +6 -170
- package/framework/templates/code/dotnet/contracts/contracts-vsa.cs +2 -2
- package/framework/templates/code/dotnet/extensions/database-extensions.cs +1 -1
- package/framework/templates/code/dotnet/extensions/result-extensions.cs +27 -0
- package/framework/templates/code/dotnet/feature/endpoint.cs.hbs +2 -2
- package/framework/templates/docs/plan.md +72 -0
- package/framework/templates/dotnet/ai-kit/README.md +1 -9
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/MediaDisclosureTests.cs +1 -1
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Morph.AiKit.Tests.csproj +0 -10
- package/framework/templates/infrastructure/docker/coolify.template.json +3 -3
- package/framework/templates/infrastructure/github/README.md +2 -1
- package/framework/templates/infrastructure/github/workflows/deploy-coolify.yml.hbs +2 -1
- 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/e2e/e2e.js +2 -2
- package/src/commands/observability/cost.js +18 -60
- package/src/commands/observability/telemetry.js +3 -5
- package/src/commands/project/doctor-procs.js +1 -1
- package/src/commands/project/doctor.js +9 -9
- package/src/commands/project/fleet.js +4 -4
- package/src/commands/project/heavy.js +3 -3
- package/src/commands/project/init.js +6 -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 +79 -25
- package/src/commands/project/status.js +29 -69
- package/src/commands/project/update.js +33 -19
- package/src/commands/project/worktree.js +1 -1
- package/src/commands/state/advance.js +62 -46
- package/src/commands/state/approve.js +95 -138
- package/src/commands/state/archive.js +20 -84
- package/src/commands/state/auto-approval.js +68 -0
- package/src/commands/state/create.js +28 -1
- package/src/commands/state/delete.js +1 -1
- package/src/commands/state/finish.js +11 -23
- package/src/commands/state/gate-check.js +86 -95
- package/src/commands/state/gate-decision.js +6 -4
- package/src/commands/state/handoff.js +1 -1
- package/src/commands/state/list.js +9 -9
- package/src/commands/state/report-check.js +157 -311
- package/src/commands/state/retype.js +9 -3
- package/src/commands/validation/mutate.js +77 -14
- package/src/commands/validation/plan-check.js +81 -0
- package/src/commands/validation/validate-feature.js +60 -135
- package/src/commands/validation/verify.js +41 -82
- package/src/core/paths/output-schema.js +20 -67
- package/src/core/state/gate-order.js +5 -6
- package/src/core/state/lifecycle-audit.js +2 -2
- package/src/core/state/state-manager.js +17 -98
- package/src/core/templates/template-registry.js +2 -2
- package/src/core/templates/template-seed.js +22 -0
- package/src/core/work-types.js +10 -10
- package/src/dashboard/app/App.jsx +0 -2
- package/src/dashboard/app/components/ActivityFeed.jsx +2 -3
- package/src/dashboard/app/components/CommandPalette.jsx +7 -8
- package/src/dashboard/app/components/EntityLink.jsx +1 -2
- package/src/dashboard/app/components/Markdown.jsx +1 -1
- package/src/dashboard/app/components/Sidebar.jsx +1 -2
- package/src/dashboard/app/hooks/useMorphQuery.js +1 -1
- package/src/dashboard/app/lib/phases.js +2 -4
- package/src/dashboard/app/pages/Activity.jsx +1 -1
- package/src/dashboard/app/pages/FeatureDetail.jsx +139 -129
- package/src/dashboard/app/pages/Features.jsx +9 -9
- package/src/dashboard/app/pages/Guide.jsx +2 -2
- package/src/dashboard/app/pages/PhasePipeline.jsx +3 -4
- package/src/dashboard/app/pages/RulesMap.jsx +3 -3
- package/src/dashboard/app/pages/SkillsLibrary.jsx +3 -3
- package/src/dashboard/app/pages/Standards.jsx +1 -1
- package/src/dashboard/scanner/activity-scanner.js +6 -16
- package/src/dashboard/scanner/agents-scanner.js +1 -1
- package/src/dashboard/scanner/docs-scanner.js +5 -23
- package/src/dashboard/scanner/features-scanner.js +95 -60
- package/src/dashboard/scanner/index.js +0 -2
- package/src/dashboard/scanner/project-api.js +1 -1
- package/src/dashboard/scanner/rules-scanner.js +15 -10
- package/src/dashboard/scanner/skills-scanner.js +2 -3
- package/src/dashboard/scanner/standards-scanner.js +2 -1
- package/src/lib/ci/ci-verify.js +17 -1
- package/src/lib/ci/github-ci.js +1 -1
- package/src/lib/detectors/index.js +3 -8
- package/src/lib/generators/handoff-generator.js +34 -65
- package/src/lib/generators/settings-generator.js +11 -89
- package/src/lib/git/evidence-staleness.js +1 -1
- package/src/lib/git/tree-fingerprint.js +19 -7
- package/src/lib/git/tree-state.js +2 -2
- package/src/lib/heavy/cleanup.js +1 -5
- package/src/lib/installers/memory-installer.js +6 -8
- package/src/lib/mutation/commands.js +3 -2
- package/src/lib/{tasks/dotnet-test-introspection.js → mutation/dotnet-introspection.js} +17 -282
- package/src/lib/mutation/plan.js +14 -6
- package/src/lib/mutation/runner.js +1 -1
- package/src/lib/mutation/subset.js +46 -9
- package/src/lib/plan/artifact-vocabulary.js +60 -0
- package/src/lib/plan/checks.js +234 -0
- package/src/lib/plan/plan-parser.js +209 -0
- package/src/lib/plan/plan-template.js +18 -0
- package/src/lib/review-reports.js +222 -0
- package/src/lib/risk-detector.js +134 -135
- package/src/lib/specs/adr-index.js +50 -69
- package/src/lib/specs/design-seed.js +18 -0
- package/src/lib/specs/frontmatter.js +44 -0
- package/src/lib/specs/gfm-table.js +17 -0
- package/src/lib/specs/old-format.js +68 -0
- package/src/lib/specs/revocations.js +37 -95
- package/src/lib/specs/screen-checklist.js +18 -17
- package/src/lib/stack/dotnet-build-ignores.js +47 -0
- package/src/lib/stack/stack-profile.js +1 -1
- package/src/lib/stack/stack-scan.js +267 -0
- package/src/lib/standards/registry.js +43 -0
- package/src/lib/standards/sections.js +58 -0
- package/src/lib/tasks/eval-node.js +4 -12
- package/src/lib/tasks/test-nodes.js +1 -74
- package/src/lib/tasks/test-runner.js +75 -117
- package/src/lib/telemetry/metrics.js +8 -69
- package/src/lib/telemetry/telemetry-reader.js +5 -118
- package/src/lib/telemetry/verify-event.js +5 -7
- package/src/lib/validators/code-budget/code-budget-validator.js +1 -1
- package/src/lib/validators/contracts/contract-compliance-validator.js +2 -2
- package/src/lib/validators/reuse/reuse-validator.js +24 -48
- package/src/lib/validators/reuse/symbol-scanner.js +2 -4
- package/src/lib/validators/traceability-check.js +85 -129
- package/src/lib/validators/validation-runner.js +8 -88
- package/src/lib/validators/verify-runner.js +134 -301
- package/src/lib/worktree/docker-audit.js +1 -2
- package/src/lib/worktree/fleet-scanner.js +25 -38
- package/src/scripts/setup-infra.js +42 -22
- package/src/utils/agents-installer.js +92 -13
- package/src/utils/claude-settings-manager.js +0 -35
- package/src/utils/file-copier.js +34 -6
- package/src/utils/hooks-installer.js +16 -9
- package/src/utils/skills-installer.js +1 -2
- package/framework/commands/commit.md +0 -166
- 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/rubrics/backend.json +0 -41
- package/framework/rubrics/default.json +0 -36
- package/framework/rubrics/frontend.json +0 -36
- 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/project/validate.js +0 -97
- 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/dashboard/app/pages/Rubrics.jsx +0 -97
- package/src/dashboard/scanner/rubrics-scanner.js +0 -12
- package/src/lib/agents/output-collector.js +0 -76
- package/src/lib/evaluator-report.js +0 -91
- 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/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/lib/validators/architecture/architecture-validator.js +0 -270
- package/src/lib/validators/architecture/index.js +0 -7
- package/src/lib/validators/css/css-validator.js +0 -340
- package/src/lib/validators/css/index.js +0 -7
- package/src/lib/validators/design-system/design-system-validator.js +0 -237
- package/src/lib/validators/design-system/index.js +0 -7
- package/src/lib/validators/score-aggregator.js +0 -244
- package/src/lib/validators/ui/index.js +0 -7
- package/src/lib/validators/ui/ui-contrast-validator.js +0 -422
package/bin/morph-spec.js
CHANGED
|
@@ -45,6 +45,8 @@ const claimCommand = lazy('../src/commands/project/claim.js', 'claimCommand');
|
|
|
45
45
|
const standardsCommand = lazy('../src/commands/project/standards.js', 'standardsCommand');
|
|
46
46
|
const reportCheckCommand = lazy('../src/commands/state/report-check.js', 'reportCheckCommand');
|
|
47
47
|
const scoutCheckCommand = lazy('../src/commands/validation/scout-check.js', 'scoutCheckCommand');
|
|
48
|
+
const planCheckCommand = lazy('../src/commands/validation/plan-check.js', 'planCheckCommand');
|
|
49
|
+
const stackScanCommand = lazy('../src/commands/project/stack-scan.js', 'stackScanCommand');
|
|
48
50
|
|
|
49
51
|
// === Approval gates (human-only) ===
|
|
50
52
|
const approveCommand = lazy('../src/commands/state/approve.js', 'approveCommand');
|
|
@@ -60,11 +62,8 @@ const retypeCommand = lazy('../src/commands/state/retype.js', 'retypeCommand');
|
|
|
60
62
|
const handoffCommand = lazy('../src/commands/state/handoff.js', 'handoffCommand');
|
|
61
63
|
const listCommand = lazy('../src/commands/state/list.js', 'listCommand');
|
|
62
64
|
const deleteCommand = lazy('../src/commands/state/delete.js', 'deleteCommand');
|
|
63
|
-
const usecaseReserveCommand = lazy('../src/commands/state/usecase.js', 'usecaseReserveCommand');
|
|
64
|
-
const usecaseCheckCommand = lazy('../src/commands/state/usecase.js', 'usecaseCheckCommand');
|
|
65
65
|
|
|
66
66
|
// === Tasks ===
|
|
67
|
-
const dagCommand = lazy('../src/commands/tasks/dag.js', 'dagCommand');
|
|
68
67
|
|
|
69
68
|
// === Codebase graph ===
|
|
70
69
|
const graphStatusCommand = lazy('../src/commands/graph/status.js', 'graphStatusCommand');
|
|
@@ -174,7 +173,7 @@ program
|
|
|
174
173
|
|
|
175
174
|
program
|
|
176
175
|
.command('list')
|
|
177
|
-
.description('List every feature × status × gates (G1/
|
|
176
|
+
.description('List every feature × status × gates (G1 plan / Gd uiux / G3 review) × workType — the audit board')
|
|
178
177
|
.option('--all', 'Include archived features (.morph/archive)')
|
|
179
178
|
.option('--archived', 'Include archived features (alias of --all)')
|
|
180
179
|
.option('--no-branch', 'Skip reading morph/{feature} for truth — report only what is on disk in this tree')
|
|
@@ -184,12 +183,12 @@ program
|
|
|
184
183
|
// ─── Approval gates (dev-only) ────────────────────────────────────────────
|
|
185
184
|
program
|
|
186
185
|
.command('approve <feature> <gate>')
|
|
187
|
-
.description('Approve a phase gate (
|
|
186
|
+
.description('Approve a phase gate (plan, uiux, review). Enforces gate order (uiux and review require plan)')
|
|
188
187
|
.option('--approver <name>', 'Name of approver (default: current user when interactive, "auto" otherwise)')
|
|
189
188
|
.option('--mode <mode>', 'Approval mode: "user" or "auto" (default: detected from TTY)')
|
|
190
189
|
.option('--notes <notes>', 'Approval notes')
|
|
191
190
|
.option('--force', 'Approve out of order (bypass the gate-monotonicity check)')
|
|
192
|
-
.option('--self-assessed', 'Gate 3 only: approve without
|
|
191
|
+
.option('--self-assessed', 'Gate 3 only: approve without the review reports (verifier.md, reviewer.md, security.md), recording the degradation in feature.json')
|
|
193
192
|
.action((feature, gate, options) => approveCommand(feature, gate, options));
|
|
194
193
|
|
|
195
194
|
program
|
|
@@ -197,7 +196,7 @@ program
|
|
|
197
196
|
.description('Approve the current phase gate and scaffold the next phase folder (one step)')
|
|
198
197
|
.option('--approver <name>', 'Name of approver (default: current user when interactive, "auto" otherwise)')
|
|
199
198
|
.option('--mode <mode>', 'Approval mode: "user" or "auto" (default: detected from TTY)')
|
|
200
|
-
.option('--design', 'From
|
|
199
|
+
.option('--design', 'From plan, advance into the optional design (uiux) phase instead of implement')
|
|
201
200
|
.option('--notes <notes>', 'Approval notes')
|
|
202
201
|
.option('--force', 'Advance even if a prerequisite gate is unapproved (out-of-order recovery)')
|
|
203
202
|
.action((feature, options) => advanceCommand(feature, options));
|
|
@@ -251,7 +250,7 @@ program
|
|
|
251
250
|
program
|
|
252
251
|
.command('gate-check <feature> <gate>')
|
|
253
252
|
.description('Decide + record a gate\'s trust decision from disk-derived signals (shouldPauseGate) — the deterministic default; see gate-decision for the manual escape hatch')
|
|
254
|
-
.option('--signals <json>', 'Override ONLY standardsViolations/designSystemDivergence (not derivable from disk) — everything else is read from feature.json/
|
|
253
|
+
.option('--signals <json>', 'Override ONLY standardsViolations/designSystemDivergence (not derivable from disk) — everything else is read from feature.json/checks.json/git and cannot be overridden here')
|
|
255
254
|
.option('--trust <mode>', 'Trust mode to decide with (default: config.json → trust, or "auto")')
|
|
256
255
|
.option('--json', 'Output as JSON')
|
|
257
256
|
.action((feature, gateArg, options) => gateCheckCommand(feature, gateArg, options));
|
|
@@ -294,33 +293,6 @@ program
|
|
|
294
293
|
.option('--here', 'Force building/writing in the current directory, even if another tree owns this feature')
|
|
295
294
|
.action((feature, options) => handoffCommand(feature, options));
|
|
296
295
|
|
|
297
|
-
// ─── Use cases ────────────────────────────────────────────────────────────
|
|
298
|
-
const usecaseCommand = program
|
|
299
|
-
.command('usecase')
|
|
300
|
-
.description('Project-wide use cases: UC-{nn} numbering (acervo + every worktree of this repo) and the acervo lifecycle check');
|
|
301
|
-
|
|
302
|
-
usecaseCommand
|
|
303
|
-
.command('reserve')
|
|
304
|
-
.description('Atomically reserve the next N UC-{nn} numbers, shared across every worktree of this repo — replaces the old max+1 disk scan, which collides across worktrees')
|
|
305
|
-
.option('--count <n>', 'How many numbers to reserve', '1')
|
|
306
|
-
.option('--feature <name>', 'Feature to record as the reservation owner (defaults to the sole active feature, if unambiguous) — also what the promotion collision guard compares against')
|
|
307
|
-
.option('--json', 'Output as JSON')
|
|
308
|
-
.action((options) => usecaseReserveCommand(options));
|
|
309
|
-
|
|
310
|
-
usecaseCommand
|
|
311
|
-
.command('check <feature>')
|
|
312
|
-
.description('Check a feature against the acervo lifecycle: tasks citing a superseded UC, malformed supersession frontmatter, spec.md revocation rows the finish could not apply (plus the task/use-case plumbing dag checks, when tasks.json exists)')
|
|
313
|
-
.option('--json', 'Output as JSON')
|
|
314
|
-
.action((feature, options) => usecaseCheckCommand(feature, options));
|
|
315
|
-
|
|
316
|
-
// ─── Tasks ────────────────────────────────────────────────────────────────
|
|
317
|
-
program
|
|
318
|
-
.command('dag <feature>')
|
|
319
|
-
.description('Analyze the tasks.json DAG and print the sequential vs parallel dispatch decision (effort-weighted)')
|
|
320
|
-
.option('--json', 'Output as JSON')
|
|
321
|
-
.option('--mermaid', 'Emit the tasks.json DAG as a Mermaid flowchart (flowchart TD)')
|
|
322
|
-
.action((feature, options) => dagCommand(feature, options));
|
|
323
|
-
|
|
324
296
|
// ─── Codebase graph ───────────────────────────────────────────────────────
|
|
325
297
|
const graphCommand = program
|
|
326
298
|
.command('graph')
|
|
@@ -366,17 +338,15 @@ graphCommand
|
|
|
366
338
|
// ─── Validation ───────────────────────────────────────────────────────────
|
|
367
339
|
program
|
|
368
340
|
.command('validate [validator]')
|
|
369
|
-
.description('Run project validations (all | packages |
|
|
341
|
+
.description('Run project validations (all | packages | next-components | spec-tasks)')
|
|
370
342
|
.option('-v, --verbose', 'Show detailed output')
|
|
371
343
|
.option('--auto-fix, --fix', 'Auto-fix issues where possible')
|
|
372
344
|
.option('--no-fail', 'Don\'t exit with error code')
|
|
373
|
-
.option('--wcag-aaa', 'Use WCAG AAA standard (stricter)')
|
|
374
345
|
.action((validator, options) => {
|
|
375
346
|
const args = validator ? [validator] : ['all'];
|
|
376
347
|
if (options.verbose) args.push('--verbose');
|
|
377
348
|
if (options.autoFix) args.push('--auto-fix');
|
|
378
349
|
if (options.noFail) args.push('--no-fail');
|
|
379
|
-
if (options.wcagAaa) args.push('--wcag-aaa');
|
|
380
350
|
validateCommand(args);
|
|
381
351
|
});
|
|
382
352
|
|
|
@@ -390,25 +360,23 @@ program
|
|
|
390
360
|
.action(validateFeatureCommand);
|
|
391
361
|
|
|
392
362
|
program
|
|
393
|
-
.command('verify <feature>
|
|
363
|
+
.command('verify <feature>')
|
|
394
364
|
.description('Run the deterministic verification chain (build + tests + validators + e2e) — code before the LLM judge')
|
|
395
365
|
.option('--json', 'Output as JSON')
|
|
396
|
-
.option('--rubric <id>', 'Force a rubric (default: by task group → config → default)')
|
|
397
366
|
.option('--timeout <ms>', 'Timeout in ms for the build AND tests nodes (build default 120000; tests default 120000 per test project, or project.testTimeoutMs)', (v) => parseInt(v, 10))
|
|
398
367
|
.option('--filter <ids>', 'Run only the test nodes whose id matches (comma-separated; exact or substring). Unmatched nodes are reported as skip; matching nothing is a usage error (exit 2)')
|
|
399
368
|
.option('--linux', 'Run the test nodes inside a Linux container, on a COPY of the tree (the host tree is mounted read-only and copied in — a bind mount is case-insensitive and cannot reproduce case defects). No Docker = usage error, never a skip')
|
|
400
369
|
.option('--linux-image <img>', 'Image used by --linux (default: mcr.microsoft.com/dotnet/sdk:10.0)')
|
|
401
|
-
.option('--
|
|
402
|
-
.option('--record-baseline', 'Measure every test node and write expectedCount back into .morph/config/config.json (only from an all-green run at FEATURE scope; with a task id it is a usage error; never creates config.json)')
|
|
370
|
+
.option('--record-baseline', 'Measure every test node and write expectedCount back into .morph/config/config.json (only from an all-green run; never creates config.json)')
|
|
403
371
|
.option('--refresh-cache', 'Rewrite the response cache of every `runner: "evals"` node against the real provider. NEVER implicit: a cache rewrite is a paid call nobody asked for. Requires the declared envFile; no eval node declared, --skip-tests, or a --filter that excludes them all are usage errors (exit 2), refused BEFORE the cache is touched')
|
|
404
|
-
.option('--skip-tests', 'Skip the test node.
|
|
405
|
-
.option('--skip-build', 'Skip the build node.
|
|
372
|
+
.option('--skip-tests', 'Skip the test node. The run is partial, so the verification stamp is NOT written (reason "skip-tests")')
|
|
373
|
+
.option('--skip-build', 'Skip the build node. The run is partial, so the verification stamp is NOT written (reason "skip-build")')
|
|
406
374
|
.option('--skip-e2e', 'Skip the e2e node (Docker bring-up + Playwright)')
|
|
407
375
|
.option('--fresh-e2e', 'Recreate the e2e stack from scratch: down -v (named volumes included), drop the freshness stamp, rebuild, re-seed auth')
|
|
408
376
|
.option('--no-persist', 'Do not persist the result to feature.json')
|
|
409
|
-
.option('--ci', '
|
|
410
|
-
.action((feature,
|
|
411
|
-
verifyCommand(feature,
|
|
377
|
+
.option('--ci', 'Push morph/<feature> and take the proof from the project CI (creates .github/workflows/morph-verify.yml when no workflow runs verify). Same stamp, source "ci". No GitHub/gh/workflow = local verify with the reason; uncommitted code = exit 2; CI still running after 50 min = exit 3, no stamp')
|
|
378
|
+
.action((feature, options) =>
|
|
379
|
+
verifyCommand(feature, { ...options, noPersist: options.persist === false })
|
|
412
380
|
);
|
|
413
381
|
|
|
414
382
|
program
|
|
@@ -619,8 +587,9 @@ program
|
|
|
619
587
|
// ─── Standards search (server-side, R2 token cut) ─────────────────────────
|
|
620
588
|
program
|
|
621
589
|
.command('standards')
|
|
622
|
-
.description('Search STANDARDS.json server-side (top 3,
|
|
590
|
+
.description('Search STANDARDS.json server-side (top 3, digest + anchors) or print one section, instead of reading the whole registry. Bare: categories + counts')
|
|
623
591
|
.option('--find <query>', 'Search query — matches name/id, tags/aliases, category, digest')
|
|
592
|
+
.option('--show <target>', '<id>: digest + anchors; <id>#<anchor>: only that section of the standard .md')
|
|
624
593
|
.option('--category <category>', 'Restrict --find to a single category')
|
|
625
594
|
.option('--tags <tags>', 'Restrict --find to standards carrying any of these comma-separated tags')
|
|
626
595
|
.option('--json', 'Output as JSON')
|
|
@@ -628,11 +597,11 @@ program
|
|
|
628
597
|
|
|
629
598
|
// ─── Sub-agent report protocol ────────────────────────────────────────────
|
|
630
599
|
program
|
|
631
|
-
.command('report-check <feature> [
|
|
632
|
-
.description('Audit
|
|
633
|
-
.option('--before-eval', 'Save a snapshot of the tree before dispatching the
|
|
600
|
+
.command('report-check <feature> [slices...]')
|
|
601
|
+
.description('Audit slice report files (3-implement/reports/{slice}.md) against the work the dispatch actually wrote (telemetry, keyed by the agent that wrote the report). Exits 0 only when every audited slice is intact; naming slices audits only those')
|
|
602
|
+
.option('--before-eval', 'Save a snapshot of the tree before dispatching the review agents and print their models; later runs report what changed since')
|
|
634
603
|
.option('--json', 'Output as JSON')
|
|
635
|
-
.action((feature,
|
|
604
|
+
.action((feature, slices, options) => reportCheckCommand(feature, slices, options));
|
|
636
605
|
|
|
637
606
|
program
|
|
638
607
|
.command('scout-check <map>')
|
|
@@ -641,6 +610,20 @@ program
|
|
|
641
610
|
.option('--json', 'Output as JSON')
|
|
642
611
|
.action((map, options) => scoutCheckCommand(map, options));
|
|
643
612
|
|
|
613
|
+
program
|
|
614
|
+
.command('plan-check <feature>')
|
|
615
|
+
.description('Parse 2-plan/plan.md (scenarios, slices, decisions, reuse) and, with no error, write 2-plan/checks.json — the only writer of checks.json. Refuses to rewrite it once the plan gate is approved and the plan changed outside ## Errata. Exits 1 on errors, 2 when plan.md is missing')
|
|
616
|
+
.option('--json', 'Output as JSON')
|
|
617
|
+
.addHelpText('after', () => '\nGramática (framework/templates/docs/plan.md):\n\n' +
|
|
618
|
+
readFileSync(join(__dirname, '..', 'framework', 'templates', 'docs', 'plan.md'), 'utf8').replace(/\{\{FEATURE_NAME\}\}/g, '<feature>'))
|
|
619
|
+
.action((feature, options) => planCheckCommand(feature, options));
|
|
620
|
+
|
|
621
|
+
program
|
|
622
|
+
.command('stack-scan [feature]')
|
|
623
|
+
.description('Audit the code against config.project.stack, judging only the configured stacks (runtime, ORM, database, Guid.NewGuid, generic repository, service layer, raw SQL, sealed, router, UI library) by severity. With a feature, write .morph/features/<f>/2-plan/stack-scan.md; without, print the report')
|
|
624
|
+
.option('--json', 'Output as JSON')
|
|
625
|
+
.action((feature, options) => stackScanCommand(feature, options));
|
|
626
|
+
|
|
644
627
|
// ─── Dashboard ────────────────────────────────────────────────────────────
|
|
645
628
|
program
|
|
646
629
|
.command('dashboard')
|
|
@@ -660,10 +643,10 @@ program
|
|
|
660
643
|
|
|
661
644
|
program
|
|
662
645
|
.command('cost [feature]')
|
|
663
|
-
.description('Cost-facing view over .morph/logs/events.jsonl:
|
|
664
|
-
.option('--by <mode>', 'Group by:
|
|
646
|
+
.description('Cost-facing view over .morph/logs/events.jsonl: bytes re-ingested by kind (proxy, not tokens), dispatch counts, real tokens when observed')
|
|
647
|
+
.option('--by <mode>', 'Group by: phase (default: feature-wide summary; with --all-trees, applies to the combined aggregate)')
|
|
665
648
|
.option('--all-trees', 'Aggregate across every git worktree with a log plus the logs finish saved in .git/morph-spec/finish-backup — per-tree breakdown + combined total')
|
|
666
|
-
.option('--metrics', 'Loop measurements: turns, tool calls (orchestrator x sub-agent), time per command class, identical reruns, rereads,
|
|
649
|
+
.option('--metrics', 'Loop measurements: turns, tool calls (orchestrator x sub-agent), time per command class, identical reruns, rereads, verify count per feature, git calls, reuse validator per tree')
|
|
667
650
|
.option('--top <n>', 'With --metrics: how many reread files to list (default 10)', (v) => Number.parseInt(v, 10))
|
|
668
651
|
.option('--json', 'Output the aggregate as JSON')
|
|
669
652
|
.action((feature, options) => costCommand(feature, options));
|
package/bin/validate.js
CHANGED
|
@@ -5,9 +5,8 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Runs validators for the current project stack (detected from .morph/config/config.json).
|
|
7
7
|
*
|
|
8
|
-
* .NET
|
|
9
|
-
* Next.js stack: next-components
|
|
10
|
-
* Other stacks: spec-tasks
|
|
8
|
+
* .NET stacks: packages
|
|
9
|
+
* Next.js stack: next-components
|
|
11
10
|
*
|
|
12
11
|
* Usage:
|
|
13
12
|
* morph-spec validate [options]
|
|
@@ -21,12 +20,7 @@
|
|
|
21
20
|
import chalk from 'chalk';
|
|
22
21
|
import { getStackProfile } from '../src/lib/stack/stack-profile.js';
|
|
23
22
|
|
|
24
|
-
/**
|
|
25
|
-
* Build the VALIDATORS registry for the current stack.
|
|
26
|
-
* .NET stacks → packages, architecture, contrast, spec-tasks
|
|
27
|
-
* nextjs stack → next-components, spec-tasks
|
|
28
|
-
* other stacks → spec-tasks only
|
|
29
|
-
*/
|
|
23
|
+
/** The validators of the current stack: .NET → packages, Next.js → next-components. */
|
|
30
24
|
async function buildValidators(stack) {
|
|
31
25
|
const validators = {};
|
|
32
26
|
|
|
@@ -35,24 +29,12 @@ async function buildValidators(stack) {
|
|
|
35
29
|
|
|
36
30
|
if (isDotnet) {
|
|
37
31
|
const { validatePackages } = await import('../src/lib/validators/packages/package-validator.js');
|
|
38
|
-
const { validateArchitecture } = await import('../src/lib/validators/architecture/architecture-validator.js');
|
|
39
|
-
const { validateContrast } = await import('../src/lib/validators/ui/ui-contrast-validator.js');
|
|
40
32
|
|
|
41
33
|
validators.packages = {
|
|
42
34
|
name: 'Package Compatibility',
|
|
43
35
|
description: 'Validates NuGet package versions against .NET compatibility matrix',
|
|
44
36
|
run: validatePackages
|
|
45
37
|
};
|
|
46
|
-
validators.architecture = {
|
|
47
|
-
name: 'Architecture Patterns',
|
|
48
|
-
description: 'Detects DI anti-patterns, middleware issues, and configuration problems in .NET',
|
|
49
|
-
run: validateArchitecture
|
|
50
|
-
};
|
|
51
|
-
validators.contrast = {
|
|
52
|
-
name: 'UI Contrast (WCAG)',
|
|
53
|
-
description: 'Validates color contrast ratios for accessibility',
|
|
54
|
-
run: validateContrast
|
|
55
|
-
};
|
|
56
38
|
}
|
|
57
39
|
|
|
58
40
|
if (isNextjs) {
|
|
@@ -64,111 +46,9 @@ async function buildValidators(stack) {
|
|
|
64
46
|
};
|
|
65
47
|
}
|
|
66
48
|
|
|
67
|
-
validators['spec-tasks'] = {
|
|
68
|
-
name: 'Spec vs Tasks Coverage',
|
|
69
|
-
description: 'Validates that tasks.json covers all requirements from spec.md',
|
|
70
|
-
run: validateSpecVsTasks
|
|
71
|
-
};
|
|
72
|
-
|
|
73
49
|
return validators;
|
|
74
50
|
}
|
|
75
51
|
|
|
76
|
-
/**
|
|
77
|
-
* Validate spec.md requirements are covered by tasks
|
|
78
|
-
*/
|
|
79
|
-
async function validateSpecVsTasks(projectPath, options = {}) {
|
|
80
|
-
const path = await import('path');
|
|
81
|
-
const fs = await import('fs');
|
|
82
|
-
const { loadState } = await import('../src/core/state/state-manager.js');
|
|
83
|
-
|
|
84
|
-
const results = [];
|
|
85
|
-
let errors = 0;
|
|
86
|
-
let warnings = 0;
|
|
87
|
-
|
|
88
|
-
try {
|
|
89
|
-
const state = loadState(false);
|
|
90
|
-
if (!state || !state.features) {
|
|
91
|
-
return { status: 'ok', errors: 0, warnings: 0, message: 'No features to validate' };
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
for (const [featureName, feature] of Object.entries(state.features)) {
|
|
95
|
-
const outputsPath = path.join(projectPath, '.morph/features', featureName);
|
|
96
|
-
const specPath = path.join(outputsPath, 'spec.md');
|
|
97
|
-
|
|
98
|
-
if (!fs.existsSync(specPath)) {
|
|
99
|
-
continue; // No spec to validate
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Read spec.md and extract requirements
|
|
103
|
-
const specContent = fs.readFileSync(specPath, 'utf-8');
|
|
104
|
-
|
|
105
|
-
// Extract requirement patterns (## Requisitos, - [ ], numbered lists, etc.)
|
|
106
|
-
const requirementPatterns = [
|
|
107
|
-
/^#+\s*Requisitos?\s*$/gim,
|
|
108
|
-
/^-\s*\[.\]\s*(.+)$/gm,
|
|
109
|
-
/^\d+\.\s+(.+)$/gm
|
|
110
|
-
];
|
|
111
|
-
|
|
112
|
-
const requirements = [];
|
|
113
|
-
for (const pattern of requirementPatterns) {
|
|
114
|
-
const matches = specContent.matchAll(pattern);
|
|
115
|
-
for (const match of matches) {
|
|
116
|
-
if (match[1]) {
|
|
117
|
-
requirements.push(match[1].trim());
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Check if feature has tasks
|
|
123
|
-
if (!feature.tasks || (Array.isArray(feature.tasks) && feature.tasks.length === 0)) {
|
|
124
|
-
if (requirements.length > 0) {
|
|
125
|
-
warnings++;
|
|
126
|
-
results.push({
|
|
127
|
-
feature: featureName,
|
|
128
|
-
level: 'warning',
|
|
129
|
-
message: `Spec has ${requirements.length} requirements but no tasks defined`
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
continue;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
// Get task titles
|
|
136
|
-
const taskTitles = Array.isArray(feature.tasks)
|
|
137
|
-
? feature.tasks.map(t => t.title?.toLowerCase() || '')
|
|
138
|
-
: [];
|
|
139
|
-
|
|
140
|
-
// Check each requirement has a matching task (fuzzy match)
|
|
141
|
-
for (const req of requirements.slice(0, 20)) { // Limit to first 20
|
|
142
|
-
const reqLower = req.toLowerCase();
|
|
143
|
-
const hasMatch = taskTitles.some(title =>
|
|
144
|
-
title.includes(reqLower.slice(0, 20)) ||
|
|
145
|
-
reqLower.includes(title.slice(0, 20))
|
|
146
|
-
);
|
|
147
|
-
|
|
148
|
-
if (!hasMatch && options.verbose) {
|
|
149
|
-
console.log(chalk.gray(` ? Requirement may not be covered: "${req.slice(0, 50)}..."`));
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
if (options.verbose) {
|
|
154
|
-
console.log(chalk.green(` ✓ ${featureName}: ${requirements.length} requirements, ${taskTitles.length} tasks`));
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
} catch (error) {
|
|
159
|
-
if (options.verbose) {
|
|
160
|
-
console.log(chalk.yellow(` ⚠ Could not validate: ${error.message}`));
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return {
|
|
165
|
-
status: errors > 0 ? 'error' : warnings > 0 ? 'warning' : 'ok',
|
|
166
|
-
errors,
|
|
167
|
-
warnings,
|
|
168
|
-
results
|
|
169
|
-
};
|
|
170
|
-
}
|
|
171
|
-
|
|
172
52
|
/**
|
|
173
53
|
* Main validation command
|
|
174
54
|
*/
|
|
@@ -273,8 +153,7 @@ async function runValidator(VALIDATORS, name, options) {
|
|
|
273
153
|
try {
|
|
274
154
|
const result = await validator.run('.', {
|
|
275
155
|
verbose: true, // Always verbose for single validator
|
|
276
|
-
autoFix: options.autoFix
|
|
277
|
-
wcagLevel: options.wcagLevel
|
|
156
|
+
autoFix: options.autoFix
|
|
278
157
|
});
|
|
279
158
|
|
|
280
159
|
if (result.status === 'ok') {
|
|
@@ -302,8 +181,7 @@ function parseOptions(args) {
|
|
|
302
181
|
const options = {
|
|
303
182
|
verbose: false,
|
|
304
183
|
autoFix: false,
|
|
305
|
-
noFail: false
|
|
306
|
-
wcagLevel: 'AA'
|
|
184
|
+
noFail: false
|
|
307
185
|
};
|
|
308
186
|
|
|
309
187
|
for (const arg of args) {
|
|
@@ -313,8 +191,6 @@ function parseOptions(args) {
|
|
|
313
191
|
options.autoFix = true;
|
|
314
192
|
} else if (arg === '--no-fail') {
|
|
315
193
|
options.noFail = true;
|
|
316
|
-
} else if (arg === '--wcag-aaa') {
|
|
317
|
-
options.wcagLevel = 'AAA';
|
|
318
194
|
}
|
|
319
195
|
}
|
|
320
196
|
|
|
@@ -334,20 +210,15 @@ ${chalk.bold('USAGE')}
|
|
|
334
210
|
${chalk.bold('VALIDATORS')}
|
|
335
211
|
all Run all validators (default)
|
|
336
212
|
packages Validate NuGet package compatibility (.NET 10)
|
|
337
|
-
architecture Validate architecture patterns (DI, lifecycle)
|
|
338
|
-
contrast Validate UI contrast ratios (WCAG 2.1)
|
|
339
213
|
|
|
340
214
|
${chalk.bold('OPTIONS')}
|
|
341
215
|
--verbose, -v Show detailed output
|
|
342
216
|
--auto-fix, --fix Auto-fix issues where possible
|
|
343
217
|
--no-fail Don't exit with error code
|
|
344
|
-
--wcag-aaa Use WCAG AAA standard (stricter)
|
|
345
218
|
|
|
346
219
|
${chalk.bold('EXAMPLES')}
|
|
347
220
|
morph-spec validate # Run all validators
|
|
348
221
|
morph-spec validate packages --fix # Validate packages and auto-fix
|
|
349
|
-
morph-spec validate architecture -v # Verbose architecture validation
|
|
350
|
-
morph-spec validate contrast --wcag-aaa # Stricter contrast validation
|
|
351
222
|
morph-spec validate all # Run all validators
|
|
352
223
|
|
|
353
224
|
${chalk.bold('EXIT CODES')}
|
package/claude-plugin.json
CHANGED
package/docs/CHEATSHEET.md
CHANGED
|
@@ -94,7 +94,7 @@ Never hand-edit `gateDecisions`/`approvalGates` in `feature.json` — always go
|
|
|
94
94
|
## CLI — validation
|
|
95
95
|
|
|
96
96
|
```bash
|
|
97
|
-
morph-spec validate [
|
|
97
|
+
morph-spec validate [packages|next-components|spec-tasks]
|
|
98
98
|
morph-spec validate-feature {feature} [--phase {phase}] [--json] # alias: vf
|
|
99
99
|
morph-spec verify {feature} [task] [--json] [--skip-tests] [--skip-build] # deterministic build+test+validator chain, before the LLM judge
|
|
100
100
|
```
|
|
@@ -185,4 +185,4 @@ Never edited directly — go through CLI commands or `morph-spec update` instead
|
|
|
185
185
|
|
|
186
186
|
---
|
|
187
187
|
|
|
188
|
-
*morph-spec
|
|
188
|
+
*morph-spec v9.0.0 by Polymorphism Tech*
|
package/docs/QUICKSTART.md
CHANGED
package/framework/CLAUDE.md
CHANGED
|
@@ -1,114 +1,54 @@
|
|
|
1
1
|
# MORPH-SPEC Runtime Instructions
|
|
2
2
|
|
|
3
|
-
> by Polymorphism Tech —
|
|
4
|
-
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
1. Leia `.morph/framework/MORPH.md`
|
|
8
|
-
2.
|
|
9
|
-
3.
|
|
10
|
-
4.
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
-
|
|
18
|
-
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
3
|
+
> by Polymorphism Tech — harness spec-driven para Claude Code
|
|
4
|
+
|
|
5
|
+
## Início de cada sessão
|
|
6
|
+
|
|
7
|
+
1. Leia `.morph/framework/MORPH.md` uma vez (de novo após `/compact`): papéis, fases, gates, dispatch.
|
|
8
|
+
2. `.morph/state.json` é índice gitignored, só para achar a feature ativa; o estado autoritativo é `.morph/features/{feature}/feature.json`.
|
|
9
|
+
3. Existe `.morph/features/{feature}/handoff.md`? Leia antes de re-derivar contexto à mão.
|
|
10
|
+
4. Feature em andamento → assuma o papel da fase e continue entre gates sem esperar instrução. Nenhuma ativa → pergunte qual trabalhar.
|
|
11
|
+
|
|
12
|
+
## Regras
|
|
13
|
+
|
|
14
|
+
- Perguntas ao usuário só por `AskUserQuestion` (1-4 por chamada), nunca em texto solto. Na entrevista da `morph-plan`, **uma pergunta por chamada**: lote impede que uma resposta pode os ramos seguintes. Única exceção: ferramenta indisponível ou negada (headless) — texto numerado com a resposta recomendada e gate pausado (`morph-plan` §3).
|
|
15
|
+
- A pergunta de gate nomeia a feature ("Gate do plano — Plano de {feature} aprovado?"): é por esse nome que o hook `state-sync` grava a aprovação no `feature.json` certo; sem nome, com mais de uma feature, ele recusa e você aprova por `morph-spec approve <feature> <gate>`.
|
|
16
|
+
- Estado só pela CLI, nunca à mão: `feature.json`, `gateDecisions`, `checks.json` (escrito só por `plan-check`) e o corpo do `plan.md` depois do gate (fato errado → `## Errata` no fim; escopo mudou → `unapprove`).
|
|
17
|
+
- SessionStart avisou claim vivo de outra sessão na mesma feature → confirme com o usuário antes de `finish`/`archive`/`delete`.
|
|
18
|
+
- Depois de um dispatch, leia o arquivo de relatório da fatia, não a mensagem final, que pode não chegar.
|
|
19
|
+
|
|
20
|
+
## CLI do loop
|
|
21
|
+
|
|
22
|
+
Prefixo `morph-spec`; flags e porquês em `.morph/framework/CLI.md` (um `###` por comando).
|
|
23
|
+
|
|
24
|
+
| Comando | Para quê |
|
|
25
|
+
|---|---|
|
|
26
|
+
| `create <f> --description "…" --type <t> [--worktree]` | nasce a feature; exit 2 = você escolhe o tipo |
|
|
27
|
+
| `stack-scan [f]` | desvios do código contra `project.stack` |
|
|
28
|
+
| `plan-check <f>` | valida `plan.md`, grava `checks.json`, imprime as ondas |
|
|
29
|
+
| `gate-check <f> <gate>` | decide a pausa pelos sinais do disco |
|
|
30
|
+
| `approve <f> <gate> --mode auto` / `advance <f>` | aprova (advance também abre a próxima fase) |
|
|
31
|
+
| `verify <f> [--ci]` | build + testes + validadores + e2e, sem filtro |
|
|
32
|
+
| `report-check <f> [F1 …]` | audita o relatório de cada fatia e diz a ação |
|
|
33
|
+
| `mutate <f>` | mutação dirigida do Gate 3 (até 3 mutantes) |
|
|
34
|
+
| `finish <f> --pr\|--merge` | encerra; só o `--merge` integra |
|
|
35
|
+
| `standards --find "<tema>"` / `--show <id>#<âncora>` | digest do standard / uma seção |
|
|
36
|
+
| `heavy status\|run -- <cmd>` | fila de build/teste; exit 3 = fila cheia |
|
|
37
|
+
| `worktree setup\|provision\|link\|remove\|list\|reap` | ciclo da worktree; `remove` é a única remoção segura |
|
|
38
|
+
| `graph affected\|explain <sym>` | blast radius; sem grafo, caia para grep |
|
|
36
39
|
|
|
37
40
|
## Slash commands
|
|
38
41
|
|
|
39
|
-
|
|
40
|
-
|---------|-----------|
|
|
41
|
-
| `/morph-proposal {feature}` | Entendimento de negócio + plano (Gates 1 e 2). Passo 0 roteia por tipo de trabalho (`feature`/`bug`/`chore`/`hotfix`) |
|
|
42
|
-
| `/morph-hotfix {feature}` | ADW cirúrgico de hotfix (scout → fix → gate humano → ship) |
|
|
43
|
-
| `/morph-apply {feature}` | Execução autônoma + review (Gate 3) |
|
|
44
|
-
| `/morph-status [feature]` | Status da feature ativa (ou a especificada) |
|
|
45
|
-
| `/morph-archive {feature}` | Arquiva-**sem-integrar** (legadas/faxina) — wrapper de `archive`. Fechamento normal = `finish --pr\|--merge` |
|
|
46
|
-
| `/morph-preflight` | Validação pré-deploy (specs, contratos, testes, infra) |
|
|
47
|
-
| `/morph-troubleshoot [erro]` | Diagnóstico de erros .NET/Next.js com root-cause analysis |
|
|
48
|
-
|
|
49
|
-
**Comandos CLI de gate e de estado** (a LLM os usa em vez de editar o estado à mão):
|
|
50
|
-
|
|
51
|
-
| Comando | Propósito |
|
|
52
|
-
|---------|-----------|
|
|
53
|
-
| `approve <f> <gate> --mode auto` | Aprova gate em `trust:auto`. Gate 3 exige `evaluator-report.md` (ou `--self-assessed`); `hotfix` nunca aceita `--mode auto` — use `--approver` |
|
|
54
|
-
| `advance <f>` | Aprova o gate corrente + já cria a pasta da próxima fase |
|
|
55
|
-
| `gate-check <f> <gate> [--json]` | Default: decide via sinais do disco (`shouldPauseGate`) |
|
|
56
|
-
| `gate-decision <f> <gate> --pause <bool>` | Escape manual: risco que o disco não vê |
|
|
57
|
-
| `create <f> --description "..." --type <t>` | Nasce a feature + `feature.json`; `--worktree` já isola |
|
|
58
|
-
| `list [--all] [--json]` | Quadro de auditoria: feature × workType × status × gates |
|
|
59
|
-
| `delete <f> [--archive] [--force]` | Remove feature; recusa se gate aprovado sem `--force` |
|
|
60
|
-
| `retype <f> <tipo>` | Muda o workType mid-flight; bloqueado após o Gate 3 |
|
|
61
|
-
| `finish <f> --pr\|--merge` | Encerramento único: arquiva, promove use cases, desmonta worktree. Integra só no `--merge`; `--pr` abre PR e fica `aguardando-merge` até alguém mergear |
|
|
62
|
-
| `archive <f>` | Arquiva sem integrar (legadas/faxina) |
|
|
63
|
-
| `worktree setup\|provision\|link\|remove\|list\|reap` | Ciclo do worktree; `provision` = isolamento de task; `remove` é a única remoção segura |
|
|
64
|
-
| `branch prune [--dry-run]` | Apaga branch já integrada, inclusive squash-merge; nunca a com PR aberto |
|
|
65
|
-
| `handoff <f>` | Regenera o documento de retomada da feature |
|
|
66
|
-
| `fleet` | Visão agregada de toda feature ativa (raiz + worktrees) |
|
|
67
|
-
| `claim [f] [--release] [--list]` | Posse advisory — confirme antes de `finish`/`archive`/`delete` se outra sessão tiver claim vivo |
|
|
68
|
-
| `dag <f>` | DAG de `tasks.json`: sequencial/paralelo, recomenda isolamento |
|
|
69
|
-
| `graph status\|build\|refresh` | Grafo de codebase. `status` reporta frescor e se há refresh em background |
|
|
70
|
-
| `graph affected\|explain <sym>` | Blast radius e vizinhança saneados. Sem grafo, caia para grep — nunca é erro |
|
|
71
|
-
| `verify <f> [task] [--ci]` | Build+testes+validadores+e2e — prova da task; a do Gate 3 com `--ci` (no CI) |
|
|
72
|
-
| `e2e up\|status\|down <f>` | Stack de verificação (docker compose) |
|
|
73
|
-
| `doctor --worktrees [--prune]` | Reconcilia git × disco × features; só `--prune` remove algo |
|
|
74
|
-
| `report-check <f> [task...] [--json]` | Audita relatório de sub-agent vs. trabalho entregue |
|
|
75
|
-
| `telemetry [--feature] [--limit]` | Caminho de execução da sessão a partir de `events.jsonl` |
|
|
76
|
-
| `cost [f] [--by task\|phase] [--metrics]` | Custo (bytes/duração) e medições do loop (turnos, rerun, releitura) do mesmo log |
|
|
77
|
-
|
|
78
|
-
Prefixo de todo comando: `morph-spec`. Flags/exemplos: `.morph/framework/CLI.md`.
|
|
79
|
-
|
|
80
|
-
## Skills core (em `.claude/skills/`)
|
|
81
|
-
|
|
82
|
-
| Skill | Quando usar |
|
|
83
|
-
|-------|-------------|
|
|
84
|
-
| `morph-brainstorming` | Entender negócio, escanear stack, produzir proposal.md |
|
|
85
|
-
| `morph-stack-scan` | Desvios de stack em projeto brownfield |
|
|
86
|
-
| `morph-uiux` | Ramo opcional de UI/UX — design system e mockups |
|
|
87
|
-
| `morph-plan` | Destilar use cases e produzir spec.md + tasks.json |
|
|
88
|
-
| `morph-implement` | Executar uma tarefa com auto-advance entre tasks |
|
|
89
|
-
| `morph-review` | Produzir review-report.md (Gate 3) |
|
|
90
|
-
| `morph-hotfix` | Hotfix cirúrgico (`/morph-hotfix`) |
|
|
91
|
-
| `morph-standards` | Localizar standard sob demanda |
|
|
92
|
-
| `morph-machine` | RAM/CPU: fila pesada, órfãos, worktrees sobrando |
|
|
93
|
-
|
|
94
|
-
## Roteamento por tipo de trabalho
|
|
95
|
-
|
|
96
|
-
`workType` (`create --type <tipo>` ou classificado de `--request`) dimensiona o pipeline: `feature` completo (+ ramo uiux quando há superfície de UI), `bug` enxuto, `chore` fast-track (Gates 1/2 por política), `hotfix` scout→fix→gate humano→ship. Canônico: `MORPH.md` §2.1/§5.
|
|
97
|
-
|
|
98
|
-
Features independentes rodam em paralelo, uma por git worktree (`create --worktree`/`worktree setup`), bloco de portas próprio + handoff.md. Fechamento: `finish <f> --pr|--merge`; agregado: `fleet`. Canônico: `MORPH.md` §2.2.
|
|
42
|
+
`/morph-proposal {f}` (plano), `/morph-apply {f}` (execução + Gate 3), `/morph-hotfix {f}`, `/morph-status [f]`.
|
|
99
43
|
|
|
100
44
|
## Personas (em `.claude/agents/`)
|
|
101
45
|
|
|
102
|
-
Despache
|
|
46
|
+
Despache fatias com `subagent_type: "morph-{id}"` — a persona, gerada de `agents.json`, é o system prompt. Tipo não registrado: `general-purpose` com o `persona` colado, registrado no relatório da fatia. Nunca edite `.claude/agents/morph-*.md` à mão (`morph-spec doctor` acusa o drift).
|
|
103
47
|
|
|
104
48
|
<!-- morph-agents:start -->
|
|
105
|
-
_Lista derivada na instalação
|
|
49
|
+
_Lista derivada na instalação. Bloco vazio → `morph-spec setup-infra --reinstall`._
|
|
106
50
|
<!-- morph-agents:end -->
|
|
107
51
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
## Regra de precedência de skills
|
|
111
|
-
|
|
112
|
-
Com o plugin superpowers ativo, `morph-*` vence o equivalente genérico (aplica Gates e paths de `.morph/`), e `using-git-worktrees`→`morph-spec worktree setup|provision`.
|
|
52
|
+
## Precedência de skills
|
|
113
53
|
|
|
114
|
-
|
|
54
|
+
Com o plugin superpowers ativo, `morph-*` vence o equivalente genérico (aplica os gates e os paths de `.morph/`), e `using-git-worktrees`→`morph-spec worktree setup|provision`.
|