@polymorphism-tech/morph-spec 9.0.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 +8 -9
- package/README.md +38 -36
- package/bin/morph-spec.js +4 -62
- package/bin/validate.js +1 -39
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +1 -1
- package/framework/MORPH.md +1 -1
- package/framework/agents.json +12 -4
- package/framework/commands/morph-apply.md +1 -1
- package/framework/commands/morph-status.md +1 -1
- package/framework/docs/CLI.md +6 -17
- 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 +2 -16
- package/framework/hooks/claude-code/core/enforce-phase-writes.js +6 -50
- package/framework/hooks/claude-code/core/gate-guard.js +7 -67
- 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 +0 -4
- package/framework/hooks/claude-code/core/protect-spec-files.js +7 -67
- package/framework/hooks/claude-code/core/state-sync.js +11 -67
- package/framework/hooks/claude-code/core/telemetry-log.js +12 -93
- package/framework/hooks/claude-code/core/validate-completion.js +11 -57
- package/framework/hooks/claude-code/core/warn-bash-source-write.js +1 -9
- package/framework/hooks/claude-code/core/worktree-context.js +10 -110
- 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/shared/activity-logger.js +9 -89
- package/framework/hooks/shared/agent-reap.js +2 -17
- package/framework/hooks/shared/build-check.js +6 -75
- package/framework/hooks/shared/claim-registry.js +9 -119
- package/framework/hooks/shared/command-tokens.js +6 -51
- package/framework/hooks/shared/comment-rules.js +5 -20
- package/framework/hooks/shared/comment-scanner.js +6 -25
- package/framework/hooks/shared/comment-stripper.js +11 -85
- package/framework/hooks/shared/e2e-check.js +0 -0
- package/framework/hooks/shared/errata.js +2 -15
- package/framework/hooks/shared/feature-locator.js +11 -95
- package/framework/hooks/shared/frontend-locations.js +1 -3
- package/framework/hooks/shared/gate-question.js +1 -7
- 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 +1 -42
- 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 +4 -23
- package/framework/hooks/shared/source-files.js +4 -17
- package/framework/hooks/shared/state-reader.js +13 -183
- package/framework/hooks/shared/state-writer.js +8 -52
- 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/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/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 +2 -2
- package/framework/skills/core/morph-hotfix/SKILL.md +1 -1
- package/framework/skills/core/morph-machine/SKILL.md +1 -1
- package/framework/skills/core/morph-media/SKILL.md +1 -1
- package/framework/skills/core/morph-plan/SKILL.md +2 -2
- package/framework/skills/core/morph-review/SKILL.md +1 -1
- package/framework/skills/core/morph-standards/SKILL.md +1 -1
- package/framework/skills/core/morph-uiux/SKILL.md +29 -12
- package/framework/standards/STANDARDS.json +34 -12
- package/framework/standards/STANDARDS.meta.json +16 -2
- 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/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 +2 -2
- 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 +1 -1
- 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/templates/CLAUDE.md.core.template +3 -3
- package/framework/templates/REGISTRY.json +9 -9
- package/framework/templates/docs/ui-mockups.md +4 -0
- 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 +17 -104
- 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 +5 -57
- 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.js +48 -302
- package/src/commands/project/env.js +1 -27
- package/src/commands/project/fleet.js +3 -32
- package/src/commands/project/init.js +4 -68
- package/src/commands/project/install-plugin-cmd.js +0 -1
- package/src/commands/project/standards.js +1 -62
- package/src/commands/project/status.js +0 -53
- package/src/commands/project/update.js +31 -239
- package/src/commands/project/worktree.js +108 -882
- package/src/commands/scaffold/scaffold.js +0 -25
- package/src/commands/state/advance.js +14 -85
- package/src/commands/state/approve.js +14 -96
- package/src/commands/state/archive.js +12 -64
- package/src/commands/state/auto-approval.js +2 -5
- package/src/commands/state/create.js +22 -109
- package/src/commands/state/delete.js +11 -63
- package/src/commands/state/finish.js +98 -475
- package/src/commands/state/gate-check.js +22 -132
- package/src/commands/state/gate-decision.js +3 -39
- package/src/commands/state/handoff.js +3 -30
- package/src/commands/state/list.js +14 -84
- package/src/commands/state/report-check.js +8 -58
- package/src/commands/state/retype.js +4 -26
- package/src/commands/validation/index.js +0 -3
- package/src/commands/validation/mutate.js +2 -5
- package/src/commands/validation/validate-feature.js +5 -94
- package/src/commands/validation/verify.js +15 -98
- package/src/core/paths/output-schema.js +2 -101
- package/src/core/state/feature-identity.js +1 -25
- package/src/core/state/gate-order.js +0 -27
- package/src/core/state/lifecycle-audit.js +8 -100
- package/src/core/state/state-manager.js +22 -304
- 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 +0 -1
- package/src/core/work-types.js +1 -36
- package/src/dashboard/app/App.jsx +1 -8
- package/src/dashboard/app/components/ActivityFeed.jsx +0 -5
- package/src/dashboard/app/components/CommandPalette.jsx +0 -7
- 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 +1 -5
- package/src/dashboard/app/lib/project.js +0 -12
- package/src/dashboard/app/pages/AgentMap.jsx +1 -8
- package/src/dashboard/app/pages/FeatureDetail.jsx +1 -5
- package/src/dashboard/app/pages/Features.jsx +1 -8
- package/src/dashboard/app/pages/Guide.jsx +0 -1
- package/src/dashboard/app/pages/HookInspector.jsx +2 -23
- package/src/dashboard/app/pages/PhasePipeline.jsx +0 -3
- 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 +10 -69
- package/src/dashboard/scanner/agents-scanner.js +1 -23
- package/src/dashboard/scanner/docs-scanner.js +0 -6
- package/src/dashboard/scanner/feature-status.js +2 -5
- package/src/dashboard/scanner/features-scanner.js +10 -66
- 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 +2 -6
- 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 +4 -19
- 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 +4 -50
- 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 +9 -53
- package/src/lib/generators/scaffold-generator.js +5 -101
- package/src/lib/generators/settings-generator.js +4 -37
- 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 +1 -0
- 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 +3 -15
- 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 +1 -1
- package/src/lib/installers/effects.js +8 -93
- package/src/lib/installers/mcp-installer.js +9 -169
- package/src/lib/installers/memory-installer.js +4 -27
- package/src/lib/installers/templates-reconcile.js +5 -60
- package/src/lib/mutation/dotnet-introspection.js +20 -106
- package/src/lib/mutation/subset.js +1 -4
- package/src/lib/plan/artifact-vocabulary.js +5 -25
- package/src/lib/plan/checks.js +5 -31
- package/src/lib/plan/plan-parser.js +1 -6
- package/src/lib/projects/registry.js +7 -44
- package/src/lib/review-reports.js +5 -23
- package/src/lib/risk-detector.js +39 -173
- package/src/lib/specs/adr-index.js +6 -34
- package/src/lib/specs/frontmatter.js +2 -15
- package/src/lib/specs/gfm-table.js +1 -7
- package/src/lib/specs/revocations.js +1 -14
- package/src/lib/specs/screen-checklist.js +47 -124
- package/src/lib/stack/dotnet-build-ignores.js +2 -6
- package/src/lib/stack/stack-profile.js +1 -28
- package/src/lib/stack/stack-scan.js +1 -8
- package/src/lib/stack-filter.js +4 -27
- package/src/lib/standards/registry.js +1 -7
- package/src/lib/standards/sections.js +2 -13
- package/src/lib/standards/verified-against.js +19 -191
- package/src/lib/tasks/eval-node.js +21 -169
- package/src/lib/tasks/linux-runner.js +18 -142
- package/src/lib/tasks/test-nodes.js +43 -240
- package/src/lib/tasks/test-runner.js +43 -341
- package/src/lib/telemetry/metrics.js +7 -36
- package/src/lib/telemetry/telemetry-reader.js +13 -125
- package/src/lib/telemetry/verify-event.js +2 -30
- package/src/lib/validators/code-budget/code-budget-validator.js +3 -43
- package/src/lib/validators/code-budget/index.js +0 -7
- package/src/lib/validators/contracts/contract-compliance-validator.js +2 -24
- 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 +11 -101
- package/src/lib/validators/reuse/symbol-scanner.js +6 -62
- package/src/lib/validators/traceability-check.js +5 -63
- package/src/lib/validators/validation-runner.js +20 -125
- package/src/lib/validators/verify-runner.js +52 -358
- package/src/lib/work-type-detector.js +5 -67
- package/src/lib/worktree/docker-audit.js +17 -136
- 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 +13 -95
- 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 -147
- package/src/utils/agents-installer.js +28 -275
- package/src/utils/banner.js +4 -25
- package/src/utils/claude-md-injector.js +1 -37
- package/src/utils/claude-settings-manager.js +1 -52
- package/src/utils/file-copier.js +11 -95
- package/src/utils/hooks-installer.js +21 -298
- package/src/utils/skills-installer.js +4 -101
- package/src/utils/version-checker.js +4 -83
- package/framework/commands/morph-proposal.md +0 -9
- package/src/commands/utils/index.js +0 -3
- package/src/lib/detectors/design-system-detector.js +0 -188
- package/src/lib/generators/design-system-generator.js +0 -508
- package/src/lib/specs/old-format.js +0 -68
- package/src/utils/agent-id-mapper.js +0 -11
package/bin/morph-spec.js
CHANGED
|
@@ -1,14 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* morph-spec CLI v5
|
|
5
|
-
*
|
|
6
|
-
* In v5 the CLI is the *installer* — Claude executes everything else
|
|
7
|
-
* autonomously based on MORPH.md and the core skills. Commands here are
|
|
8
|
-
* limited to actions that humans take or operations Claude needs help with
|
|
9
|
-
* (scaffolding, validation, context refresh).
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
3
|
import { program } from 'commander';
|
|
13
4
|
import chalk from 'chalk';
|
|
14
5
|
import { fileURLToPath } from 'url';
|
|
@@ -16,14 +7,9 @@ import { dirname, join } from 'path';
|
|
|
16
7
|
import { readFileSync } from 'fs';
|
|
17
8
|
import { renderLogo, maybePrintFirstRunBanner } from '../src/utils/banner.js';
|
|
18
9
|
|
|
19
|
-
//
|
|
20
|
-
// ~700 ms on EVERY invocation (init.js alone pulls inquirer: ~550 ms), paid
|
|
21
|
-
// by each hook that shells out to the CLI and by each CLI spawn in the suite.
|
|
22
|
-
// test/bin/command-modules-import.test.js imports every path below, so a module
|
|
23
|
-
// that breaks at import time still fails the suite, not only its own command.
|
|
10
|
+
// Lazy: eager import of every command cost ~700 ms per invocation, paid by each hook that shells out.
|
|
24
11
|
const lazy = (path, name) => async (...args) => (await import(path))[name](...args);
|
|
25
12
|
|
|
26
|
-
// === Project / install ===
|
|
27
13
|
const initCommand = lazy('../src/commands/project/init.js', 'initCommand');
|
|
28
14
|
const setupInfraCommand = lazy('../src/commands/project/setup-infra-cmd.js', 'setupInfraCommand');
|
|
29
15
|
const installPluginCommand = lazy('../src/commands/project/install-plugin-cmd.js', 'installPluginCommand');
|
|
@@ -48,7 +34,6 @@ const scoutCheckCommand = lazy('../src/commands/validation/scout-check.js', 'sco
|
|
|
48
34
|
const planCheckCommand = lazy('../src/commands/validation/plan-check.js', 'planCheckCommand');
|
|
49
35
|
const stackScanCommand = lazy('../src/commands/project/stack-scan.js', 'stackScanCommand');
|
|
50
36
|
|
|
51
|
-
// === Approval gates (human-only) ===
|
|
52
37
|
const approveCommand = lazy('../src/commands/state/approve.js', 'approveCommand');
|
|
53
38
|
const approvalStatusCommand = lazy('../src/commands/state/approve.js', 'approvalStatusCommand');
|
|
54
39
|
const unapproveCommand = lazy('../src/commands/state/approve.js', 'unapproveCommand');
|
|
@@ -63,15 +48,11 @@ const handoffCommand = lazy('../src/commands/state/handoff.js', 'handoffCommand'
|
|
|
63
48
|
const listCommand = lazy('../src/commands/state/list.js', 'listCommand');
|
|
64
49
|
const deleteCommand = lazy('../src/commands/state/delete.js', 'deleteCommand');
|
|
65
50
|
|
|
66
|
-
// === Tasks ===
|
|
67
|
-
|
|
68
|
-
// === Codebase graph ===
|
|
69
51
|
const graphStatusCommand = lazy('../src/commands/graph/status.js', 'graphStatusCommand');
|
|
70
52
|
const graphBuildCommand = lazy('../src/commands/graph/build.js', 'graphBuildCommand');
|
|
71
53
|
const graphAffectedCommand = lazy('../src/commands/graph/affected.js', 'graphAffectedCommand');
|
|
72
54
|
const graphExplainCommand = lazy('../src/commands/graph/explain.js', 'graphExplainCommand');
|
|
73
55
|
|
|
74
|
-
// === Validation ===
|
|
75
56
|
const validateCommand = lazy('./validate.js', 'validateCommand');
|
|
76
57
|
const validateFeatureCommand = lazy('../src/commands/validation/validate-feature.js', 'validateFeatureCommand');
|
|
77
58
|
const verifyCommand = lazy('../src/commands/validation/verify.js', 'verifyCommand');
|
|
@@ -80,20 +61,15 @@ const e2eUpCommand = lazy('../src/commands/e2e/e2e.js', 'e2eUpCommand');
|
|
|
80
61
|
const e2eStatusCommand = lazy('../src/commands/e2e/e2e.js', 'e2eStatusCommand');
|
|
81
62
|
const e2eDownCommand = lazy('../src/commands/e2e/e2e.js', 'e2eDownCommand');
|
|
82
63
|
|
|
83
|
-
// === Scaffolding ===
|
|
84
64
|
const scaffoldDotnetCommand = lazy('../src/commands/scaffold/scaffold.js', 'scaffoldDotnetCommand');
|
|
85
65
|
const scaffoldNextjsCommand = lazy('../src/commands/scaffold/scaffold.js', 'scaffoldNextjsCommand');
|
|
86
66
|
|
|
87
|
-
// === MCP setup ===
|
|
88
67
|
const mcpSetupCommand = lazy('../src/commands/mcp/mcp-setup.js', 'mcpSetupCommand');
|
|
89
68
|
|
|
90
|
-
// === Context refresh ===
|
|
91
69
|
const contextRefreshCommand = lazy('../src/commands/context/context-refresh.js', 'contextRefreshCommand');
|
|
92
70
|
|
|
93
|
-
// === Dashboard ===
|
|
94
71
|
const dashboardCommand = lazy('../src/commands/dashboard/dashboard.js', 'dashboardCommand');
|
|
95
72
|
|
|
96
|
-
// === Observability ===
|
|
97
73
|
const telemetryCommand = lazy('../src/commands/observability/telemetry.js', 'telemetryCommand');
|
|
98
74
|
const costCommand = lazy('../src/commands/observability/cost.js', 'costCommand');
|
|
99
75
|
|
|
@@ -104,9 +80,7 @@ const banner = `${renderLogo(pkg.version)}
|
|
|
104
80
|
${chalk.dim('Spec-driven development harness for Claude Code — by Polymorphism Tech')}
|
|
105
81
|
`;
|
|
106
82
|
|
|
107
|
-
//
|
|
108
|
-
// postinstall output). Skipped for --version/--help (parsed/already-bannered)
|
|
109
|
-
// and for non-TTY output — see maybePrintFirstRunBanner.
|
|
83
|
+
// npm >=7 hides postinstall output, so the first run after an install shows the banner.
|
|
110
84
|
const argvRest = process.argv.slice(2);
|
|
111
85
|
const skipFirstRun = argvRest.length === 0 ||
|
|
112
86
|
argvRest.some(a => ['-V', '--version', '-h', '--help'].includes(a));
|
|
@@ -120,7 +94,6 @@ program
|
|
|
120
94
|
.version(pkg.version)
|
|
121
95
|
.addHelpText('beforeAll', banner);
|
|
122
96
|
|
|
123
|
-
// ─── Install ──────────────────────────────────────────────────────────────
|
|
124
97
|
program
|
|
125
98
|
.command('init')
|
|
126
99
|
.description('Initialize MORPH-SPEC in current directory')
|
|
@@ -163,7 +136,6 @@ program
|
|
|
163
136
|
.option('--reset', 'Remove morph-managed entries from .claude/settings.local.json')
|
|
164
137
|
.action(doctorCommand);
|
|
165
138
|
|
|
166
|
-
// ─── Status / inspection ──────────────────────────────────────────────────
|
|
167
139
|
program
|
|
168
140
|
.command('status <feature>')
|
|
169
141
|
.description('Show feature status (phase, gate state, task counts)')
|
|
@@ -180,7 +152,6 @@ program
|
|
|
180
152
|
.option('--json', 'Output as JSON')
|
|
181
153
|
.action((options) => listCommand(options));
|
|
182
154
|
|
|
183
|
-
// ─── Approval gates (dev-only) ────────────────────────────────────────────
|
|
184
155
|
program
|
|
185
156
|
.command('approve <feature> <gate>')
|
|
186
157
|
.description('Approve a phase gate (plan, uiux, review). Enforces gate order (uiux and review require plan)')
|
|
@@ -293,7 +264,6 @@ program
|
|
|
293
264
|
.option('--here', 'Force building/writing in the current directory, even if another tree owns this feature')
|
|
294
265
|
.action((feature, options) => handoffCommand(feature, options));
|
|
295
266
|
|
|
296
|
-
// ─── Codebase graph ───────────────────────────────────────────────────────
|
|
297
267
|
const graphCommand = program
|
|
298
268
|
.command('graph')
|
|
299
269
|
.description('Grafo de codebase (graphify) com saneamento determinístico — fail-open: sem grafo, tudo segue por grep');
|
|
@@ -335,7 +305,6 @@ graphCommand
|
|
|
335
305
|
.option('--json', 'Output as JSON')
|
|
336
306
|
.action((symbol, options) => graphExplainCommand(symbol, options));
|
|
337
307
|
|
|
338
|
-
// ─── Validation ───────────────────────────────────────────────────────────
|
|
339
308
|
program
|
|
340
309
|
.command('validate [validator]')
|
|
341
310
|
.description('Run project validations (all | packages | next-components | spec-tasks)')
|
|
@@ -392,7 +361,6 @@ program
|
|
|
392
361
|
.option('--json', 'Output as JSON')
|
|
393
362
|
.action((feature, options) => mutateCommand(feature, options));
|
|
394
363
|
|
|
395
|
-
// ─── Scaffolding ──────────────────────────────────────────────────────────
|
|
396
364
|
const scaffoldCmd = program
|
|
397
365
|
.command('scaffold')
|
|
398
366
|
.description('Generate feature files from templates');
|
|
@@ -414,7 +382,6 @@ scaffoldCmd
|
|
|
414
382
|
.option('-v, --verbose', 'Show detailed output')
|
|
415
383
|
.action(scaffoldNextjsCommand);
|
|
416
384
|
|
|
417
|
-
// ─── MCP setup ────────────────────────────────────────────────────────────
|
|
418
385
|
const mcpCommand = program
|
|
419
386
|
.command('mcp')
|
|
420
387
|
.description('MCP server setup and configuration');
|
|
@@ -426,7 +393,6 @@ mcpCommand
|
|
|
426
393
|
.option('--auto', 'Auto-install credential-free MCPs without prompts')
|
|
427
394
|
.action((name, options) => mcpSetupCommand(name, options));
|
|
428
395
|
|
|
429
|
-
// ─── Context refresh ──────────────────────────────────────────────────────
|
|
430
396
|
const contextCommand = program
|
|
431
397
|
.command('context')
|
|
432
398
|
.description('Project context management (refresh)');
|
|
@@ -439,7 +405,6 @@ contextCommand
|
|
|
439
405
|
.option('--json', 'Output scan result as JSON')
|
|
440
406
|
.action((options) => contextRefreshCommand(options));
|
|
441
407
|
|
|
442
|
-
// ─── E2E stack (Docker bring-up for runtime verification) ─────────────────
|
|
443
408
|
const e2eCommand = program
|
|
444
409
|
.command('e2e')
|
|
445
410
|
.description("Lifecycle of the feature's verification stack (docker compose)");
|
|
@@ -464,7 +429,6 @@ e2eCommand
|
|
|
464
429
|
.option('--json', 'Output as JSON')
|
|
465
430
|
.action((feature, options) => e2eDownCommand(feature, options));
|
|
466
431
|
|
|
467
|
-
// ─── Heavy nodes (build, tests, e2e) ─────────────────────────────────────
|
|
468
432
|
const heavyCommand = program
|
|
469
433
|
.command('heavy')
|
|
470
434
|
.description('Slots por usuário para os nós pesados (build, testes, e2e), compartilhados entre as sessões');
|
|
@@ -481,7 +445,6 @@ heavyCommand
|
|
|
481
445
|
.option('--label <label>', 'Nome do que roda, mostrado a quem espera pelo slot')
|
|
482
446
|
.action((command, options) => heavyRunCommand(command, options));
|
|
483
447
|
|
|
484
|
-
// ─── Worktree (optional, isolation) ───────────────────────────────────────
|
|
485
448
|
const worktreeCommand = program
|
|
486
449
|
.command('worktree')
|
|
487
450
|
.description('Manage git worktrees for feature isolation');
|
|
@@ -493,10 +456,6 @@ worktreeCommand
|
|
|
493
456
|
.option('--json', 'Output as JSON (always JSON — accepted so the WorktreeCreate hook can call setup and provision uniformly)')
|
|
494
457
|
.action((feature, options) => worktreeSetupCommand(feature, options));
|
|
495
458
|
|
|
496
|
-
// Task isolation — the tree `claude -w`, EnterWorktree and Agent
|
|
497
|
-
// isolation:"worktree" ask for when the name is NOT a feature. Same infra as
|
|
498
|
-
// setup (junctions, port block, git-invisible manifest, primary-root landing),
|
|
499
|
-
// no feature identity. The WorktreeCreate hook is its main caller.
|
|
500
459
|
worktreeCommand
|
|
501
460
|
.command('provision <name>')
|
|
502
461
|
.description('Create a task-isolation worktree at worktrees/{name}/ on branch morph-task/{name} — full morph infra, no feature identity')
|
|
@@ -511,10 +470,8 @@ worktreeCommand
|
|
|
511
470
|
.option('--all', 'Link all shared dirs, not just node_modules')
|
|
512
471
|
.action((options) => worktreeLinkCommand(options));
|
|
513
472
|
|
|
514
|
-
//
|
|
515
|
-
//
|
|
516
|
-
// root's .claude/ and .morph/framework/, so nothing in this repo (message, doc,
|
|
517
|
-
// or skill) may point at it; they all point here.
|
|
473
|
+
// Raw `git worktree remove` follows the infra junctions and empties the primary root's .claude/
|
|
474
|
+
// and .morph/framework/: nothing in this repo may point at it, only at this command.
|
|
518
475
|
worktreeCommand
|
|
519
476
|
.command('remove [feature]')
|
|
520
477
|
.description('Safely tear down a worktree (drops infra junctions first, PROVE-or-DECLINE) — does NOT close the feature; that is `finish`')
|
|
@@ -525,9 +482,6 @@ worktreeCommand
|
|
|
525
482
|
.option('--json', 'Output as JSON (always JSON)')
|
|
526
483
|
.action((feature, options) => worktreeRemoveCommand(feature, options));
|
|
527
484
|
|
|
528
|
-
// Sub-agent trees (`agent-<hex>` on `morph-task/agent-<hex>`) outlive the agent: nothing
|
|
529
|
-
// tells the harness the agent is done with its worktree. The reaper removes only what it can prove
|
|
530
|
-
// is finished and lost-proof; the rest is listed with the reason.
|
|
531
485
|
worktreeCommand
|
|
532
486
|
.command('reap')
|
|
533
487
|
.description('Remove the worktrees and branches of sub-agents that stopped clean (nothing uncommitted, no commit only they hold); everything else is listed with the reason and left alone')
|
|
@@ -542,11 +496,6 @@ worktreeCommand
|
|
|
542
496
|
.option('--json', 'Output as JSON')
|
|
543
497
|
.action((options) => worktreeListCommand(options));
|
|
544
498
|
|
|
545
|
-
// ─── Branch housekeeping ──────────────────────────────────────────────────
|
|
546
|
-
// `git branch --merged` cannot see a squash-merge, so the only command left for
|
|
547
|
-
// a squash-merged branch is `git branch -D` — indistinguishable from discarding
|
|
548
|
-
// real work. `prune` makes the distinction itself and deletes only what it
|
|
549
|
-
// proved is already integrated.
|
|
550
499
|
const branchCommand = program
|
|
551
500
|
.command('branch')
|
|
552
501
|
.description('Local branch housekeeping');
|
|
@@ -559,7 +508,6 @@ branchCommand
|
|
|
559
508
|
.option('--json', 'Output as JSON')
|
|
560
509
|
.action((options) => branchPruneCommand(options));
|
|
561
510
|
|
|
562
|
-
// ─── Worktree env (shell-loadable port block) ─────────────────────────────
|
|
563
511
|
program
|
|
564
512
|
.command('env [feature]')
|
|
565
513
|
.description('Print the worktree\'s dedicated environment (port block + COMPOSE_PROJECT_NAME), shell-loadable: eval "$(morph-spec env)" outside Claude Code; feature defaults to the morph/{f} or morph-task/{n} branch of cwd')
|
|
@@ -567,14 +515,12 @@ program
|
|
|
567
515
|
.option('--powershell', 'Emit $env:K="V" lines instead of POSIX exports')
|
|
568
516
|
.action((feature, options) => envCommand(feature, options));
|
|
569
517
|
|
|
570
|
-
// ─── Fleet ────────────────────────────────────────────────────────────────
|
|
571
518
|
program
|
|
572
519
|
.command('fleet')
|
|
573
520
|
.description('Fleet view — every active feature across primary root and worktrees (phase, gates, tasks, ports, handoff, activity)')
|
|
574
521
|
.option('--json', 'Output as JSON')
|
|
575
522
|
.action((options) => fleetCommand(options));
|
|
576
523
|
|
|
577
|
-
// ─── Claims (advisory feature ownership) ──────────────────────────────────
|
|
578
524
|
program
|
|
579
525
|
.command('claim [feature]')
|
|
580
526
|
.description('claim [feature] acquires it (moves this tree\'s previous claim in the same step); no args shows the board (claims are advisory warnings, never locks)')
|
|
@@ -584,7 +530,6 @@ program
|
|
|
584
530
|
.option('--json', 'Output as JSON')
|
|
585
531
|
.action((feature, options) => claimCommand(feature, options));
|
|
586
532
|
|
|
587
|
-
// ─── Standards search (server-side, R2 token cut) ─────────────────────────
|
|
588
533
|
program
|
|
589
534
|
.command('standards')
|
|
590
535
|
.description('Search STANDARDS.json server-side (top 3, digest + anchors) or print one section, instead of reading the whole registry. Bare: categories + counts')
|
|
@@ -595,7 +540,6 @@ program
|
|
|
595
540
|
.option('--json', 'Output as JSON')
|
|
596
541
|
.action((options) => standardsCommand(options));
|
|
597
542
|
|
|
598
|
-
// ─── Sub-agent report protocol ────────────────────────────────────────────
|
|
599
543
|
program
|
|
600
544
|
.command('report-check <feature> [slices...]')
|
|
601
545
|
.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')
|
|
@@ -624,7 +568,6 @@ program
|
|
|
624
568
|
.option('--json', 'Output as JSON')
|
|
625
569
|
.action((feature, options) => stackScanCommand(feature, options));
|
|
626
570
|
|
|
627
|
-
// ─── Dashboard ────────────────────────────────────────────────────────────
|
|
628
571
|
program
|
|
629
572
|
.command('dashboard')
|
|
630
573
|
.description('Open the morph-spec inspector dashboard')
|
|
@@ -632,7 +575,6 @@ program
|
|
|
632
575
|
.option('--no-open', 'Don\'t auto-open browser')
|
|
633
576
|
.action(dashboardCommand);
|
|
634
577
|
|
|
635
|
-
// ─── Observability ────────────────────────────────────────────────────────
|
|
636
578
|
program
|
|
637
579
|
.command('telemetry')
|
|
638
580
|
.description('Summarize the harness execution path from .morph/logs/events.jsonl (skills, personas, standards read, tool mix, prompts)')
|
package/bin/validate.js
CHANGED
|
@@ -1,26 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Validation CLI
|
|
5
|
-
*
|
|
6
|
-
* Runs validators for the current project stack (detected from .morph/config/config.json).
|
|
7
|
-
*
|
|
8
|
-
* .NET stacks: packages
|
|
9
|
-
* Next.js stack: next-components
|
|
10
|
-
*
|
|
11
|
-
* Usage:
|
|
12
|
-
* morph-spec validate [options]
|
|
13
|
-
* morph-spec validate all
|
|
14
|
-
* morph-spec validate next-components (Next.js projects)
|
|
15
|
-
* morph-spec validate packages (.NET projects)
|
|
16
|
-
*
|
|
17
|
-
* MORPH-SPEC 3.0
|
|
18
|
-
*/
|
|
19
|
-
|
|
20
3
|
import chalk from 'chalk';
|
|
21
4
|
import { getStackProfile } from '../src/lib/stack/stack-profile.js';
|
|
22
5
|
|
|
23
|
-
/** The validators of the current stack: .NET → packages, Next.js → next-components. */
|
|
24
6
|
async function buildValidators(stack) {
|
|
25
7
|
const validators = {};
|
|
26
8
|
|
|
@@ -49,9 +31,6 @@ async function buildValidators(stack) {
|
|
|
49
31
|
return validators;
|
|
50
32
|
}
|
|
51
33
|
|
|
52
|
-
/**
|
|
53
|
-
* Main validation command
|
|
54
|
-
*/
|
|
55
34
|
export async function validateCommand(args = []) {
|
|
56
35
|
const validatorName = args[0] || 'all';
|
|
57
36
|
const options = parseOptions(args);
|
|
@@ -79,9 +58,6 @@ export async function validateCommand(args = []) {
|
|
|
79
58
|
}
|
|
80
59
|
}
|
|
81
60
|
|
|
82
|
-
/**
|
|
83
|
-
* Run all validators
|
|
84
|
-
*/
|
|
85
61
|
async function runAllValidators(VALIDATORS, options) {
|
|
86
62
|
const results = {};
|
|
87
63
|
let totalErrors = 0;
|
|
@@ -101,12 +77,10 @@ async function runAllValidators(VALIDATORS, options) {
|
|
|
101
77
|
|
|
102
78
|
results[name] = result;
|
|
103
79
|
|
|
104
|
-
// Count errors/warnings
|
|
105
80
|
if (result.errors !== undefined) {
|
|
106
81
|
totalErrors += result.errors;
|
|
107
82
|
totalWarnings += result.warnings || 0;
|
|
108
83
|
} else if (result.results) {
|
|
109
|
-
// Count issues in results array
|
|
110
84
|
const issues = result.results.flatMap(r => r.issues || []);
|
|
111
85
|
totalErrors += issues.filter(i => i.level === 'error').length;
|
|
112
86
|
totalWarnings += issues.filter(i => i.level === 'warning').length;
|
|
@@ -118,7 +92,6 @@ async function runAllValidators(VALIDATORS, options) {
|
|
|
118
92
|
}
|
|
119
93
|
}
|
|
120
94
|
|
|
121
|
-
// Summary
|
|
122
95
|
console.log(chalk.bold.cyan('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
|
|
123
96
|
console.log(chalk.bold('📊 Validation Summary\n'));
|
|
124
97
|
|
|
@@ -135,15 +108,11 @@ async function runAllValidators(VALIDATORS, options) {
|
|
|
135
108
|
|
|
136
109
|
console.log('');
|
|
137
110
|
|
|
138
|
-
// Exit with error code if errors found
|
|
139
111
|
if (totalErrors > 0 && !options.noFail) {
|
|
140
112
|
process.exit(1);
|
|
141
113
|
}
|
|
142
114
|
}
|
|
143
115
|
|
|
144
|
-
/**
|
|
145
|
-
* Run single validator
|
|
146
|
-
*/
|
|
147
116
|
async function runValidator(VALIDATORS, name, options) {
|
|
148
117
|
const validator = VALIDATORS[name];
|
|
149
118
|
|
|
@@ -152,7 +121,7 @@ async function runValidator(VALIDATORS, name, options) {
|
|
|
152
121
|
|
|
153
122
|
try {
|
|
154
123
|
const result = await validator.run('.', {
|
|
155
|
-
verbose: true,
|
|
124
|
+
verbose: true,
|
|
156
125
|
autoFix: options.autoFix
|
|
157
126
|
});
|
|
158
127
|
|
|
@@ -174,9 +143,6 @@ async function runValidator(VALIDATORS, name, options) {
|
|
|
174
143
|
}
|
|
175
144
|
}
|
|
176
145
|
|
|
177
|
-
/**
|
|
178
|
-
* Parse command-line options
|
|
179
|
-
*/
|
|
180
146
|
function parseOptions(args) {
|
|
181
147
|
const options = {
|
|
182
148
|
verbose: false,
|
|
@@ -197,9 +163,6 @@ function parseOptions(args) {
|
|
|
197
163
|
return options;
|
|
198
164
|
}
|
|
199
165
|
|
|
200
|
-
/**
|
|
201
|
-
* Show help
|
|
202
|
-
*/
|
|
203
166
|
export function showValidateHelp() {
|
|
204
167
|
console.log(`
|
|
205
168
|
${chalk.bold.cyan('morph-spec validate')} - Run project validations
|
|
@@ -234,7 +197,6 @@ ${chalk.bold('INTEGRATION')}
|
|
|
234
197
|
`);
|
|
235
198
|
}
|
|
236
199
|
|
|
237
|
-
// Run if called directly
|
|
238
200
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
239
201
|
const args = process.argv.slice(2);
|
|
240
202
|
|
package/claude-plugin.json
CHANGED
package/docs/CHEATSHEET.md
CHANGED
package/docs/QUICKSTART.md
CHANGED
package/framework/CLAUDE.md
CHANGED
|
@@ -39,7 +39,7 @@ Prefixo `morph-spec`; flags e porquês em `.morph/framework/CLI.md` (um `###` po
|
|
|
39
39
|
|
|
40
40
|
## Slash commands
|
|
41
41
|
|
|
42
|
-
`/morph-
|
|
42
|
+
`/morph-plan {f}` (plano), `/morph-apply {f}` (execução + Gate 3), `/morph-hotfix {f}`, `/morph-status [f]`.
|
|
43
43
|
|
|
44
44
|
## Personas (em `.claude/agents/`)
|
|
45
45
|
|
package/framework/MORPH.md
CHANGED
|
@@ -199,4 +199,4 @@ Relatório ausente não prova que o agente falhou, e relatório presente não pr
|
|
|
199
199
|
|
|
200
200
|
**Skills core** (`.claude/skills/{nome}/SKILL.md`, invocadas no momento indicado na descrição de cada uma): `morph-plan` (entrada: roteia, varre, entrevista, `plan.md`, gate do plano) · `morph-apply` (fatias → verify → review) · `morph-uiux` · `morph-review` · `morph-hotfix` · `morph-standards` · `morph-media` · `morph-machine`.
|
|
201
201
|
|
|
202
|
-
`/morph-
|
|
202
|
+
`/morph-plan` invoca a skill direto; `/morph-apply` e `/morph-hotfix` são atalhos da skill homônima. Desvio do passo a passo vai justificado no relatório.
|
package/framework/agents.json
CHANGED
|
@@ -242,6 +242,8 @@
|
|
|
242
242
|
],
|
|
243
243
|
"standards": [
|
|
244
244
|
"frontend-design-system-naming",
|
|
245
|
+
"frontend-design-system-art-direction",
|
|
246
|
+
"frontend-design-system-premium-finish",
|
|
245
247
|
"frontend-design-system-animations",
|
|
246
248
|
"frontend-nextjs-motion-patterns",
|
|
247
249
|
"architecture-code-comments",
|
|
@@ -251,7 +253,6 @@
|
|
|
251
253
|
"marketing-site": {
|
|
252
254
|
"when": "site de marketing: landing page, institucional, campanha — narrativa, conversão, movimento e SEO",
|
|
253
255
|
"standards": [
|
|
254
|
-
"frontend-design-system-premium-finish",
|
|
255
256
|
"frontend-design-system-ai-image-generation",
|
|
256
257
|
"frontend-design-system-ai-video-generation",
|
|
257
258
|
"frontend-scroll-driven-frame-scrub",
|
|
@@ -271,6 +272,13 @@
|
|
|
271
272
|
"frontend-admin-app-feedback",
|
|
272
273
|
"frontend-admin-app-page-structure"
|
|
273
274
|
]
|
|
275
|
+
},
|
|
276
|
+
"brand-moment": {
|
|
277
|
+
"when": "momento de marca dentro do produto: login e auth, onboarding, primeira tela, estado vazio de destaque, sucesso, vitrine — direção, cena e movimento",
|
|
278
|
+
"standards": [
|
|
279
|
+
"frontend-gsap-core",
|
|
280
|
+
"frontend-gsap-scrolltrigger"
|
|
281
|
+
]
|
|
274
282
|
}
|
|
275
283
|
},
|
|
276
284
|
"mcp": [
|
|
@@ -280,10 +288,10 @@
|
|
|
280
288
|
"playwright",
|
|
281
289
|
"graphify"
|
|
282
290
|
],
|
|
283
|
-
"model": "
|
|
291
|
+
"model": "opus",
|
|
284
292
|
"maxTurns": 120,
|
|
285
|
-
"effort": "
|
|
286
|
-
"persona": "Você desenha sistemas
|
|
293
|
+
"effort": "high",
|
|
294
|
+
"persona": "Você desenha sistemas E telas que alguém lembra. As duas réguas valem juntas: a de sistema (tokens de cor, espaço e tipografia, componentes reutilizáveis, estados default/hover/focus/disabled/loading/error, WCAG AA) e a estética, que é o que separa um design correto de um design aprovado. DIREÇÃO ANTES DE COMPONENTE: antes de qualquer componente, escreva em `1-design/direcao.md` o conceito em uma frase, a metáfora visual, o que torna a tela memorável e o que ela NÃO pode parecer (template shadcn cru, card branco centralizado, lista de ícones genérica). Tela nova ou momento de marca: explore 2 ou 3 direções distintas, recomende uma e justifique — o standard `frontend-design-system-art-direction` é a régua. SKILLS: carregue `frontend-design:frontend-design` sempre; `high-end-visual-design` em momento de marca; `redesign-existing-projects` em tela existente — cada uma só se instalada (a lista de skills da sessão diz); ausente, o standard de direção de arte é a régua e o relatório registra a ausência. CELULAR PRIMEIRO E NATIVO: folha inferior, zona do polegar, alvos de 44px, navegação que o polegar alcança; o celular é desenhado, nunca o desktop empilhado. MOVIMENTO COM INTENÇÃO: a ferramenta mais leve que entrega o efeito (CSS transition e `@keyframes` → animação por scroll em CSS → Framer Motion → GSAP com ScrollTrigger e timeline), orçamento de 60 fps, só `transform` e `opacity`, nada de layout thrash; `prefers-reduced-motion` tem versão estática digna, composta, nunca só a animação desligada. ACABAMENTO: camadas, luz (gradiente radial, trama discreta), vidro com moderação, sombra com a cor do tema, ritmo tipográfico (escala modular, tracking negativo no display), microinteração em foco, hover e envio. PROTÓTIPO E AUTOCRÍTICA: toda tela nova ou alterada vira `1-design/prototipos/{tela}.html` autossuficiente, com os tokens REAIS do projeto lidos do CSS de tokens (o `design-system.md` pode estar velho), desktop e celular lado a lado em moldura de aparelho, com controles animado, estático e pausar. Sirva por HTTP local (o Playwright MCP recusa `file:`), tire print em 1280 e em 390 (`{tela}-1280.png`, `{tela}-390.png` ao lado do HTML), avalie contra as duas réguas (hierarquia, contraste, ritmo, celular, \"parece template?\"), corrija e repita até passar; o relatório lista as rodadas e o que cada uma corrigiu. PROIBIDO: número ou dado inventado em tela real (cena ilustrativa não traz métrica), cópia de marca de terceiros, efeito que quebra contraste AA. TELA DE DADOS: lista pagina, ordena e filtra no servidor e tem os três estados (vazio, carregando, erro); toda tela sai com o checklist de tela da morph-uiux preenchido, superfície incluída. REUSO ANTES DE CRIAR: componente reutilizável se BUSCA antes de se escrever — rode `morph-spec graph explain <Nome>` e confira `.morph/context/design-system.md` (sem grafo: `grep -rn`); criar um novo exige justificativa em uma linha no relatório da fatia, a mesma regra que já vale para token de design. COMENTÁRIO E TESTE: nenhum comentário, mesmo com vizinho comentado: nome, tipo e teste explicam (pós-condição no nome do teste); só o porquê invisível, sem `///`/JSDoc, id de cenário/fatia ou banner; um teste por pós-condição, cenários do mesmo comportamento em tabela, nenhum teste que só fixa texto."
|
|
287
295
|
},
|
|
288
296
|
"infra-engineer": {
|
|
289
297
|
"title": "Infrastructure / Jobs Engineer",
|
|
@@ -9,6 +9,6 @@ allowed-tools: Read, Write, Edit, Bash, Glob, Grep, Agent, AskUserQuestion, Skil
|
|
|
9
9
|
Atalho: invoque `Skill(morph-apply)` com o nome da feature.
|
|
10
10
|
|
|
11
11
|
Pré-requisito: o gate do plano aprovado, com `.morph/features/{feature}/2-plan/plan.md` e
|
|
12
|
-
`2-plan/checks.json` (gravado por `morph-spec plan-check`). Faltando, rode `/morph-
|
|
12
|
+
`2-plan/checks.json` (gravado por `morph-spec plan-check`). Faltando, rode `/morph-plan {feature}`.
|
|
13
13
|
|
|
14
14
|
**Feature:** $ARGUMENTS
|
|
@@ -34,7 +34,7 @@ output completion (X/N outputs), slice progress (reports in `3-implement/reports
|
|
|
34
34
|
After running the CLI, summarize:
|
|
35
35
|
- Current phase and which gate (if any) is open
|
|
36
36
|
- Outstanding outputs for the current phase
|
|
37
|
-
- Recommended next slash command (`/morph-
|
|
37
|
+
- Recommended next slash command (`/morph-plan`, `/morph-apply`, or a gate approval)
|
|
38
38
|
|
|
39
39
|
---
|
|
40
40
|
|
package/framework/docs/CLI.md
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
**Exceção `hotfix`:** esse tipo nunca despacha (`morph-hotfix` §7); o Gate 3 exige só `4-review/verifier.md`, escrito pelo orquestrador, e a assinatura humana continua obrigatória via `--approver` (o backstop de `--mode auto` acima permanece recusando).
|
|
18
18
|
|
|
19
|
-
**No `uiux`, a assinatura `auto` é recusada (exit 1) onde o `gate-check uiux` pausaria pelo checklist de tela** — o mesmo predicado do `advance` (`uiuxChecklistPause`, em `risk-detector.js`), lido mesmo sem gate-check antes. Destravam: uma decisão gravada com `pause: false` (`gate-decision {f} uiux --pause false --reason …`, ou um gate-check que não pausou) e a assinatura humana (`--approver`); `--force` não. A decisão vale para o mockup que viu: ela grava `mockupsHash` (o `mockups.md` por conteúdo), e um mockup escrito ou mudado depois dela volta a ser conferido.
|
|
19
|
+
**No `uiux`, a assinatura `auto` é recusada (exit 1) onde o `gate-check uiux` pausaria pelo checklist de tela ou pelo protótipo** — o mesmo predicado do `advance` (`uiuxChecklistPause`, em `risk-detector.js`), lido mesmo sem gate-check antes. Destravam: uma decisão gravada com `pause: false` (`gate-decision {f} uiux --pause false --reason …`, ou um gate-check que não pausou) e a assinatura humana (`--approver`); `--force` não. A decisão vale para o mockup que viu: ela grava `mockupsHash` (o `mockups.md` por conteúdo), e um mockup escrito ou mudado depois dela volta a ser conferido.
|
|
20
20
|
|
|
21
21
|
**O hook state-sync.js** cobre o caminho manual: `AskUserQuestion` respondida com frase de aprovação (abaixo) → registra o gate no `feature.json` autoritativo com `approvedBy: "manual"`. **A feature é identificada pelo nome que a pergunta cita** — grava na árvore dona dela, nunca na "feature ativa" da sessão. Pergunta sem nome numa árvore com mais de uma feature: o hook **recusa gravar** e avisa — aprove por `morph-spec approve`.
|
|
22
22
|
|
|
@@ -42,7 +42,7 @@ Um stamp de `verification` com status `fail` (último `morph-spec verify` vermel
|
|
|
42
42
|
|
|
43
43
|
**Prova de mídia:** do MESMO relatório e pelo MESMO leitor, o `gate-check` grava `signals.mediaClaims = {section, featureGeneratesMedia}`. `featureGeneratesMedia` é determinístico do disco — existe ao menos uma fatia do `checks.json` cujo `standards` cita `ai-agents-modalities-image-gen`, `ai-agents-media-video` ou `ai-agents-media-pipeline` — pelo id de STANDARDS.json ou pelo caminho, com ou sem `framework/`/`standards/` na frente, porque uma grafia não prevista desarmaria o guardrail sem uma linha de erro (`featureGeneratesMedia`, função exportada de `gate-check.js`, é onde essa normalização mora e é testada). Nessa condição, relatório **sem** a seção `## Mídia gerada` **pausa o Gate 3**: as quatro afirmações de mídia (custo, revisão humana, marcação, hot path não bloqueado) não foram provadas (`framework/evals/review-checklist.md`, "Feature que gera mídia").
|
|
44
44
|
|
|
45
|
-
**Checklist de tela:** na `uiux` e no `review`, o `gate-check` grava `signals.screenChecklist` lido do `1-design/mockups.md` (`mockups`, `legacy`, `screens`, `problems`). Na **uiux**, checklist incompleto **pausa** nomeando a tela e o item, e um mockup sem nenhuma `## Tela:` é o problema "nenhuma tela declarada". No **review**, o que se cobra é o item **devido** — decidido, nem "não se aplica" nem a superfície (`uncovered`): cada um exige uma linha na seção `## Checklist de tela` do `verifier.md`, e a linha que o verificador marca como não verificável conta. Com item devido, relatório sem a seção ou com linha faltando (`section`, `uncovered`) **pausa** o Gate 3 (`evals/review-checklist.md`, "Contrato de tela"); tela toda "não se aplica" não deve nada e não pausa. **Mockup legado** — telas no formato antigo (`## S001: …`) e nenhuma `## Tela:`, o que o template anterior gerava — é **isento nas duas fases**, com a isenção à vista: o sinal grava `exempt: "checklist dispensado: mockup no formato antigo"` e a mesma razão aparece em "risk signals present". Mockup ausente não pausa. `screenChecklist` **não** é sobrescrevível por `--signals`.
|
|
45
|
+
**Checklist de tela:** na `uiux` e no `review`, o `gate-check` grava `signals.screenChecklist` lido do `1-design/mockups.md` (`mockups`, `legacy`, `screens`, `problems`). Na **uiux**, checklist incompleto **pausa** nomeando a tela e o item, e um mockup sem nenhuma `## Tela:` é o problema "nenhuma tela declarada". Com o checklist completo, cada tela ainda deve o **protótipo** (`prototypes`, só na uiux): a linha `**Protótipo:** 1-design/prototipos/<tela>.html` dentro da `## Tela:`, o HTML e os prints `<tela>-1280.png` e `<tela>-390.png` ao lado dele; faltando um, **pausa** nomeando a tela e o arquivo ("protótipo incompleto"), pelo mesmo predicado. No **review**, o que se cobra é o item **devido** — decidido, nem "não se aplica" nem a superfície (`uncovered`): cada um exige uma linha na seção `## Checklist de tela` do `verifier.md`, e a linha que o verificador marca como não verificável conta. Com item devido, relatório sem a seção ou com linha faltando (`section`, `uncovered`) **pausa** o Gate 3 (`evals/review-checklist.md`, "Contrato de tela"); tela toda "não se aplica" não deve nada e não pausa. **Mockup legado** — telas no formato antigo (`## S001: …`) e nenhuma `## Tela:`, o que o template anterior gerava — é **isento nas duas fases**, com a isenção à vista: o sinal grava `exempt: "checklist dispensado: mockup no formato antigo"` e a mesma razão aparece em "risk signals present". Mockup ausente não pausa. `screenChecklist` **não** é sobrescrevível por `--signals`.
|
|
46
46
|
|
|
47
47
|
**Por quê.** Fora do review a regra não vale (pausar o Gate 1/2 numa máquina sem docker travaria planejamento legítimo). Feature que não pina standard de mídia é **isenta automaticamente** — a regra não pede cerimônia de quem não gera mídia. `mediaClaims` **não** é sobrescrevível por `--signals`, pela mesma razão anti-spoof dos demais sinais de disco.
|
|
48
48
|
|
|
@@ -61,7 +61,7 @@ A tabela é a mesma régua que `shouldPauseGate` aplica e que o `gate-check` imp
|
|
|
61
61
|
| `e2eSkipClass` (derivada) | environment/requested/unknown | e2e pulou sem dispensa legítima (só `project`). Só no **ship** |
|
|
62
62
|
| `promptModel` | prompt/modelo tocado | Sem nó `evals` declarado, ou eval pulado neste verify. Só no **ship** |
|
|
63
63
|
| `mediaClaims` | seção ausente | Feature que gera mídia, relatório sem `## Mídia gerada`. Só no **ship** |
|
|
64
|
-
| `screenChecklist` | item em aberto | **uiux**: tela sem checklist completo,
|
|
64
|
+
| `screenChecklist` | item em aberto | **uiux**: tela sem checklist completo, nenhuma `## Tela:`, ou tela sem protótipo e prints 1280/390. **ship**: item decidido sem linha em `## Checklist de tela` |
|
|
65
65
|
| `planChecks` | ≠ `fresh` | `checks.json` ausente ou de outra versão do `plan.md`: rode `plan-check`. Só no **plano**; `approve`/`advance` automáticos recusam |
|
|
66
66
|
| `sliceCount` | > 12 | Plano grande demais para uma feature |
|
|
67
67
|
| `workType` | === 'hotfix' | Gate 3 pausa SEMPRE (ver "Gates por tipo de trabalho") |
|
|
@@ -268,7 +268,7 @@ Fail-open: uma poda que falha nunca derruba o comando. PROVE-or-DECLINE como o r
|
|
|
268
268
|
|
|
269
269
|
### claim
|
|
270
270
|
|
|
271
|
-
**`morph-spec claim [feature] [--release] [--list] [--all] [--json]`** — posse **advisory** de feature. Cada sessão reclama sua feature ativa automaticamente (hook SessionStart) e renova o heartbeat a cada tool call; o registro vive em `<git-common-dir>/morph-spec/claims.json`, compartilhado por todos os worktrees. **`morph-spec claim <feature>` (sem flags) ADQUIRE** — se esta árvore já tinha claim vivo em outra feature, ele é liberado no mesmo passo (o CLI reporta "movido de X para Y"); é o jeito de trocar de feature no meio da tarefa sem a dança de dois passos `--release` + reclamar. `--list` força a leitura sem adquirir mesmo passando uma feature. **Claims avisam, nunca bloqueiam** — mas se o SessionStart avisar que outra sessão tem claim vivo, **confirme antes de `finish`/`archive`/`delete`**: duas sessões na mesma feature já custaram
|
|
271
|
+
**`morph-spec claim [feature] [--release] [--list] [--all] [--json]`** — posse **advisory** de feature. Cada sessão reclama sua feature ativa automaticamente (hook SessionStart) e renova o heartbeat a cada tool call; o registro vive em `<git-common-dir>/morph-spec/claims.json`, compartilhado por todos os worktrees. **`morph-spec claim <feature>` (sem flags) ADQUIRE** — se esta árvore já tinha claim vivo em outra feature, ele é liberado no mesmo passo (o CLI reporta "movido de X para Y"); é o jeito de trocar de feature no meio da tarefa sem a dança de dois passos `--release` + reclamar. `--list` força a leitura sem adquirir mesmo passando uma feature. **Claims avisam, nunca bloqueiam** — mas se o SessionStart avisar que outra sessão tem claim vivo, **confirme antes de `finish`/`archive`/`delete`**: duas sessões na mesma feature já custaram o trabalho de uma fatia e um sub-agent (o worktree sumiu debaixo dele). Claim órfão de sessão morta: `morph-spec claim <f> --release`. **O board mostra só claims VIVOS** (dentro do TTL de 30 min): um claim morto não avisa mais nada, e deixá-lo listado transformava o quadro em ruído (features encerradas há 20h e 73h ainda aparecendo). `--all` mostra o registro inteiro; a contagem dos omitidos sai no rodapé, nunca em silêncio.
|
|
272
272
|
|
|
273
273
|
## Validação
|
|
274
274
|
|
|
@@ -735,7 +735,7 @@ Falhas do `--show` saem 1: id inexistente (`Standard "<id>" não existe.` com at
|
|
|
735
735
|
**`--dry-run` prevê sem tocar em nada.** Previsão e execução são o **mesmo percurso**, com os **mesmos filtros** e o **mesmo coletor de efeitos**: em modo normal cada verbo executa *e* registra, em dry apenas registra.
|
|
736
736
|
|
|
737
737
|
O relatório agrupa por natureza do efeito (apagar, criar diretório, copiar, escrever, mesclar, executar, índice do git) e **nomeia separadamente três grupos que ninguém adivinha da palavra "update"**:
|
|
738
|
-
- **apagados por inteiro antes da reinstalação** — `.claude/{commands,rules,skills,agents}` e `.morph/{framework/standards,framework/hooks,framework/schemas,framework/
|
|
738
|
+
- **apagados por inteiro antes da reinstalação** — `.claude/{commands,rules,skills,agents}` e `.morph/{framework/standards,framework/hooks,framework/schemas,framework/evals,config}`, com a contagem de arquivos que hoje moram em cada um;
|
|
739
739
|
- **fora do projeto** — `~/.claude/statusline.sh`, `~/.claude/statusline.py` e a mesclagem de `~/.claude/settings.json`;
|
|
740
740
|
- **dentro do pacote da CLI** — `generate-refs.js` escrevendo `framework/hooks/shared/phase-utils.js` do pacote, que num `npm link` de desenvolvimento é o próprio repositório do framework. Em dry roda a variante `--check`, que verifica e não escreve.
|
|
741
741
|
|
|
@@ -743,17 +743,6 @@ O `--dry-run` **passa por cima** da saída antecipada de "CLI desatualizada": bl
|
|
|
743
743
|
|
|
744
744
|
**Freio de major.** Um salto de **dois majors ou mais** é recusado sem `--force`, **antes de qualquer mutação** — recusar depois de mutar é meio-estado. A versão instalada vem de `.morph/.morphversion → morphVersion`, o mesmo registro que o `update` já lê; **nunca** de `config.json → frameworkVersion`, que o `update` escreve e jamais lê para decidir (medido: os dois divergem por um major inteiro num projeto real). Quando os dois discordam, a mensagem imprime **os dois** e diz qual decidiu — escolher em silêncio é acertar metade das vezes e nunca saber qual metade. `.morphversion` ausente ou ilegível é tratado como salto grande, com motivo próprio (`versão instalada indeterminável`) distinto do salto medido: "não sei quão velho isto é" é precisamente quando sobrescrever às cegas é mais perigoso. `--force` dispensa o freio e o relatório final **registra a dispensa**. `--dry-run` combinado com uma recusa **imprime o relatório**, com a recusa como primeiro item.
|
|
745
745
|
|
|
746
|
-
**Feature em voo no formato anterior.** Antes de qualquer mutação, o `update` varre `.morph/features/` da raiz e de cada worktree que o `git worktree list` conhece; uma feature não encerrada (`status` diferente de `completed`/`abandoned`) com `2-plan/tasks.json` ou `0-proposal/` e sem `2-plan/plan.md` é do formato que esta versão não conduz, e o `update` recusa (exit 1, nada escrito):
|
|
747
|
-
|
|
748
|
-
```
|
|
749
|
-
Recusado: N feature(s) em voo no formato anterior ao plan.md (proposal/spec/tasks.json), que esta versão não conduz:
|
|
750
|
-
- <feature> (raiz | <caminho da worktree>)
|
|
751
|
-
Termine cada uma na 8.47: `npx @polymorphism-tech/morph-spec@8.47 <comando>` (por exemplo `finish <feature> --pr`),
|
|
752
|
-
ou arquive sem integrar: `morph-spec archive <feature> --force` (o Gate 3 dela não foi aprovado). Depois rode o `update` de novo.
|
|
753
|
-
```
|
|
754
|
-
|
|
755
|
-
`--force` **não** dispensa esta recusa (o freio de major, sim): a CLI nova não sabe conduzir essas features. Feature em `.morph/archive/` não conta. `--dry-run` põe as mesmas linhas no topo da previsão. A mesma regra roda no `init --force` e no `setup-infra` (inclusive `--reinstall`), que sobrescrevem `.morph/` e `.claude/` sem passar pelo `update`: recusam com as mesmas linhas e saem 1. No retorno programático, `{ refused: true, reason: 'old-format-features', features }`.
|
|
756
|
-
|
|
757
746
|
**Por quê.** Não há travessia paralela — o resumo de uma execução real também sai do coletor, de modo que um ponto de emissão esquecido some das duas saídas ao mesmo tempo, em vez de mentir só no `--dry-run`.
|
|
758
747
|
|
|
759
748
|
## Grafo de codebase
|
|
@@ -810,7 +799,7 @@ O servidor MCP (`graphify-mcp`, 10 tools, todas aceitando `project_path`) está
|
|
|
810
799
|
|
|
811
800
|
### cost
|
|
812
801
|
|
|
813
|
-
**`morph-spec cost [feature] [--by phase] [--all-trees] [--json]`** — custo da execução a partir do mesmo `events.jsonl`: bytes de contexto lidos por tipo (`
|
|
802
|
+
**`morph-spec cost [feature] [--by phase] [--all-trees] [--json]`** — custo da execução a partir do mesmo `events.jsonl`: bytes de contexto lidos por tipo (`checklist`/`standard`/`skill`/`agents`/`plan-artifact`/`code` — a janela `offset`/`limit` que o Read trouxe, quando o evento a tem), dispatches + tamanho de prompt e mix de tools. Bytes são **proxy determinística** de custo de token; os tokens reais vêm à parte: `SessionUsage` (sessão principal) e `AgentUsage` (cada sub-agent, lido do transcript dele), somados **só pelo `delta`** de cada amostra — o total de topo é acumulado e se repete a cada Stop, e amostra antiga sem `delta` fica fora da soma e é contada como legada. `--all-trees` agrega **toda árvore git** com log, mais os logs que o `finish` guardou em `.git/morph-spec/finish-backup/` antes de desmontar a worktree, deduplicados por `eventId`.
|
|
814
803
|
|
|
815
804
|
### cost --metrics
|
|
816
805
|
|