@polymorphism-tech/morph-spec 8.47.0 → 9.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +51 -43
- package/README.md +39 -38
- package/bin/morph-spec.js +41 -113
- package/bin/validate.js +1 -147
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +41 -101
- package/framework/MORPH.md +95 -252
- package/framework/agents.json +86 -21
- package/framework/commands/morph-apply.md +5 -28
- package/framework/commands/morph-archive.md +1 -1
- package/framework/commands/morph-hotfix.md +8 -8
- package/framework/commands/morph-infra.md +1 -1
- package/framework/commands/morph-preflight.md +2 -3
- package/framework/commands/morph-status.md +4 -4
- package/framework/docs/CLI.md +574 -286
- package/framework/evals/review-checklist.md +82 -41
- package/framework/hooks/README.md +10 -11
- package/framework/hooks/claude-code/core/block-destructive-worktree-removal.js +6 -49
- package/framework/hooks/claude-code/core/block-raw-worktree-add.js +2 -35
- package/framework/hooks/claude-code/core/chain.js +4 -65
- package/framework/hooks/claude-code/core/comment-guard.js +3 -17
- package/framework/hooks/claude-code/core/denylist.json +33 -3
- package/framework/hooks/claude-code/core/enforce-phase-writes.js +15 -63
- package/framework/hooks/claude-code/core/gate-guard.js +9 -78
- package/framework/hooks/claude-code/core/graph-refresh-kick.js +3 -24
- package/framework/hooks/claude-code/core/heavy-gate.js +3 -21
- package/framework/hooks/claude-code/core/heavy-release.js +2 -13
- package/framework/hooks/claude-code/core/loop-detect.js +2 -31
- package/framework/hooks/claude-code/core/pre-bash-denylist.js +36 -2
- package/framework/hooks/claude-code/core/protect-spec-files.js +25 -297
- package/framework/hooks/claude-code/core/state-sync.js +15 -85
- package/framework/hooks/claude-code/core/telemetry-log.js +15 -96
- package/framework/hooks/claude-code/core/validate-completion.js +37 -147
- package/framework/hooks/claude-code/core/warn-bash-source-write.js +23 -0
- package/framework/hooks/claude-code/core/worktree-context.js +15 -114
- package/framework/hooks/claude-code/core/worktree-create.js +6 -70
- package/framework/hooks/claude-code/core/worktree-env-inject.js +5 -56
- package/framework/hooks/claude-code/core/worktree-remove.js +5 -31
- package/framework/hooks/claude-code/statusline.py +55 -41
- package/framework/hooks/package.json +3 -0
- package/framework/hooks/shared/activity-logger.js +9 -89
- package/framework/hooks/shared/agent-reap.js +2 -17
- package/framework/hooks/shared/build-check.js +11 -76
- package/framework/hooks/shared/claim-registry.js +9 -119
- package/framework/hooks/shared/command-tokens.js +168 -44
- package/framework/hooks/shared/comment-rules.js +5 -20
- package/framework/hooks/shared/comment-scanner.js +11 -43
- package/framework/hooks/shared/comment-stripper.js +11 -85
- package/framework/hooks/shared/e2e-check.js +0 -0
- package/framework/hooks/shared/errata.js +59 -0
- package/framework/hooks/shared/feature-locator.js +11 -95
- package/framework/hooks/shared/frontend-locations.js +4 -0
- package/framework/hooks/shared/gate-question.js +12 -0
- package/framework/hooks/shared/git-exclude.js +3 -20
- package/framework/hooks/shared/git-paths.js +8 -104
- package/framework/hooks/shared/graph-freshness.js +22 -166
- package/framework/hooks/shared/graph-refresh.js +21 -149
- package/framework/hooks/shared/heavy-command.js +4 -12
- package/framework/hooks/shared/hook-response.js +8 -83
- package/framework/hooks/shared/morph-cli.js +8 -52
- package/framework/hooks/shared/payload-utils.js +10 -132
- package/framework/hooks/shared/phase-utils.js +14 -72
- package/framework/hooks/shared/redact-secrets.js +4 -15
- package/framework/hooks/shared/reparse-scan.js +6 -66
- package/framework/hooks/shared/slice-progress.js +99 -0
- package/framework/hooks/shared/source-files.js +4 -17
- package/framework/hooks/shared/spawn-command.js +23 -0
- package/framework/hooks/shared/state-reader.js +51 -247
- package/framework/hooks/shared/state-writer.js +9 -54
- package/framework/hooks/shared/stdin-reader.js +1 -11
- package/framework/hooks/shared/telemetry-logger.js +7 -67
- package/framework/hooks/shared/transcript-usage.js +7 -29
- package/framework/hooks/shared/worktree-root.js +7 -29
- package/framework/mcp/registry.json +3 -4
- package/framework/phases.json +23 -39
- package/framework/rules/csharp-standards.md +1 -1
- package/framework/rules/frontend-standards.md +1 -0
- package/framework/rules/hangfire-standards.md +1 -1
- package/framework/rules/neon-standards.md +1 -1
- package/framework/schemas/config.schema.json +14 -9
- package/framework/schemas/feature.schema.json +15 -50
- package/framework/skills/README.md +3 -4
- package/framework/skills/core/create-umbraco-lp/SKILL.md +1 -1
- package/framework/skills/core/migrate-lp-to-umbraco/SKILL.md +1 -1
- package/framework/skills/core/morph-apply/SKILL.md +149 -222
- package/framework/skills/core/morph-hotfix/SKILL.md +33 -42
- package/framework/skills/core/morph-machine/SKILL.md +2 -2
- package/framework/skills/core/morph-media/SKILL.md +1 -1
- package/framework/skills/core/morph-plan/SKILL.md +137 -299
- package/framework/skills/core/morph-review/SKILL.md +111 -136
- package/framework/skills/core/morph-standards/SKILL.md +27 -39
- package/framework/skills/core/morph-uiux/SKILL.md +94 -152
- package/framework/standards/STANDARDS.json +109 -1219
- package/framework/standards/STANDARDS.meta.json +1319 -0
- package/framework/standards/ai-agents/agent-archetypes.md +2 -2
- package/framework/standards/ai-agents/agent-session.md +1 -1
- package/framework/standards/ai-agents/conversational-agent-with-phases.md +4 -4
- package/framework/standards/ai-agents/durable-workflows-hitl.md +3 -3
- package/framework/standards/ai-agents/evals-with-cache.md +1 -2
- package/framework/standards/ai-agents/guardrails.md +1 -1
- package/framework/standards/ai-agents/multi-agent-patterns.md +2 -2
- package/framework/standards/ai-agents/observability-patterns.md +1 -1
- package/framework/standards/ai-agents/production.md +1 -1
- package/framework/standards/ai-agents/prompt-sources.md +2 -2
- package/framework/standards/ai-agents/providers/model-registry.md +1 -1
- package/framework/standards/ai-agents/rag-custom-pgvector.md +2 -2
- package/framework/standards/ai-agents/setup.md +3 -3
- package/framework/standards/ai-agents/sweet-spot.md +2 -2
- package/framework/standards/ai-agents/tool-adapters.md +0 -2
- package/framework/standards/ai-agents/vector-data-extensions.md +4 -4
- package/framework/standards/ai-agents/workflows.md +1 -1
- package/framework/standards/architecture/code-comments.md +7 -7
- package/framework/standards/architecture/vertical-slice/vertical-slice.md +1 -1
- package/framework/standards/backend/api/validation.md +1 -1
- package/framework/standards/backend/dotnet/vsa-handler-patterns.md +5 -5
- package/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +1 -1
- package/framework/standards/backend/integrations/neon-auth/neon-auth.md +2 -2
- package/framework/standards/data/nosql/cache/redis.md +1 -1
- package/framework/standards/data/nosql/cosmos-db.md +3 -3
- package/framework/standards/frontend/admin-app/forms.md +1 -1
- package/framework/standards/frontend/design-system/art-direction.md +88 -0
- package/framework/standards/frontend/design-system/premium-finish.md +77 -2
- package/framework/standards/infrastructure/neon/neon-pgvector.md +5 -5
- package/framework/standards/integration/mcp/mcp-tools.md +7 -7
- package/framework/templates/CLAUDE.md.core.template +3 -3
- package/framework/templates/README.md +2 -3
- package/framework/templates/REGISTRY.json +15 -179
- package/framework/templates/docs/plan.md +72 -0
- package/framework/templates/docs/ui-mockups.md +4 -0
- package/framework/templates/dotnet/ai-kit/README.md +1 -9
- package/framework/templates/dotnet/ai-kit/tests/Morph.AiKit.Tests/Morph.AiKit.Tests.csproj +0 -10
- package/framework/templates/meta-prompts/squad-leaders/backend-squad.md +1 -1
- package/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +1 -1
- package/framework/templates/meta-prompts/squad-leaders/squad-leader.md +1 -1
- package/framework/templates/meta-prompts/validators/pre-commit-validator.md +3 -4
- package/package.json +1 -1
- package/src/commands/context/context-refresh.js +0 -16
- package/src/commands/dashboard/dashboard.js +2 -8
- package/src/commands/e2e/e2e.js +18 -105
- package/src/commands/graph/affected.js +0 -14
- package/src/commands/graph/build.js +11 -50
- package/src/commands/graph/explain.js +0 -16
- package/src/commands/graph/status.js +1 -12
- package/src/commands/mcp/mcp-setup.js +4 -62
- package/src/commands/observability/cost.js +17 -111
- package/src/commands/observability/telemetry.js +1 -14
- package/src/commands/project/branch.js +4 -45
- package/src/commands/project/claim.js +4 -48
- package/src/commands/project/doctor-procs.js +1 -1
- package/src/commands/project/doctor.js +53 -307
- package/src/commands/project/env.js +1 -27
- package/src/commands/project/fleet.js +6 -35
- package/src/commands/project/heavy.js +3 -3
- package/src/commands/project/init.js +8 -68
- package/src/commands/project/install-plugin-cmd.js +0 -1
- package/src/commands/project/setup-infra-cmd.js +2 -1
- package/src/commands/project/stack-scan.js +58 -0
- package/src/commands/project/standards.js +65 -72
- package/src/commands/project/status.js +28 -121
- package/src/commands/project/update.js +31 -223
- package/src/commands/project/worktree.js +109 -883
- package/src/commands/scaffold/scaffold.js +0 -25
- package/src/commands/state/advance.js +65 -120
- package/src/commands/state/approve.js +87 -229
- package/src/commands/state/archive.js +23 -139
- package/src/commands/state/auto-approval.js +65 -0
- package/src/commands/state/create.js +49 -109
- package/src/commands/state/delete.js +11 -63
- package/src/commands/state/finish.js +105 -494
- package/src/commands/state/gate-check.js +74 -183
- package/src/commands/state/gate-decision.js +8 -42
- package/src/commands/state/handoff.js +4 -31
- package/src/commands/state/list.js +21 -91
- package/src/commands/state/report-check.js +134 -338
- package/src/commands/state/retype.js +12 -28
- package/src/commands/validation/index.js +0 -3
- package/src/commands/validation/mutate.js +79 -19
- package/src/commands/validation/plan-check.js +81 -0
- package/src/commands/validation/validate-feature.js +52 -216
- package/src/commands/validation/verify.js +45 -160
- package/src/core/paths/output-schema.js +9 -155
- package/src/core/state/feature-identity.js +1 -25
- package/src/core/state/gate-order.js +2 -30
- package/src/core/state/lifecycle-audit.js +8 -100
- package/src/core/state/state-manager.js +32 -395
- package/src/core/templates/template-registry.js +2 -97
- package/src/core/templates/template-renderer.js +13 -93
- package/src/core/templates/template-seed.js +21 -0
- package/src/core/work-types.js +10 -45
- package/src/dashboard/app/App.jsx +1 -8
- package/src/dashboard/app/components/ActivityFeed.jsx +2 -8
- package/src/dashboard/app/components/CommandPalette.jsx +4 -11
- package/src/dashboard/app/components/DetailPanel.jsx +1 -5
- package/src/dashboard/app/components/EntityLink.jsx +0 -12
- package/src/dashboard/app/components/ErrorBoundary.jsx +1 -8
- package/src/dashboard/app/components/KnowledgeMarkdown.jsx +0 -11
- package/src/dashboard/app/components/Markdown.jsx +0 -9
- package/src/dashboard/app/components/PhaseRail.jsx +0 -11
- package/src/dashboard/app/components/SearchFilter.jsx +0 -4
- package/src/dashboard/app/components/Sidebar.jsx +0 -5
- package/src/dashboard/app/hooks/useMorphQuery.js +1 -11
- package/src/dashboard/app/hooks/usePref.js +1 -5
- package/src/dashboard/app/lib/format.js +0 -2
- package/src/dashboard/app/lib/phases.js +3 -9
- package/src/dashboard/app/lib/project.js +0 -12
- package/src/dashboard/app/pages/Activity.jsx +1 -1
- package/src/dashboard/app/pages/AgentMap.jsx +1 -8
- package/src/dashboard/app/pages/FeatureDetail.jsx +139 -133
- package/src/dashboard/app/pages/Features.jsx +9 -16
- package/src/dashboard/app/pages/Guide.jsx +2 -3
- package/src/dashboard/app/pages/HookInspector.jsx +2 -23
- package/src/dashboard/app/pages/PhasePipeline.jsx +3 -7
- package/src/dashboard/app/pages/Portfolio.jsx +0 -1
- package/src/dashboard/app/pages/RulesMap.jsx +1 -16
- package/src/dashboard/app/pages/SkillsLibrary.jsx +1 -16
- package/src/dashboard/app/pages/Standards.jsx +2 -17
- package/src/dashboard/scanner/activity-scanner.js +14 -83
- package/src/dashboard/scanner/agents-scanner.js +1 -23
- package/src/dashboard/scanner/docs-scanner.js +1 -7
- package/src/dashboard/scanner/feature-status.js +2 -5
- package/src/dashboard/scanner/features-scanner.js +92 -113
- package/src/dashboard/scanner/hooks-scanner.js +5 -28
- package/src/dashboard/scanner/index.js +0 -4
- package/src/dashboard/scanner/portfolio.js +5 -29
- package/src/dashboard/scanner/project-api.js +8 -54
- package/src/dashboard/scanner/rules-scanner.js +1 -2
- package/src/dashboard/scanner/skills-scanner.js +2 -12
- package/src/dashboard/scanner/standards-scanner.js +4 -7
- package/src/dashboard/vite-plugin-morph-data.js +5 -19
- package/src/lib/ai/ai-checks.js +7 -52
- package/src/lib/ai/ai-project-scan.js +14 -108
- package/src/lib/ai/code-audit.js +7 -63
- package/src/lib/ai/pin-drift.js +8 -51
- package/src/lib/ai/registry-audit.js +11 -90
- package/src/lib/ci/ci-verify.js +14 -13
- package/src/lib/ci/github-ci.js +9 -37
- package/src/lib/ci/workflow-scaffold.js +2 -10
- package/src/lib/detectors/claude-config-detector.js +13 -74
- package/src/lib/detectors/index.js +8 -59
- package/src/lib/e2e/compose-env.js +5 -66
- package/src/lib/e2e/stack-teardown.js +6 -40
- package/src/lib/generators/architecture-scanner.js +18 -156
- package/src/lib/generators/handoff-generator.js +37 -112
- package/src/lib/generators/scaffold-generator.js +5 -101
- package/src/lib/generators/settings-generator.js +11 -122
- package/src/lib/git/branch-classifier.js +11 -84
- package/src/lib/git/default-branch.js +14 -169
- package/src/lib/git/evidence-staleness.js +2 -1
- package/src/lib/git/gh.js +2 -17
- package/src/lib/git/pending-prs.js +6 -37
- package/src/lib/git/pr-files.js +3 -28
- package/src/lib/git/pr-index.js +3 -34
- package/src/lib/git/tree-fingerprint.js +17 -17
- package/src/lib/git/tree-state.js +6 -33
- package/src/lib/graph/god-nodes.js +2 -22
- package/src/lib/graph/graph-health.js +3 -24
- package/src/lib/graph/graph-loader.js +5 -56
- package/src/lib/graph/graphify-runtime.js +7 -37
- package/src/lib/graph/graphifyignore.js +8 -74
- package/src/lib/graph/sanitize.js +16 -136
- package/src/lib/heavy/cleanup.js +2 -6
- package/src/lib/installers/effects.js +8 -93
- package/src/lib/installers/mcp-installer.js +9 -169
- package/src/lib/installers/memory-installer.js +8 -33
- package/src/lib/installers/templates-reconcile.js +5 -60
- package/src/lib/mutation/commands.js +3 -2
- package/src/lib/mutation/dotnet-introspection.js +281 -0
- package/src/lib/mutation/plan.js +14 -6
- package/src/lib/mutation/runner.js +1 -1
- package/src/lib/mutation/subset.js +47 -13
- package/src/lib/plan/artifact-vocabulary.js +40 -0
- package/src/lib/plan/checks.js +208 -0
- package/src/lib/plan/plan-parser.js +204 -0
- package/src/lib/plan/plan-template.js +18 -0
- package/src/lib/projects/registry.js +7 -44
- package/src/lib/review-reports.js +204 -0
- package/src/lib/risk-detector.js +131 -274
- package/src/lib/specs/adr-index.js +38 -85
- package/src/lib/specs/design-seed.js +18 -0
- package/src/lib/specs/frontmatter.js +31 -0
- package/src/lib/specs/gfm-table.js +11 -0
- package/src/lib/specs/revocations.js +31 -102
- package/src/lib/specs/screen-checklist.js +56 -132
- package/src/lib/stack/dotnet-build-ignores.js +43 -0
- package/src/lib/stack/stack-profile.js +1 -28
- package/src/lib/stack/stack-scan.js +260 -0
- package/src/lib/stack-filter.js +4 -27
- package/src/lib/standards/registry.js +37 -0
- package/src/lib/standards/sections.js +47 -0
- package/src/lib/standards/verified-against.js +19 -191
- package/src/lib/tasks/eval-node.js +23 -179
- package/src/lib/tasks/linux-runner.js +18 -142
- package/src/lib/tasks/test-nodes.js +43 -313
- package/src/lib/tasks/test-runner.js +107 -447
- package/src/lib/telemetry/metrics.js +13 -103
- package/src/lib/telemetry/telemetry-reader.js +13 -238
- package/src/lib/telemetry/verify-event.js +4 -34
- package/src/lib/validators/code-budget/code-budget-validator.js +4 -44
- package/src/lib/validators/code-budget/index.js +0 -7
- package/src/lib/validators/contracts/contract-compliance-validator.js +4 -26
- package/src/lib/validators/contracts/index.js +0 -6
- package/src/lib/validators/nextjs/index.js +0 -5
- package/src/lib/validators/nextjs/next-component-validator.js +4 -81
- package/src/lib/validators/packages/index.js +0 -6
- package/src/lib/validators/packages/package-validator.js +6 -56
- package/src/lib/validators/reuse/index.js +0 -8
- package/src/lib/validators/reuse/reuse-validator.js +24 -137
- package/src/lib/validators/reuse/symbol-scanner.js +6 -62
- package/src/lib/validators/traceability-check.js +54 -156
- package/src/lib/validators/validation-runner.js +20 -125
- package/src/lib/validators/verify-runner.js +152 -575
- package/src/lib/work-type-detector.js +5 -67
- package/src/lib/worktree/docker-audit.js +17 -137
- package/src/lib/worktree/env-allocator.js +10 -98
- package/src/lib/worktree/feature-truth.js +12 -115
- package/src/lib/worktree/finish-backup.js +32 -242
- package/src/lib/worktree/fleet-scanner.js +31 -126
- package/src/lib/worktree/ignored-triage.js +15 -91
- package/src/lib/worktree/vscode-settings.js +2 -3
- package/src/lib/worktree/worktree-audit.js +21 -213
- package/src/lib/worktree/worktree-include.js +3 -5
- package/src/scripts/global-install.js +3 -9
- package/src/scripts/install-plugin.js +1 -13
- package/src/scripts/setup-infra.js +17 -138
- package/src/utils/agents-installer.js +92 -272
- package/src/utils/banner.js +4 -25
- package/src/utils/claude-md-injector.js +1 -37
- package/src/utils/claude-settings-manager.js +1 -87
- package/src/utils/file-copier.js +32 -90
- package/src/utils/hooks-installer.js +26 -296
- package/src/utils/skills-installer.js +4 -102
- package/src/utils/version-checker.js +4 -83
- package/framework/commands/morph-proposal.md +0 -57
- package/framework/evals/trace-schema.md +0 -67
- package/framework/hooks/claude-code/core/tasks-json-guard.js +0 -83
- package/framework/hooks/claude-code/core/trace-autogen.js +0 -277
- package/framework/hooks/git/pre-commit/specs.sh +0 -50
- package/framework/hooks/shared/tasks-validator.js +0 -111
- package/framework/rules/morph-task-tracking.md +0 -54
- package/framework/rules/morph-workflow.md +0 -244
- package/framework/schemas/tasks.schema.json +0 -79
- package/framework/skills/core/morph-brainstorming/SKILL.md +0 -161
- package/framework/skills/core/morph-implement/SKILL.md +0 -194
- package/framework/skills/core/morph-proposal/SKILL.md +0 -152
- package/framework/skills/core/morph-stack-scan/SKILL.md +0 -145
- package/framework/templates/docs/proposal.md +0 -192
- package/framework/templates/docs/spec.md +0 -57
- package/framework/templates/docs/ui-components.md +0 -52
- package/framework/templates/docs/ui-design-system.md +0 -76
- package/framework/templates/docs/ui-flows.md +0 -167
- package/framework/templates/examples/spec-examples.md +0 -91
- package/framework/templates/feature/decisions.md +0 -124
- package/framework/templates/feature/recap.md +0 -145
- package/framework/templates/tasks.template.json +0 -17
- package/src/commands/state/usecase.js +0 -143
- package/src/commands/tasks/dag.js +0 -181
- package/src/commands/utils/index.js +0 -3
- package/src/lib/agents/output-collector.js +0 -76
- package/src/lib/detectors/design-system-detector.js +0 -188
- package/src/lib/evaluator-report.js +0 -104
- package/src/lib/generators/design-system-generator.js +0 -508
- package/src/lib/specs/acervo-format.js +0 -70
- package/src/lib/specs/acervo-lifecycle.js +0 -264
- package/src/lib/specs/done-criteria-check.js +0 -200
- package/src/lib/specs/usecase-check.js +0 -301
- package/src/lib/specs/usecase-promoter.js +0 -301
- package/src/lib/specs/usecase-registry.js +0 -237
- package/src/lib/tasks/dispatch-planner.js +0 -319
- package/src/lib/tasks/dotnet-test-introspection.js +0 -632
- package/src/lib/tasks/mermaid-renderer.js +0 -132
- package/src/lib/tasks/task-classifier.js +0 -30
- package/src/lib/tasks/task-parser.js +0 -209
- package/src/lib/tasks/tasks-json-parser.js +0 -296
- package/src/lib/tasks/test-scope.js +0 -597
- package/src/utils/agent-id-mapper.js +0 -11
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `morph-spec env [feature] [--json|--posix|--powershell]` — print the
|
|
3
|
-
* dedicated environment of a worktree (port block + compose project) in a
|
|
4
|
-
* shell-loadable form.
|
|
5
|
-
*
|
|
6
|
-
* Inside Claude Code the `worktree-env-inject` hook applies this block to
|
|
7
|
-
* every dev-server / compose launcher automatically. This command is the same
|
|
8
|
-
* contract for everything OUTSIDE the harness: a human terminal
|
|
9
|
-
* (`eval "$(morph-spec env)"`), a CI step, a sub-agent running without hooks.
|
|
10
|
-
* It derives from `buildComposeEnv` — the function the `verify` e2e node and
|
|
11
|
-
* `e2e up` already use — so a shell and the stack can never disagree.
|
|
12
|
-
*
|
|
13
|
-
* Feature resolution: explicit argument, else the `morph/{f}` (or
|
|
14
|
-
* `morph-task/{n}`) branch of the cwd. Read-only: allocation is idempotent and
|
|
15
|
-
* never moves an existing block.
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
1
|
import { execFileSync } from 'child_process';
|
|
19
2
|
import { readFileSync } from 'fs';
|
|
20
3
|
import { join, resolve } from 'path';
|
|
@@ -49,14 +32,9 @@ function gitCommonDir(cwd) {
|
|
|
49
32
|
}
|
|
50
33
|
}
|
|
51
34
|
|
|
52
|
-
/** POSIX single-quote. */
|
|
53
35
|
const shq = (v) => `'${String(v).replace(/'/g, "'\\''")}'`;
|
|
54
36
|
|
|
55
|
-
/**
|
|
56
|
-
* Pure: the env map for a key, or `{ error }`.
|
|
57
|
-
* @param {string|null} featureArg
|
|
58
|
-
* @param {string} cwd
|
|
59
|
-
*/
|
|
37
|
+
/** The env map for a key, or `{ error }`. */
|
|
60
38
|
export function resolveWorktreeEnv(featureArg, cwd = process.cwd()) {
|
|
61
39
|
const key = featureArg || envKeyFromBranch(currentBranch(cwd));
|
|
62
40
|
if (!key) {
|
|
@@ -78,10 +56,6 @@ export function render(env, format) {
|
|
|
78
56
|
return entries.map(([k, v]) => `export ${k}=${shq(v)}`).join('\n');
|
|
79
57
|
}
|
|
80
58
|
|
|
81
|
-
/**
|
|
82
|
-
* @param {string|undefined} featureArg
|
|
83
|
-
* @param {{ json?: boolean, posix?: boolean, powershell?: boolean }} options
|
|
84
|
-
*/
|
|
85
59
|
export function envCommand(featureArg, options = {}) {
|
|
86
60
|
const result = resolveWorktreeEnv(featureArg || null, process.cwd());
|
|
87
61
|
if (result.error) {
|
|
@@ -1,22 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `morph-spec fleet [--json]` — the fleet view.
|
|
3
|
-
*
|
|
4
|
-
* One line per active feature across the primary root and every morph/*
|
|
5
|
-
* worktree: phase, pending gates, task progress, port block, handoff
|
|
6
|
-
* freshness, last commit and dirtiness. This is the terminal surface the
|
|
7
|
-
* operator scans between sessions ("what is each instance doing, what is
|
|
8
|
-
* waiting on me") — `worktree list` remains the lean per-worktree view.
|
|
9
|
-
*
|
|
10
|
-
* Read-only, always exits 0 (fail-open — an empty fleet is an answer).
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
1
|
import chalk from 'chalk';
|
|
14
2
|
import { scanFleet } from '../../lib/worktree/fleet-scanner.js';
|
|
15
3
|
import { claimAge } from '../../../framework/hooks/shared/claim-registry.js';
|
|
16
4
|
|
|
17
|
-
/**
|
|
18
|
-
* @param {{ json?: boolean, cwd?: string }} [options]
|
|
19
|
-
*/
|
|
20
5
|
export function fleetCommand(options = {}) {
|
|
21
6
|
const fleet = scanFleet(options.cwd || process.cwd());
|
|
22
7
|
|
|
@@ -32,22 +17,13 @@ export function fleetCommand(options = {}) {
|
|
|
32
17
|
|
|
33
18
|
const col = (s, w) => String(s ?? '-').padEnd(w);
|
|
34
19
|
|
|
35
|
-
/**
|
|
36
|
-
* The REMOTO cell. `-` means "unknown" (no origin, or the probe failed) —
|
|
37
|
-
* deliberately the same glyph as "nothing there", because both mean "do not
|
|
38
|
-
* trust the local view alone". `local` is the confident negative.
|
|
39
|
-
*/
|
|
20
|
+
/** `-` (unknown) shares the "nothing there" glyph on purpose: both mean "do not trust the local view alone". */
|
|
40
21
|
const remoteCell = (r) => {
|
|
41
22
|
if (!r) return '-';
|
|
42
23
|
if (r.pr) return `PR #${r.pr.number}${r.pr.state && r.pr.state !== 'OPEN' ? ` (${r.pr.state.toLowerCase()})` : ''}`;
|
|
43
24
|
return r.pushed ? 'pushed' : 'local';
|
|
44
25
|
};
|
|
45
26
|
|
|
46
|
-
/**
|
|
47
|
-
* The CLAIM cell — who is on this feature right now (B1). A stale claim is
|
|
48
|
-
* shown as stale, not hidden: "nobody here" and "somebody died here" are
|
|
49
|
-
* different facts for the operator.
|
|
50
|
-
*/
|
|
51
27
|
const claimCell = (c) => {
|
|
52
28
|
if (!c) return '-';
|
|
53
29
|
const age = claimAge(c);
|
|
@@ -55,20 +31,15 @@ export function fleetCommand(options = {}) {
|
|
|
55
31
|
};
|
|
56
32
|
|
|
57
33
|
console.log(chalk.white.bold(
|
|
58
|
-
// PHASE at 18
|
|
59
|
-
|
|
60
|
-
// already uses (17) for the identical string. A narrower column here
|
|
61
|
-
// would misalign every column after it just for that one row.
|
|
62
|
-
col('FEATURE', 20) + col('TYPE', 9) + col('PHASE', 18) + col('TASKS', 8)
|
|
34
|
+
// PHASE at 18 fits `aguardando-merge`; narrower misaligns every column after it.
|
|
35
|
+
col('FEATURE', 20) + col('TYPE', 9) + col('PHASE', 18) + col('FATIAS', 8)
|
|
63
36
|
+ col('GATES PEND.', 20) + col('WHERE', 24) + col('REMOTO', 16) + col('CLAIM', 16)
|
|
64
37
|
+ col('PORTS', 12) + col('HANDOFF', 9) + 'ATIVIDADE',
|
|
65
38
|
));
|
|
66
39
|
for (const e of fleet.entries) {
|
|
67
|
-
const
|
|
40
|
+
const slices = e.slices ? `${e.slices.done}/${e.slices.total}` : '-';
|
|
68
41
|
const gates = e.pendingGates.length ? e.pendingGates.join(',') : '-';
|
|
69
|
-
// pr-pending
|
|
70
|
-
// is the only place it exists, so show that instead of the misleading
|
|
71
|
-
// 'raiz' a location-blind check would print.
|
|
42
|
+
// pr-pending exists only on its branch, never in a worktree or the root.
|
|
72
43
|
const where = (e.location === 'worktree' || e.location === 'pr-pending') ? e.branch : 'raiz';
|
|
73
44
|
const ports = e.env ? `${e.env.range[0]}-${e.env.range[1]}` : '-';
|
|
74
45
|
const handoff = e.handoff?.exists ? 'sim' : '-';
|
|
@@ -80,7 +51,7 @@ export function fleetCommand(options = {}) {
|
|
|
80
51
|
// length and append the padding by hand.
|
|
81
52
|
const claimPlain = e.claim ? `${e.claim.live ? 'sessão' : 'morta'} (${claimAge(e.claim)})` : '-';
|
|
82
53
|
console.log(
|
|
83
|
-
col(e.feature, 20) + col(e.workType || '-', 9) + col(e.phase, 18) + col(
|
|
54
|
+
col(e.feature, 20) + col(e.workType || '-', 9) + col(e.phase, 18) + col(slices, 8)
|
|
84
55
|
+ col(gates, 20) + col(where, 24) + col(remoteCell(e.remote), 16)
|
|
85
56
|
+ claimCell(e.claim) + ' '.repeat(Math.max(1, 16 - claimPlain.length))
|
|
86
57
|
+ col(ports, 12) + col(handoff, 9) + activity,
|
|
@@ -4,9 +4,9 @@ import { logger } from '../../utils/logger.js';
|
|
|
4
4
|
import { readHeavyConfig } from '../../../framework/hooks/shared/heavy-config.js';
|
|
5
5
|
import { createHeavyGate, HeavyBusyError } from '../../lib/heavy/gate.js';
|
|
6
6
|
import { describeHolder, heavyDir, heavyStatus } from '../../../framework/hooks/shared/heavy-slots.js';
|
|
7
|
+
import { resolveSpawn } from '../../../framework/hooks/shared/spawn-command.js';
|
|
7
8
|
|
|
8
9
|
const EXIT_BUSY = 3;
|
|
9
|
-
const NEEDS_CMD_SHIM = /^(npm|npx|pnpm|yarn)$/;
|
|
10
10
|
|
|
11
11
|
export function heavyStatusCommand(options = {}) {
|
|
12
12
|
const config = readHeavyConfig(process.cwd());
|
|
@@ -49,8 +49,8 @@ export function heavyRunCommand(command, options = {}) {
|
|
|
49
49
|
process.exit(EXIT_BUSY);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
const
|
|
53
|
-
const res = spawnSync(
|
|
52
|
+
const spawn = resolveSpawn(file, args);
|
|
53
|
+
const res = spawnSync(spawn.file, spawn.args, { stdio: 'inherit', shell: spawn.shell });
|
|
54
54
|
gate.release();
|
|
55
55
|
|
|
56
56
|
if (res.error) {
|
|
@@ -37,25 +37,8 @@ import { resolvePrimaryRoot } from './worktree.js';
|
|
|
37
37
|
import { registerProject } from '../../lib/projects/registry.js';
|
|
38
38
|
|
|
39
39
|
/**
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* A worktree's `.claude/` and `.morph/framework/` are junctions back to the
|
|
44
|
-
* primary root (see `worktree.js`'s `setupInfraLinks`), but `.morph/config/`,
|
|
45
|
-
* `.morph/context/`, `.morph/checkpoints/`, `.morph/memory/`, `.morph/archive/`
|
|
46
|
-
* and `.morph/state.json` are NOT linked — a full `init` there would scaffold
|
|
47
|
-
* a second, disconnected install (config, state) inside the worktree, orphaned
|
|
48
|
-
* from the primary root's real install.
|
|
49
|
-
*
|
|
50
|
-
* Fail-SAFE (not fail-open): blocks whenever `resolvePrimaryRoot(targetPath)`
|
|
51
|
-
* resolves to a path OTHER than `targetPath` itself. `resolvePrimaryRoot`
|
|
52
|
-
* itself fails open to `targetPath` outside a git repo (or on any git error),
|
|
53
|
-
* so non-git projects and the primary root itself are never blocked.
|
|
54
|
-
* `--force` is the explicit override, mirroring init's own `--force` flag.
|
|
55
|
-
*
|
|
56
|
-
* @param {string} targetPath - Effective install target (init's targetPath)
|
|
57
|
-
* @param {{ force?: boolean }} [options]
|
|
58
|
-
* @returns {{ blocked: boolean, root?: string, target?: string }}
|
|
40
|
+
* A linked worktree junctions `.claude/` and `.morph/framework/` but not `.morph/config`/state:
|
|
41
|
+
* a full install there orphans a second, disconnected one. `--force` overrides.
|
|
59
42
|
*/
|
|
60
43
|
export function checkSecondaryWorktreeGuard(targetPath, options = {}) {
|
|
61
44
|
if (options.force) return { blocked: false };
|
|
@@ -72,9 +55,6 @@ export async function initCommand(options) {
|
|
|
72
55
|
logger.dim(`Target: ${targetPath}`);
|
|
73
56
|
logger.blank();
|
|
74
57
|
|
|
75
|
-
// Guard: refuse a full install from inside a secondary worktree — it would
|
|
76
|
-
// corrupt the shared infra junctioned back to the primary root and scaffold
|
|
77
|
-
// a second, disconnected .morph/config + state.json. --force overrides.
|
|
78
58
|
const worktreeGuard = checkSecondaryWorktreeGuard(targetPath, options);
|
|
79
59
|
if (worktreeGuard.blocked) {
|
|
80
60
|
logger.warn(`Você está num worktree secundário (${worktreeGuard.target}).`);
|
|
@@ -83,11 +63,9 @@ export async function initCommand(options) {
|
|
|
83
63
|
process.exit(0);
|
|
84
64
|
}
|
|
85
65
|
|
|
86
|
-
// Check if already initialized
|
|
87
66
|
const morphPath = join(targetPath, '.morph');
|
|
88
67
|
if (await pathExists(morphPath)) {
|
|
89
68
|
if (!options.force) {
|
|
90
|
-
// Check if project version is outdated — auto-update instead of blocking
|
|
91
69
|
const projectCheck = await checkProjectOutdated(targetPath);
|
|
92
70
|
if (projectCheck.isOutdated) {
|
|
93
71
|
logger.info(`MORPH already initialized (v${projectCheck.current}). Framework update available (v${projectCheck.cliVersion}).`);
|
|
@@ -105,31 +83,27 @@ export async function initCommand(options) {
|
|
|
105
83
|
|
|
106
84
|
try {
|
|
107
85
|
|
|
108
|
-
// Steps 1-10: Infrastructure (headless, no prompts)
|
|
109
86
|
spinner.stop();
|
|
110
|
-
//
|
|
111
|
-
// ARE the primary root, or the caller explicitly passed --force), so it
|
|
112
|
-
// must not be redundantly re-applied inside setupInfra().
|
|
87
|
+
// The secondary-worktree guard already ran above; setupInfra must not re-apply it.
|
|
113
88
|
const infraResult = await setupInfra(targetPath, { force: true });
|
|
89
|
+
if (infraResult?.refused) {
|
|
90
|
+
process.exitCode = 1;
|
|
91
|
+
return infraResult;
|
|
92
|
+
}
|
|
114
93
|
spinner.start('Continuing...');
|
|
115
94
|
|
|
116
|
-
// Derive display variables from what setupInfra installed
|
|
117
95
|
const cliVersion = getInstalledCLIVersion();
|
|
118
96
|
const commandsCopied = await pathExists(join(targetPath, '.claude', 'commands'));
|
|
119
97
|
const rulesCopied = await pathExists(join(targetPath, '.claude', 'rules'));
|
|
120
|
-
// Re-run installClaudeHooks to get the result object (idempotent — hooks already installed)
|
|
121
98
|
const hooksResult = await installClaudeHooks(targetPath);
|
|
122
99
|
|
|
123
|
-
// Re-derive config path for stack detection updates
|
|
124
100
|
const configDir = join(morphPath, 'config');
|
|
125
101
|
const configPath = join(configDir, 'config.json');
|
|
126
102
|
const contextDir = join(morphPath, 'context');
|
|
127
103
|
|
|
128
|
-
// Read config written by setupInfra so stack detection can update it
|
|
129
104
|
let config = (await pathExists(configPath)) ? await readJson(configPath) : { project: {} };
|
|
130
105
|
if (!config.project) config.project = {};
|
|
131
106
|
|
|
132
|
-
// 11b. Detect Claude Code environment (plugins, MCPs, skills)
|
|
133
107
|
spinner.text = 'Detecting Claude Code environment...';
|
|
134
108
|
let claudeConfigDetected = null;
|
|
135
109
|
let integrationsCreated = false;
|
|
@@ -148,14 +122,6 @@ export async function initCommand(options) {
|
|
|
148
122
|
logger.info(summary);
|
|
149
123
|
}
|
|
150
124
|
|
|
151
|
-
// Show MCP-to-phase mapping.
|
|
152
|
-
//
|
|
153
|
-
// This called mapMcpsToPhases with one argument where it takes three,
|
|
154
|
-
// so `phaseMatrix[currentPhase]` threw a TypeError on every project
|
|
155
|
-
// that had any MCP configured. The outer catch reported it as
|
|
156
|
-
// "Claude config detection skipped" — which reads like "nothing to
|
|
157
|
-
// detect" — and everything below it never ran: integrations.json was
|
|
158
|
-
// never written and the optimized settings were never generated.
|
|
159
125
|
if (claudeConfigDetected.mcpServers.length > 0) {
|
|
160
126
|
const byPhase = mcpAvailabilityByPhase(
|
|
161
127
|
claudeConfigDetected.mcpServers,
|
|
@@ -191,11 +157,9 @@ export async function initCommand(options) {
|
|
|
191
157
|
}
|
|
192
158
|
}
|
|
193
159
|
} catch (error) {
|
|
194
|
-
// Non-fatal: continue without integrations
|
|
195
160
|
logger.dim(` Claude config detection skipped: ${error.message}`);
|
|
196
161
|
}
|
|
197
162
|
|
|
198
|
-
// 11c. Stack detection (moved before MCP setup so we know the stack)
|
|
199
163
|
spinner.text = 'Detecting project stack...';
|
|
200
164
|
let detectedStack = 'unknown';
|
|
201
165
|
const hasProjectFiles = await pathExists(join(targetPath, 'package.json'))
|
|
@@ -210,7 +174,6 @@ export async function initCommand(options) {
|
|
|
210
174
|
if (structure?.stack && structure.stack !== 'unknown') {
|
|
211
175
|
detectedStack = structure.stack;
|
|
212
176
|
|
|
213
|
-
// Persist detected stack to config.json
|
|
214
177
|
if (structure?.stack && structure.stack !== 'unknown') {
|
|
215
178
|
config.project.stack = structure.stack;
|
|
216
179
|
}
|
|
@@ -252,23 +215,19 @@ export async function initCommand(options) {
|
|
|
252
215
|
logger.dim('Review and edit .morph/context/standards.md as needed.');
|
|
253
216
|
}
|
|
254
217
|
|
|
255
|
-
// Re-install stack-filtered assets now that we know the stack
|
|
256
218
|
const stackTags = getProjectTags(config);
|
|
257
219
|
if (stackTags.length > 0) {
|
|
258
220
|
spinner.start('Re-installing stack-filtered assets...');
|
|
259
221
|
const frameworkDir = join(targetPath, '.morph', 'framework');
|
|
260
222
|
const fwSrcDir = join(dirname(fileURLToPath(import.meta.url)), '..', '..', '..', 'framework');
|
|
261
223
|
|
|
262
|
-
// Rules
|
|
263
224
|
const rulesSrc = join(fwSrcDir, 'rules');
|
|
264
225
|
const rulesDest = join(targetPath, '.claude', 'rules');
|
|
265
226
|
installRulesForStack(rulesSrc, rulesDest, stackTags);
|
|
266
227
|
installCommandsForStack(join(fwSrcDir, 'commands'), join(targetPath, '.claude', 'commands'), stackTags);
|
|
267
228
|
|
|
268
|
-
// Skills
|
|
269
229
|
await installSkills(targetPath, { projectTags: stackTags });
|
|
270
230
|
|
|
271
|
-
// Agents (domain personas from agents.json)
|
|
272
231
|
await installAgents(targetPath, fwSrcDir, { projectTags: stackTags });
|
|
273
232
|
await installDomainAgents(targetPath, fwSrcDir, { projectTags: stackTags });
|
|
274
233
|
|
|
@@ -282,7 +241,6 @@ export async function initCommand(options) {
|
|
|
282
241
|
}
|
|
283
242
|
}
|
|
284
243
|
|
|
285
|
-
// 11d. MCP Auto-Setup
|
|
286
244
|
let mcpSetupResult = null;
|
|
287
245
|
if (!options.skipMcp) {
|
|
288
246
|
try {
|
|
@@ -300,7 +258,6 @@ export async function initCommand(options) {
|
|
|
300
258
|
logger.blank();
|
|
301
259
|
logger.header('MCP Server Setup');
|
|
302
260
|
|
|
303
|
-
// Auto-install prompt
|
|
304
261
|
let autoInstalled = {};
|
|
305
262
|
if (hasAutoMcps) {
|
|
306
263
|
const { installAuto } = await inquirer.prompt([{
|
|
@@ -318,7 +275,6 @@ export async function initCommand(options) {
|
|
|
318
275
|
autoInstalled[name] = orchestration.autoInstallable[name];
|
|
319
276
|
}
|
|
320
277
|
|
|
321
|
-
// Install companion skills for MCPs that define them (e.g., Stitch agent skills)
|
|
322
278
|
const skillResults = installCompanionSkills(orchestration.autoInstallable);
|
|
323
279
|
for (const r of skillResults) {
|
|
324
280
|
if (r.success) {
|
|
@@ -330,13 +286,11 @@ export async function initCommand(options) {
|
|
|
330
286
|
}
|
|
331
287
|
}
|
|
332
288
|
|
|
333
|
-
// Credential MCPs — inline setup or instructions
|
|
334
289
|
const manualInstalled = {};
|
|
335
290
|
if (hasManualMcps) {
|
|
336
291
|
for (const [name, entry] of Object.entries(orchestration.needsManualSetup)) {
|
|
337
292
|
logger.blank();
|
|
338
293
|
|
|
339
|
-
// Show warnings
|
|
340
294
|
for (const warning of entry.install.warnings || []) {
|
|
341
295
|
logger.warn(` ${warning}`);
|
|
342
296
|
}
|
|
@@ -350,7 +304,6 @@ export async function initCommand(options) {
|
|
|
350
304
|
}]);
|
|
351
305
|
|
|
352
306
|
if (setupNow) {
|
|
353
|
-
// Stitch — automated setup via setupStitch()
|
|
354
307
|
if (name === 'stitch' && !entry.install.autoInstall) {
|
|
355
308
|
spinner.start('Setting up Stitch MCP...');
|
|
356
309
|
const stitchResult = await setupStitch(targetPath);
|
|
@@ -370,7 +323,6 @@ export async function initCommand(options) {
|
|
|
370
323
|
continue;
|
|
371
324
|
}
|
|
372
325
|
|
|
373
|
-
// Remote MCPs — launch OAuth via claude mcp add
|
|
374
326
|
if (isRemoteMcp(entry.install.config)) {
|
|
375
327
|
const url = entry.install.config.url;
|
|
376
328
|
logger.info(` Launching ${capitalizedName} OAuth authentication...`);
|
|
@@ -387,7 +339,6 @@ export async function initCommand(options) {
|
|
|
387
339
|
continue;
|
|
388
340
|
}
|
|
389
341
|
|
|
390
|
-
// Collect credentials
|
|
391
342
|
const credentialValues = {};
|
|
392
343
|
for (const cred of entry.install.credentials) {
|
|
393
344
|
const { value } = await inquirer.prompt([{
|
|
@@ -404,7 +355,6 @@ export async function initCommand(options) {
|
|
|
404
355
|
spinner.succeed(`${capitalizedName} MCP configured`);
|
|
405
356
|
manualInstalled[name] = entry;
|
|
406
357
|
} else {
|
|
407
|
-
// Show setup instructions
|
|
408
358
|
const instructions = generateSetupInstructions(name, entry);
|
|
409
359
|
logger.blank();
|
|
410
360
|
logger.dim(' Add to .mcp.json → mcpServers:');
|
|
@@ -422,7 +372,6 @@ export async function initCommand(options) {
|
|
|
422
372
|
}
|
|
423
373
|
}
|
|
424
374
|
|
|
425
|
-
// Summary table
|
|
426
375
|
const justInstalled = { ...autoInstalled, ...manualInstalled };
|
|
427
376
|
const statusRows = formatMcpStatusTable(orchestration, justInstalled);
|
|
428
377
|
|
|
@@ -456,7 +405,6 @@ export async function initCommand(options) {
|
|
|
456
405
|
logger.dim('\nSkipped MCP setup (--skip-mcp flag)');
|
|
457
406
|
}
|
|
458
407
|
|
|
459
|
-
// Auto-generate architecture context (non-blocking on failure)
|
|
460
408
|
spinner.text = 'Generating architecture context...';
|
|
461
409
|
try {
|
|
462
410
|
const { scanArchitecture, renderArchitectureContext } = await import('../../lib/generators/architecture-scanner.js');
|
|
@@ -464,15 +412,12 @@ export async function initCommand(options) {
|
|
|
464
412
|
await renderArchitectureContext(targetPath, scanResult);
|
|
465
413
|
spinner.succeed('Architecture context generated');
|
|
466
414
|
} catch {
|
|
467
|
-
// Non-fatal: placeholder README.md remains
|
|
468
415
|
spinner.warn('Architecture context generation skipped');
|
|
469
416
|
}
|
|
470
417
|
|
|
471
418
|
spinner.succeed('MORPH-SPEC installed successfully!');
|
|
472
|
-
// The dashboard's portfolio learns about the project here (fail-open).
|
|
473
419
|
registerProject(targetPath, 'init');
|
|
474
420
|
|
|
475
|
-
// Show next steps
|
|
476
421
|
logger.blank();
|
|
477
422
|
logger.success(`MORPH-SPEC v${cliVersion} installed successfully!`);
|
|
478
423
|
logger.blank();
|
|
@@ -513,7 +458,6 @@ export async function initCommand(options) {
|
|
|
513
458
|
|
|
514
459
|
logger.dim(' ✓ .claude/skills/ (installed as skill directories)');
|
|
515
460
|
|
|
516
|
-
// Show agent team breakdown from setup-infra result
|
|
517
461
|
const agents = infraResult?.agents;
|
|
518
462
|
if (agents) {
|
|
519
463
|
const total = (agents.tier1 || 0) + (agents.tier2 || 0) + (agents.specialists || 0) + (agents.personas || 0);
|
|
@@ -524,7 +468,6 @@ export async function initCommand(options) {
|
|
|
524
468
|
|
|
525
469
|
logger.dim(' ✓ ~/.claude/statusline.sh (global statusline installed)');
|
|
526
470
|
|
|
527
|
-
// Check CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS in ~/.claude/settings.local.json
|
|
528
471
|
logger.blank();
|
|
529
472
|
const globalSettingsPath = join(homedir(), '.claude', 'settings.local.json');
|
|
530
473
|
let agentTeamsEnabled = false;
|
|
@@ -532,7 +475,6 @@ export async function initCommand(options) {
|
|
|
532
475
|
const globalSettings = await readJson(globalSettingsPath);
|
|
533
476
|
agentTeamsEnabled = globalSettings?.env?.CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS === '1';
|
|
534
477
|
} catch {
|
|
535
|
-
// File missing or unreadable — treat as not enabled
|
|
536
478
|
}
|
|
537
479
|
|
|
538
480
|
if (agentTeamsEnabled) {
|
|
@@ -544,7 +486,6 @@ export async function initCommand(options) {
|
|
|
544
486
|
|
|
545
487
|
logger.blank();
|
|
546
488
|
|
|
547
|
-
// Populate Claude Code persistent memory so future sessions enter contextualized
|
|
548
489
|
try {
|
|
549
490
|
const { installProjectMemory } = await import('../../lib/installers/memory-installer.js');
|
|
550
491
|
const memResult = await installProjectMemory(targetPath, {
|
|
@@ -557,10 +498,9 @@ export async function initCommand(options) {
|
|
|
557
498
|
logger.dim(` ⚠ Memory install skipped: ${err.message}`);
|
|
558
499
|
}
|
|
559
500
|
|
|
560
|
-
// Suggest tutorial for first-time users
|
|
561
501
|
if (integrationsCreated) {
|
|
562
502
|
logger.blank();
|
|
563
|
-
logger.info('First time using morph-spec? Run `/morph-
|
|
503
|
+
logger.info('First time using morph-spec? Run `/morph-plan <feature>` to start a new feature.');
|
|
564
504
|
}
|
|
565
505
|
|
|
566
506
|
logger.blank();
|
|
@@ -4,7 +4,8 @@ import { logger } from '../../utils/logger.js';
|
|
|
4
4
|
export async function setupInfraCommand(options) {
|
|
5
5
|
const targetPath = options.path || process.cwd();
|
|
6
6
|
try {
|
|
7
|
-
await setupInfra(targetPath, { reinstall: options.reinstall ?? false });
|
|
7
|
+
const result = await setupInfra(targetPath, { reinstall: options.reinstall ?? false });
|
|
8
|
+
if (result?.refused) process.exitCode = 1;
|
|
8
9
|
} catch (err) {
|
|
9
10
|
logger.error(`setup-infra failed: ${err.message}`);
|
|
10
11
|
process.exit(1);
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import chalk from 'chalk';
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync } from 'fs';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import { getFeatureDir } from '../../core/paths/output-schema.js';
|
|
5
|
+
import { readMorphConfig } from '../../lib/tasks/test-runner.js';
|
|
6
|
+
import { notAuditedReason, scanStack, renderStackScan } from '../../lib/stack/stack-scan.js';
|
|
7
|
+
import { assertOwnerTree, ownerTreeRefusalLines } from '../../lib/worktree/feature-truth.js';
|
|
8
|
+
|
|
9
|
+
export const STACK_SCAN_FILE = 'stack-scan.md';
|
|
10
|
+
|
|
11
|
+
/** Scan the tree at `cwd`; with a feature, write `2-plan/stack-scan.md`. */
|
|
12
|
+
export function runStackScan(featureName, cwd = process.cwd()) {
|
|
13
|
+
const result = scanStack(cwd, readMorphConfig(cwd));
|
|
14
|
+
const markdown = renderStackScan(result, featureName ?? 'projeto');
|
|
15
|
+
if (!featureName) return { ...result, markdown, written: null, exit: 0 };
|
|
16
|
+
|
|
17
|
+
const featureDir = join(cwd, getFeatureDir(featureName));
|
|
18
|
+
if (!existsSync(featureDir)) return { ...result, markdown, written: null, exit: 2, error: 'feature-not-found' };
|
|
19
|
+
const planDir = join(featureDir, '2-plan');
|
|
20
|
+
mkdirSync(planDir, { recursive: true });
|
|
21
|
+
const written = join(planDir, STACK_SCAN_FILE);
|
|
22
|
+
writeFileSync(written, markdown, 'utf8');
|
|
23
|
+
return { ...result, markdown, written, exit: 0 };
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function stackScanCommand(featureName, options = {}) {
|
|
27
|
+
if (featureName) {
|
|
28
|
+
const owner = assertOwnerTree(featureName, process.cwd());
|
|
29
|
+
if (owner.blocked) {
|
|
30
|
+
for (const { tone, text } of ownerTreeRefusalLines(featureName, owner.tree, owner.branch, `morph-spec stack-scan ${featureName}`)) {
|
|
31
|
+
console.error(chalk[tone](text));
|
|
32
|
+
}
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const result = runStackScan(featureName);
|
|
38
|
+
if (options.json) {
|
|
39
|
+
const { markdown, ...rest } = result;
|
|
40
|
+
console.log(JSON.stringify(rest, null, 2));
|
|
41
|
+
process.exit(result.exit);
|
|
42
|
+
}
|
|
43
|
+
if (result.error === 'feature-not-found') {
|
|
44
|
+
console.error(chalk.red(`stack-scan: a feature "${featureName}" não existe — rode morph-spec create ${featureName} antes`));
|
|
45
|
+
process.exit(2);
|
|
46
|
+
}
|
|
47
|
+
if (result.written) {
|
|
48
|
+
const high = result.deviations.filter((d) => d.severity === 'Bloqueante' || d.severity === 'Alto').length;
|
|
49
|
+
console.log(chalk.green(`✓ stack-scan: ${join(getFeatureDir(featureName), '2-plan', STACK_SCAN_FILE)} gravado`));
|
|
50
|
+
const summary = result.greenfield ? 'greenfield'
|
|
51
|
+
: !result.audited ? notAuditedReason(result)
|
|
52
|
+
: `${result.deviations.length} desvio(s), ${high} Bloqueante/Alto`;
|
|
53
|
+
console.log(chalk.gray(` ${summary}`));
|
|
54
|
+
} else {
|
|
55
|
+
process.stdout.write(result.markdown);
|
|
56
|
+
}
|
|
57
|
+
process.exit(result.exit);
|
|
58
|
+
}
|