@polymorphism-tech/morph-spec 4.3.0 → 4.3.2
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 +155 -0
- package/bin/morph-spec.js +3 -3
- package/bin/task-manager.cjs +102 -14
- package/package.json +2 -1
- package/src/commands/agents/agents-fuse.js +2 -1
- package/src/commands/project/detect-agents.js +31 -1
- package/src/commands/project/detect.js +11 -1
- package/src/commands/project/doctor.js +76 -70
- package/src/commands/project/init.js +9 -2
- package/src/commands/project/update.js +12 -2
- package/src/commands/state/advance-phase.js +19 -4
- package/src/commands/state/state.js +38 -14
- package/src/commands/tasks/task.js +1 -1
- package/src/commands/threads/thread-template.js +1 -1
- package/src/core/state/state-manager.js +19 -15
- package/src/core/templates/template-registry.js +1 -1
- package/src/core/workflows/workflow-detector.js +16 -3
- package/src/lib/checkpoints/checkpoint-hooks.js +8 -3
- package/src/lib/detectors/index.js +1 -1
- package/src/lib/detectors/standards-generator.js +77 -17
- package/src/lib/detectors/structure-detector.js +67 -39
- package/src/lib/generators/recap-generator.js +30 -10
- package/src/lib/validators/validation-runner.js +8 -24
- package/src/utils/hooks-installer.js +69 -0
- package/stacks/blazor-azure/.claude/commands/morph-apply.md +221 -0
- package/stacks/blazor-azure/.claude/commands/morph-archive.md +79 -0
- package/stacks/blazor-azure/.claude/commands/morph-deploy.md +529 -0
- package/stacks/blazor-azure/.claude/commands/morph-infra.md +209 -0
- package/stacks/blazor-azure/.claude/commands/morph-preflight.md +227 -0
- package/stacks/blazor-azure/.claude/commands/morph-proposal.md +122 -0
- package/stacks/blazor-azure/.claude/commands/morph-status.md +86 -0
- package/stacks/blazor-azure/.claude/commands/morph-troubleshoot.md +122 -0
- package/stacks/blazor-azure/.morph/.morphversion +5 -5
- package/stacks/blazor-azure/.morph/archive/.gitkeep +25 -0
- package/stacks/blazor-azure/.morph/config/config.json +9 -0
- package/stacks/blazor-azure/.morph/features/.gitkeep +25 -0
- package/stacks/blazor-azure/.morph/project/context/README.md +17 -0
- package/stacks/blazor-azure/.morph/schemas/agent.schema.json +296 -0
- package/stacks/blazor-azure/.morph/schemas/tasks.schema.json +220 -0
- package/stacks/blazor-azure/.morph/specs/.gitkeep +20 -0
- package/stacks/blazor-azure/.morph/standards/ai-agents/blazor-ui.md +364 -0
- package/stacks/blazor-azure/.morph/standards/ai-agents/production.md +415 -0
- package/stacks/blazor-azure/.morph/standards/ai-agents/setup.md +418 -0
- package/stacks/blazor-azure/.morph/standards/ai-agents/team-orchestration.md +479 -0
- package/stacks/blazor-azure/.morph/standards/ai-agents/workflows.md +354 -0
- package/stacks/blazor-azure/.morph/standards/architecture/ddd/aggregates.md +120 -0
- package/stacks/blazor-azure/.morph/standards/architecture/ddd/entities.md +99 -0
- package/stacks/blazor-azure/.morph/standards/architecture/ddd/value-objects.md +124 -0
- package/stacks/blazor-azure/.morph/standards/backend/api/minimal-api.md +494 -0
- package/stacks/blazor-azure/.morph/standards/backend/api/rest.md +492 -0
- package/stacks/blazor-azure/.morph/standards/backend/api/validation.md +88 -0
- package/stacks/blazor-azure/.morph/standards/backend/authentication/passkeys.md +428 -0
- package/stacks/blazor-azure/.morph/standards/backend/database/ef-core.md +199 -0
- package/stacks/blazor-azure/.morph/standards/backend/database/migrations.md +393 -0
- package/stacks/blazor-azure/.morph/standards/backend/database/postgresql/database.md +352 -0
- package/stacks/blazor-azure/.morph/standards/backend/database/repository-patterns.md +528 -0
- package/stacks/blazor-azure/.morph/standards/backend/database/vector-search-rag.md +541 -0
- package/stacks/blazor-azure/.morph/standards/backend/dotnet/async.md +366 -0
- package/stacks/blazor-azure/.morph/standards/backend/dotnet/core.md +117 -0
- package/stacks/blazor-azure/.morph/standards/backend/dotnet/di.md +439 -0
- package/stacks/blazor-azure/.morph/standards/backend/dotnet/program-cs-checklist.md +92 -0
- package/stacks/blazor-azure/.morph/standards/backend/integrations/asaas/asaas-api.md +216 -0
- package/stacks/blazor-azure/.morph/standards/backend/integrations/clerk/clerk-auth.md +290 -0
- package/stacks/blazor-azure/.morph/standards/backend/integrations/hangfire/hangfire-jobs.md +350 -0
- package/stacks/blazor-azure/.morph/standards/backend/integrations/resend/resend-email.md +385 -0
- package/stacks/blazor-azure/.morph/standards/context/analytics.md +96 -0
- package/stacks/blazor-azure/.morph/standards/context/bundles.md +110 -0
- package/stacks/blazor-azure/.morph/standards/context/priming.md +78 -0
- package/stacks/blazor-azure/.morph/standards/core/architecture.md +185 -0
- package/stacks/blazor-azure/.morph/standards/core/coding.md +214 -0
- package/stacks/blazor-azure/.morph/standards/core/git-branching-strategy.md +403 -0
- package/stacks/blazor-azure/.morph/standards/core/git.md +185 -0
- package/stacks/blazor-azure/.morph/standards/core/testing.md +295 -0
- package/stacks/blazor-azure/.morph/standards/data/nosql/blob-storage.md +102 -0
- package/stacks/blazor-azure/.morph/standards/data/nosql/cache/redis.md +97 -0
- package/stacks/blazor-azure/.morph/standards/data/nosql/cosmos-db.md +118 -0
- package/stacks/blazor-azure/.morph/standards/data/vector-search/azure-ai-search.md +121 -0
- package/stacks/blazor-azure/.morph/standards/data/vector-search/rag-chunking.md +104 -0
- package/stacks/blazor-azure/.morph/standards/frontend/blazor/design-checklist.md +222 -0
- package/stacks/blazor-azure/.morph/standards/frontend/blazor/fluent-ui-setup.md +595 -0
- package/stacks/blazor-azure/.morph/standards/frontend/blazor/fluent-ui.md +137 -0
- package/stacks/blazor-azure/.morph/standards/frontend/blazor/html-conversion.md +184 -0
- package/stacks/blazor-azure/.morph/standards/frontend/blazor/lifecycle.md +195 -0
- package/stacks/blazor-azure/.morph/standards/frontend/blazor/pitfalls.md +198 -0
- package/stacks/blazor-azure/.morph/standards/frontend/blazor/state.md +191 -0
- package/stacks/blazor-azure/.morph/standards/frontend/design-system/animations.md +151 -0
- package/stacks/blazor-azure/.morph/standards/frontend/design-system/naming.md +64 -0
- package/stacks/blazor-azure/.morph/standards/frontend/nextjs/nextjs-patterns.md +198 -0
- package/stacks/blazor-azure/.morph/standards/infrastructure/azure/azure.md +624 -0
- package/stacks/blazor-azure/.morph/standards/infrastructure/azure/bicep/bicep-patterns.md +422 -0
- package/stacks/blazor-azure/.morph/standards/infrastructure/azure/devops/azure-devops-setup.md +516 -0
- package/stacks/blazor-azure/.morph/standards/infrastructure/azure/devops/local-development.md +520 -0
- package/stacks/blazor-azure/.morph/standards/infrastructure/azure/services/functions.md +486 -0
- package/stacks/blazor-azure/.morph/standards/infrastructure/azure/services/service-bus.md +459 -0
- package/stacks/blazor-azure/.morph/standards/infrastructure/azure/services/storage.md +407 -0
- package/stacks/blazor-azure/.morph/standards/infrastructure/docker/easypanel-deploy.md +196 -0
- package/stacks/blazor-azure/.morph/standards/infrastructure/supabase/mcp-setup.md +252 -0
- package/stacks/blazor-azure/.morph/standards/infrastructure/supabase/supabase-auth.md +176 -0
- package/stacks/blazor-azure/.morph/standards/infrastructure/supabase/supabase-pgvector.md +169 -0
- package/stacks/blazor-azure/.morph/standards/infrastructure/supabase/supabase-rls.md +184 -0
- package/stacks/blazor-azure/.morph/standards/infrastructure/supabase/supabase-storage.md +153 -0
- package/stacks/blazor-azure/.morph/standards/integration/api/graphql.md +91 -0
- package/stacks/blazor-azure/.morph/standards/integration/api/grpc.md +114 -0
- package/stacks/blazor-azure/.morph/standards/integration/api/rest-design.md +95 -0
- package/stacks/blazor-azure/.morph/standards/integration/event-driven/cqrs.md +101 -0
- package/stacks/blazor-azure/.morph/standards/integration/event-driven/event-sourcing.md +124 -0
- package/stacks/blazor-azure/.morph/standards/integration/event-driven/service-bus.md +95 -0
- package/stacks/blazor-azure/.morph/standards/observability/logging.md +131 -0
- package/stacks/blazor-azure/.morph/standards/observability/metrics.md +121 -0
- package/stacks/blazor-azure/.morph/standards/observability/monitoring.md +114 -0
- package/stacks/blazor-azure/.morph/standards/observability/tracing.md +132 -0
- package/stacks/blazor-azure/.morph/standards/workflows/parallel-execution.md +112 -0
- package/stacks/blazor-azure/.morph/standards/workflows/thread-management.md +113 -0
- package/stacks/blazor-azure/.morph/test-infra/example.bicep +59 -0
- package/stacks/blazor-azure/CLAUDE.md +106 -101
- package/stacks/nextjs-supabase/.claude/commands/morph-apply.md +221 -0
- package/stacks/nextjs-supabase/.claude/commands/morph-archive.md +79 -0
- package/stacks/nextjs-supabase/.claude/commands/morph-deploy.md +529 -0
- package/stacks/nextjs-supabase/.claude/commands/morph-infra.md +209 -0
- package/stacks/nextjs-supabase/.claude/commands/morph-preflight.md +227 -0
- package/stacks/nextjs-supabase/.claude/commands/morph-proposal.md +122 -0
- package/stacks/nextjs-supabase/.claude/commands/morph-status.md +86 -0
- package/stacks/nextjs-supabase/.claude/commands/morph-troubleshoot.md +122 -0
- package/stacks/nextjs-supabase/.morph/.morphversion +5 -0
- package/stacks/nextjs-supabase/.morph/config/agents.json +730 -127
- package/stacks/nextjs-supabase/.morph/config/config.json +9 -0
- package/stacks/nextjs-supabase/.morph/project/context/README.md +17 -0
- package/stacks/nextjs-supabase/.morph/standards/ai-agents/blazor-ui.md +364 -0
- package/stacks/nextjs-supabase/.morph/standards/ai-agents/production.md +415 -0
- package/stacks/nextjs-supabase/.morph/standards/ai-agents/setup.md +418 -0
- package/stacks/nextjs-supabase/.morph/standards/ai-agents/team-orchestration.md +479 -0
- package/stacks/nextjs-supabase/.morph/standards/ai-agents/workflows.md +354 -0
- package/stacks/nextjs-supabase/.morph/standards/architecture/ddd/aggregates.md +120 -0
- package/stacks/nextjs-supabase/.morph/standards/architecture/ddd/entities.md +99 -0
- package/stacks/nextjs-supabase/.morph/standards/architecture/ddd/value-objects.md +124 -0
- package/stacks/nextjs-supabase/.morph/standards/backend/api/minimal-api.md +494 -0
- package/stacks/nextjs-supabase/.morph/standards/backend/api/rest.md +492 -0
- package/stacks/nextjs-supabase/.morph/standards/backend/api/validation.md +88 -0
- package/stacks/nextjs-supabase/.morph/standards/backend/authentication/passkeys.md +428 -0
- package/stacks/nextjs-supabase/.morph/standards/backend/database/ef-core.md +199 -0
- package/stacks/nextjs-supabase/.morph/standards/backend/database/migrations.md +393 -0
- package/stacks/nextjs-supabase/.morph/standards/backend/database/postgresql/database.md +352 -0
- package/stacks/nextjs-supabase/.morph/standards/backend/database/repository-patterns.md +528 -0
- package/stacks/nextjs-supabase/.morph/standards/backend/database/vector-search-rag.md +541 -0
- package/stacks/nextjs-supabase/.morph/standards/backend/dotnet/async.md +366 -0
- package/stacks/nextjs-supabase/.morph/standards/backend/dotnet/core.md +117 -0
- package/stacks/nextjs-supabase/.morph/standards/backend/dotnet/di.md +439 -0
- package/stacks/nextjs-supabase/.morph/standards/backend/dotnet/program-cs-checklist.md +92 -0
- package/stacks/nextjs-supabase/.morph/standards/backend/integrations/asaas/asaas-api.md +216 -0
- package/stacks/nextjs-supabase/.morph/standards/backend/integrations/clerk/clerk-auth.md +290 -0
- package/stacks/nextjs-supabase/.morph/standards/backend/integrations/hangfire/hangfire-jobs.md +350 -0
- package/stacks/nextjs-supabase/.morph/standards/backend/integrations/resend/resend-email.md +385 -0
- package/stacks/nextjs-supabase/.morph/standards/context/analytics.md +96 -0
- package/stacks/nextjs-supabase/.morph/standards/context/bundles.md +110 -0
- package/stacks/nextjs-supabase/.morph/standards/context/priming.md +78 -0
- package/stacks/nextjs-supabase/.morph/standards/core/architecture.md +185 -0
- package/stacks/nextjs-supabase/.morph/standards/core/coding.md +214 -0
- package/stacks/nextjs-supabase/.morph/standards/core/git-branching-strategy.md +403 -0
- package/stacks/nextjs-supabase/.morph/standards/core/git.md +185 -0
- package/stacks/nextjs-supabase/.morph/standards/core/testing.md +295 -0
- package/stacks/nextjs-supabase/.morph/standards/data/nosql/blob-storage.md +102 -0
- package/stacks/nextjs-supabase/.morph/standards/data/nosql/cache/redis.md +97 -0
- package/stacks/nextjs-supabase/.morph/standards/data/nosql/cosmos-db.md +118 -0
- package/stacks/nextjs-supabase/.morph/standards/data/vector-search/azure-ai-search.md +121 -0
- package/stacks/nextjs-supabase/.morph/standards/data/vector-search/rag-chunking.md +104 -0
- package/stacks/nextjs-supabase/.morph/standards/frontend/blazor/design-checklist.md +222 -0
- package/stacks/nextjs-supabase/.morph/standards/frontend/blazor/fluent-ui-setup.md +595 -0
- package/stacks/nextjs-supabase/.morph/standards/frontend/blazor/fluent-ui.md +137 -0
- package/stacks/nextjs-supabase/.morph/standards/frontend/blazor/html-conversion.md +184 -0
- package/stacks/nextjs-supabase/.morph/standards/frontend/blazor/lifecycle.md +195 -0
- package/stacks/nextjs-supabase/.morph/standards/frontend/blazor/pitfalls.md +198 -0
- package/stacks/nextjs-supabase/.morph/standards/frontend/blazor/state.md +191 -0
- package/stacks/nextjs-supabase/.morph/standards/frontend/design-system/animations.md +151 -0
- package/stacks/nextjs-supabase/.morph/standards/frontend/design-system/naming.md +64 -0
- package/stacks/nextjs-supabase/.morph/standards/frontend/nextjs/nextjs-patterns.md +198 -0
- package/stacks/nextjs-supabase/.morph/standards/infrastructure/azure/azure.md +624 -0
- package/stacks/nextjs-supabase/.morph/standards/infrastructure/azure/bicep/bicep-patterns.md +422 -0
- package/stacks/nextjs-supabase/.morph/standards/infrastructure/azure/devops/azure-devops-setup.md +516 -0
- package/stacks/nextjs-supabase/.morph/standards/infrastructure/azure/devops/local-development.md +520 -0
- package/stacks/nextjs-supabase/.morph/standards/infrastructure/azure/services/functions.md +486 -0
- package/stacks/nextjs-supabase/.morph/standards/infrastructure/azure/services/service-bus.md +459 -0
- package/stacks/nextjs-supabase/.morph/standards/infrastructure/azure/services/storage.md +407 -0
- package/stacks/nextjs-supabase/.morph/standards/infrastructure/docker/easypanel-deploy.md +196 -0
- package/stacks/nextjs-supabase/.morph/standards/infrastructure/supabase/mcp-setup.md +252 -0
- package/stacks/nextjs-supabase/.morph/standards/infrastructure/supabase/supabase-auth.md +176 -0
- package/stacks/nextjs-supabase/.morph/standards/infrastructure/supabase/supabase-pgvector.md +169 -0
- package/stacks/nextjs-supabase/.morph/standards/infrastructure/supabase/supabase-rls.md +184 -0
- package/stacks/nextjs-supabase/.morph/standards/infrastructure/supabase/supabase-storage.md +153 -0
- package/stacks/nextjs-supabase/.morph/standards/integration/api/graphql.md +91 -0
- package/stacks/nextjs-supabase/.morph/standards/integration/api/grpc.md +114 -0
- package/stacks/nextjs-supabase/.morph/standards/integration/api/rest-design.md +95 -0
- package/stacks/nextjs-supabase/.morph/standards/integration/event-driven/cqrs.md +101 -0
- package/stacks/nextjs-supabase/.morph/standards/integration/event-driven/event-sourcing.md +124 -0
- package/stacks/nextjs-supabase/.morph/standards/integration/event-driven/service-bus.md +95 -0
- package/stacks/nextjs-supabase/.morph/standards/observability/logging.md +131 -0
- package/stacks/nextjs-supabase/.morph/standards/observability/metrics.md +121 -0
- package/stacks/nextjs-supabase/.morph/standards/observability/monitoring.md +114 -0
- package/stacks/nextjs-supabase/.morph/standards/observability/tracing.md +132 -0
- package/stacks/nextjs-supabase/.morph/standards/workflows/parallel-execution.md +112 -0
- package/stacks/nextjs-supabase/.morph/standards/workflows/thread-management.md +113 -0
- package/stacks/nextjs-supabase/CLAUDE.md +69 -63
- package/stacks/blazor-azure/.morph/templates/.gitkeep +0 -0
- package/stacks/blazor-azure/.morph/templates/infrastructure/github/workflows/cd-prod.yml.hbs +0 -41
- package/stacks/blazor-azure/.morph/templates/infrastructure/github/workflows/cd-staging.yml.hbs +0 -24
- package/stacks/blazor-azure/.morph/templates/infrastructure/github/workflows/ci-build.yml.hbs +0 -23
- package/stacks/nextjs-supabase/.morph/templates/.gitkeep +0 -0
- package/stacks/nextjs-supabase/.morph/templates/infrastructure/github/workflows/cd-prod.yml.hbs +0 -22
- package/stacks/nextjs-supabase/.morph/templates/infrastructure/github/workflows/cd-staging.yml.hbs +0 -22
- package/stacks/nextjs-supabase/.morph/templates/infrastructure/github/workflows/ci-build.yml.hbs +0 -35
|
@@ -53,7 +53,7 @@ function getNpmGlobalPrefix() {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
// lib files
|
|
56
|
-
const
|
|
56
|
+
const REQUIRED_LIB_FILES = [
|
|
57
57
|
'src/lib/analytics/analytics-engine.js',
|
|
58
58
|
'src/lib/tracking/artifact-trail.js',
|
|
59
59
|
'src/lib/context/context-bundler.js',
|
|
@@ -71,22 +71,22 @@ const V3_LIB_FILES = [
|
|
|
71
71
|
'src/lib/trust/trust-manager.js'
|
|
72
72
|
];
|
|
73
73
|
|
|
74
|
-
//
|
|
75
|
-
const
|
|
76
|
-
'src/commands/agents-fuse.js',
|
|
77
|
-
'src/commands/analytics.js',
|
|
78
|
-
'src/commands/context-prime.js',
|
|
79
|
-
'src/commands/core-four.js',
|
|
80
|
-
'src/commands/mcp.js',
|
|
81
|
-
'src/commands/micro-agent.js',
|
|
82
|
-
'src/commands/squad-template.js',
|
|
83
|
-
'src/commands/thread-template.js',
|
|
84
|
-
'src/commands/threads.js',
|
|
85
|
-
'src/commands/trust.js'
|
|
74
|
+
// command files
|
|
75
|
+
const REQUIRED_COMMAND_FILES = [
|
|
76
|
+
'src/commands/agents/agents-fuse.js',
|
|
77
|
+
'src/commands/analytics/analytics.js',
|
|
78
|
+
'src/commands/context/context-prime.js',
|
|
79
|
+
'src/commands/context/core-four.js',
|
|
80
|
+
'src/commands/mcp/mcp.js',
|
|
81
|
+
'src/commands/agents/micro-agent.js',
|
|
82
|
+
'src/commands/agents/squad-template.js',
|
|
83
|
+
'src/commands/threads/thread-template.js',
|
|
84
|
+
'src/commands/threads/threads.js',
|
|
85
|
+
'src/commands/trust/trust.js'
|
|
86
86
|
];
|
|
87
87
|
|
|
88
|
-
//
|
|
89
|
-
const
|
|
88
|
+
// HOP templates (meta-prompts)
|
|
89
|
+
const HOP_TEMPLATES = [
|
|
90
90
|
'framework/templates/meta-prompts/squad-leaders/backend-squad.md',
|
|
91
91
|
'framework/templates/meta-prompts/squad-leaders/frontend-squad.md',
|
|
92
92
|
'framework/templates/meta-prompts/parallel-workers/parallel-worker.md',
|
|
@@ -98,11 +98,11 @@ const V3_HOP_TEMPLATES = [
|
|
|
98
98
|
'framework/templates/meta-prompts/validators/pre-commit-validator.md',
|
|
99
99
|
'framework/templates/meta-prompts/fusion/fusion-agent.md',
|
|
100
100
|
'framework/templates/meta-prompts/fusion/fusion-aggregator.md',
|
|
101
|
-
'framework/templates/
|
|
101
|
+
'framework/templates/REGISTRY.json'
|
|
102
102
|
];
|
|
103
103
|
|
|
104
|
-
//
|
|
105
|
-
const
|
|
104
|
+
// framework standards
|
|
105
|
+
const FRAMEWORK_STANDARDS = [
|
|
106
106
|
'framework/standards/observability/monitoring.md',
|
|
107
107
|
'framework/standards/observability/logging.md',
|
|
108
108
|
'framework/standards/observability/tracing.md',
|
|
@@ -128,8 +128,8 @@ const V3_STANDARDS = [
|
|
|
128
128
|
'framework/standards/workflows/parallel-execution.md'
|
|
129
129
|
];
|
|
130
130
|
|
|
131
|
-
//
|
|
132
|
-
const
|
|
131
|
+
// required agents expected in agents.json
|
|
132
|
+
const REQUIRED_AGENTS = [
|
|
133
133
|
'vector-search-expert',
|
|
134
134
|
'thread-orchestrator',
|
|
135
135
|
'context-optimizer',
|
|
@@ -137,10 +137,10 @@ const V3_NEW_AGENTS = [
|
|
|
137
137
|
];
|
|
138
138
|
|
|
139
139
|
/**
|
|
140
|
-
* Run
|
|
140
|
+
* Run full health checks
|
|
141
141
|
*/
|
|
142
|
-
async function
|
|
143
|
-
console.log(chalk.bold('\n🔬 MORPH-SPEC
|
|
142
|
+
async function doctorFullCommand(frameworkRoot) {
|
|
143
|
+
console.log(chalk.bold('\n🔬 MORPH-SPEC Full Health Check\n'));
|
|
144
144
|
console.log('─'.repeat(60));
|
|
145
145
|
|
|
146
146
|
const checks = [];
|
|
@@ -157,55 +157,55 @@ async function doctorV3Command(frameworkRoot) {
|
|
|
157
157
|
}
|
|
158
158
|
};
|
|
159
159
|
|
|
160
|
-
// ── 1.
|
|
161
|
-
console.log(chalk.cyan(
|
|
160
|
+
// ── 1. Core Libraries ───────────────────────────────────────────────────
|
|
161
|
+
console.log(chalk.cyan(`\n src/lib/ — Core Libraries (${REQUIRED_LIB_FILES.length} files)`));
|
|
162
162
|
const missingLibs = [];
|
|
163
|
-
for (const f of
|
|
163
|
+
for (const f of REQUIRED_LIB_FILES) {
|
|
164
164
|
if (!(await pathExists(join(frameworkRoot, f)))) missingLibs.push(f.split('/').pop());
|
|
165
165
|
}
|
|
166
|
-
check(`
|
|
166
|
+
check(`Core Libraries (${REQUIRED_LIB_FILES.length - missingLibs.length}/${REQUIRED_LIB_FILES.length})`,
|
|
167
167
|
missingLibs.length === 0, false,
|
|
168
168
|
missingLibs.length > 0 ? `missing: ${missingLibs.join(', ')}` : '');
|
|
169
169
|
|
|
170
|
-
// ── 2.
|
|
171
|
-
console.log(chalk.cyan(
|
|
170
|
+
// ── 2. Command Files ─────────────────────────────────────────────────────
|
|
171
|
+
console.log(chalk.cyan(`\n src/commands/ — Command Files (${REQUIRED_COMMAND_FILES.length} files)`));
|
|
172
172
|
const missingCmds = [];
|
|
173
|
-
for (const f of
|
|
173
|
+
for (const f of REQUIRED_COMMAND_FILES) {
|
|
174
174
|
if (!(await pathExists(join(frameworkRoot, f)))) missingCmds.push(f.split('/').pop());
|
|
175
175
|
}
|
|
176
|
-
check(`
|
|
176
|
+
check(`Command Files (${REQUIRED_COMMAND_FILES.length - missingCmds.length}/${REQUIRED_COMMAND_FILES.length})`,
|
|
177
177
|
missingCmds.length === 0, false,
|
|
178
178
|
missingCmds.length > 0 ? `missing: ${missingCmds.join(', ')}` : '');
|
|
179
179
|
|
|
180
|
-
// ── 3. HOP Templates
|
|
181
|
-
console.log(chalk.cyan(
|
|
180
|
+
// ── 3. HOP Templates ────────────────────────────────────────────────────
|
|
181
|
+
console.log(chalk.cyan(`\n framework/templates/meta-prompts/ — HOP Templates (${HOP_TEMPLATES.length})`));
|
|
182
182
|
const missingHOPs = [];
|
|
183
|
-
for (const f of
|
|
183
|
+
for (const f of HOP_TEMPLATES) {
|
|
184
184
|
if (!(await pathExists(join(frameworkRoot, f)))) missingHOPs.push(f.split('/').pop());
|
|
185
185
|
}
|
|
186
|
-
check(`HOP
|
|
186
|
+
check(`HOP Templates (${HOP_TEMPLATES.length - missingHOPs.length}/${HOP_TEMPLATES.length})`,
|
|
187
187
|
missingHOPs.length === 0, false,
|
|
188
188
|
missingHOPs.length > 0 ? `missing: ${missingHOPs.join(', ')}` : '');
|
|
189
189
|
|
|
190
|
-
// ── 4.
|
|
191
|
-
console.log(chalk.cyan(
|
|
190
|
+
// ── 4. Framework Standards ───────────────────────────────────────────────
|
|
191
|
+
console.log(chalk.cyan(`\n framework/standards/ — Framework Standards (${FRAMEWORK_STANDARDS.length} files)`));
|
|
192
192
|
const missingStds = [];
|
|
193
|
-
for (const f of
|
|
193
|
+
for (const f of FRAMEWORK_STANDARDS) {
|
|
194
194
|
if (!(await pathExists(join(frameworkRoot, f)))) missingStds.push(f.replace('framework/standards/', ''));
|
|
195
195
|
}
|
|
196
|
-
check(`
|
|
196
|
+
check(`Framework Standards (${FRAMEWORK_STANDARDS.length - missingStds.length}/${FRAMEWORK_STANDARDS.length})`,
|
|
197
197
|
missingStds.length === 0, false,
|
|
198
198
|
missingStds.length > 0 ? `missing: ${missingStds.join(', ')}` : '');
|
|
199
199
|
|
|
200
|
-
// ── 5.
|
|
201
|
-
console.log(chalk.cyan(
|
|
200
|
+
// ── 5. Required Agents in agents.json ───────────────────────────────────
|
|
201
|
+
console.log(chalk.cyan(`\n .morph/config/agents.json — Required Agents (${REQUIRED_AGENTS.length})`));
|
|
202
202
|
const agentsPath = join(frameworkRoot, '.morph/config/agents.json');
|
|
203
203
|
if (await pathExists(agentsPath)) {
|
|
204
204
|
try {
|
|
205
205
|
const agentsConfig = JSON.parse(await fs.readFile(agentsPath, 'utf8'));
|
|
206
206
|
const agents = agentsConfig.agents || {};
|
|
207
|
-
const missingAgents =
|
|
208
|
-
check(`
|
|
207
|
+
const missingAgents = REQUIRED_AGENTS.filter(id => !agents[id]);
|
|
208
|
+
check(`Required Agents (${REQUIRED_AGENTS.length - missingAgents.length}/${REQUIRED_AGENTS.length})`,
|
|
209
209
|
missingAgents.length === 0, false,
|
|
210
210
|
missingAgents.length > 0 ? `missing: ${missingAgents.join(', ')}` : '');
|
|
211
211
|
} catch {
|
|
@@ -220,15 +220,15 @@ async function doctorV3Command(frameworkRoot) {
|
|
|
220
220
|
const ztPath = join(frameworkRoot, 'framework/workflows/configs/zero-touch.json');
|
|
221
221
|
check('zero-touch.json workflow config', await pathExists(ztPath));
|
|
222
222
|
|
|
223
|
-
// ── 8. state.json
|
|
223
|
+
// ── 8. state.json schema version ────────────────────────────────────────
|
|
224
224
|
console.log(chalk.cyan('\n .morph/state.json — Schema Version'));
|
|
225
225
|
const statePath = join(frameworkRoot, '.morph/state.json');
|
|
226
226
|
if (await pathExists(statePath)) {
|
|
227
227
|
try {
|
|
228
228
|
const state = JSON.parse(await fs.readFile(statePath, 'utf8'));
|
|
229
|
-
const
|
|
230
|
-
check(`state.json schema (
|
|
231
|
-
|
|
229
|
+
const isCurrent = state.version === '3.0.0';
|
|
230
|
+
check(`state.json schema (${state.version})`, isCurrent, true,
|
|
231
|
+
isCurrent ? '' : 'run: morph-spec state init --force');
|
|
232
232
|
} catch {
|
|
233
233
|
check('state.json parse', false, false, 'invalid JSON');
|
|
234
234
|
}
|
|
@@ -254,20 +254,20 @@ async function doctorV3Command(frameworkRoot) {
|
|
|
254
254
|
const total = checks.length;
|
|
255
255
|
|
|
256
256
|
if (hasErrors) {
|
|
257
|
-
console.log(chalk.red(`\n❌ ${passed}/${total} checks passed —
|
|
257
|
+
console.log(chalk.red(`\n❌ ${passed}/${total} checks passed — see errors above\n`));
|
|
258
258
|
process.exit(1);
|
|
259
259
|
} else if (hasWarnings) {
|
|
260
260
|
console.log(chalk.yellow(`\n⚠️ ${passed}/${total} checks passed (warnings only)\n`));
|
|
261
261
|
} else {
|
|
262
|
-
console.log(chalk.green(`\n✅ ${passed}/${total} — All
|
|
262
|
+
console.log(chalk.green(`\n✅ ${passed}/${total} — All checks passed!\n`));
|
|
263
263
|
}
|
|
264
264
|
}
|
|
265
265
|
|
|
266
266
|
export async function doctorCommand(options = {}) {
|
|
267
|
-
//
|
|
268
|
-
if (options.
|
|
267
|
+
// full health check mode
|
|
268
|
+
if (options.full) {
|
|
269
269
|
const frameworkRoot = process.cwd();
|
|
270
|
-
return
|
|
270
|
+
return doctorFullCommand(frameworkRoot);
|
|
271
271
|
}
|
|
272
272
|
|
|
273
273
|
const targetPath = process.cwd();
|
|
@@ -391,24 +391,25 @@ export async function doctorCommand(options = {}) {
|
|
|
391
391
|
hasErrors = true;
|
|
392
392
|
}
|
|
393
393
|
|
|
394
|
-
// Check standards
|
|
394
|
+
// Check standards (either in project .morph/standards/ or in framework package)
|
|
395
395
|
const standardsPath = join(morphPath, 'standards');
|
|
396
|
+
const frameworkStdsRoot = join(import.meta.dirname, '..', '..', '..', 'framework', 'standards');
|
|
396
397
|
if (await pathExists(standardsPath)) {
|
|
397
|
-
|
|
398
|
-
const
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
pathExists(archStd),
|
|
404
|
-
pathExists(azureStd)
|
|
405
|
-
]).then(results => results.every(Boolean));
|
|
406
|
-
|
|
407
|
-
if (hasAll) {
|
|
398
|
+
// Check for core standards in hierarchy (copied by init) or flat layout
|
|
399
|
+
const codingStd = await pathExists(join(standardsPath, 'core', 'coding.md')) ||
|
|
400
|
+
await pathExists(join(standardsPath, 'coding.md'));
|
|
401
|
+
const archStd = await pathExists(join(standardsPath, 'core', 'architecture.md')) ||
|
|
402
|
+
await pathExists(join(standardsPath, 'architecture.md'));
|
|
403
|
+
if (codingStd && archStd) {
|
|
408
404
|
checks.push({ name: 'standards/', status: 'ok' });
|
|
409
405
|
} else {
|
|
410
|
-
checks.push({ name: 'standards/', status: 'warn', msg: '
|
|
406
|
+
checks.push({ name: 'standards/', status: 'warn', msg: 'core standards missing — run morph-spec init' });
|
|
407
|
+
hasWarnings = true;
|
|
411
408
|
}
|
|
409
|
+
} else if (await pathExists(frameworkStdsRoot)) {
|
|
410
|
+
// Framework package has standards (dev/global install mode)
|
|
411
|
+
checks.push({ name: 'standards/', status: 'warn', msg: 'not installed in project (run morph-spec init)' });
|
|
412
|
+
hasWarnings = true;
|
|
412
413
|
} else {
|
|
413
414
|
checks.push({ name: 'standards/', status: 'missing' });
|
|
414
415
|
hasErrors = true;
|
|
@@ -487,13 +488,18 @@ export async function doctorCommand(options = {}) {
|
|
|
487
488
|
hasWarnings = true;
|
|
488
489
|
}
|
|
489
490
|
|
|
490
|
-
// Check key templates exist
|
|
491
|
-
const
|
|
491
|
+
// Check key templates exist (in framework package, not project copy)
|
|
492
|
+
const frameworkTemplatesRoot = join(import.meta.dirname, '..', '..', '..', 'framework', 'templates');
|
|
493
|
+
const keyTemplates = [
|
|
494
|
+
{ name: 'proposal.md', path: join(frameworkTemplatesRoot, 'docs', 'proposal.md') },
|
|
495
|
+
{ name: 'spec.md', path: join(frameworkTemplatesRoot, 'docs', 'spec.md') },
|
|
496
|
+
{ name: 'tasks.md', path: join(frameworkTemplatesRoot, 'feature', 'tasks.md') },
|
|
497
|
+
{ name: 'decisions.md', path: join(frameworkTemplatesRoot, 'feature', 'decisions.md') }
|
|
498
|
+
];
|
|
492
499
|
const missingTemplates = [];
|
|
493
500
|
for (const template of keyTemplates) {
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
missingTemplates.push(template);
|
|
501
|
+
if (!(await pathExists(template.path))) {
|
|
502
|
+
missingTemplates.push(template.name);
|
|
497
503
|
}
|
|
498
504
|
}
|
|
499
505
|
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
createDirectoryLink
|
|
19
19
|
} from '../../utils/file-copier.js';
|
|
20
20
|
import { saveProjectMorphVersion, getInstalledCLIVersion } from '../../utils/version-checker.js';
|
|
21
|
+
import { installClaudeHooks } from '../../utils/hooks-installer.js';
|
|
21
22
|
import { AutoContextOrchestrator } from '../../core/orchestrator.js';
|
|
22
23
|
import { detectClaudeCode } from '../../llm/environment-detector.js';
|
|
23
24
|
|
|
@@ -125,7 +126,7 @@ Run \`morph-spec detect\` to analyze your project.
|
|
|
125
126
|
|
|
126
127
|
// 6b. Copy framework standards hierarchy (universal standards)
|
|
127
128
|
spinner.text = 'Copying framework standards hierarchy...';
|
|
128
|
-
const frameworkStandardsSrc = join(import.meta.dirname, '..', '..', 'framework', 'standards');
|
|
129
|
+
const frameworkStandardsSrc = join(import.meta.dirname, '..', '..', '..', 'framework', 'standards');
|
|
129
130
|
const frameworkStandardsDest = join(morphPath, 'standards');
|
|
130
131
|
if (await pathExists(frameworkStandardsSrc)) {
|
|
131
132
|
// Copy entire hierarchy (core/, backend/, frontend/, infrastructure/)
|
|
@@ -155,8 +156,9 @@ Run \`morph-spec detect\` to analyze your project.
|
|
|
155
156
|
}
|
|
156
157
|
|
|
157
158
|
// 9. Copy .claude commands and create symlinks for skills
|
|
159
|
+
// Source: framework root .claude/ (canonical for all stacks)
|
|
158
160
|
spinner.text = 'Setting up Claude Code integration...';
|
|
159
|
-
const claudeSrc = join(
|
|
161
|
+
const claudeSrc = join(import.meta.dirname, '..', '..', '..', '.claude');
|
|
160
162
|
const claudeDest = join(targetPath, '.claude');
|
|
161
163
|
|
|
162
164
|
let symlinkCount = 0;
|
|
@@ -217,6 +219,10 @@ Run \`morph-spec detect\` to analyze your project.
|
|
|
217
219
|
}
|
|
218
220
|
}
|
|
219
221
|
|
|
222
|
+
// 9b. Install/update agent-teams hooks in .claude/settings.local.json
|
|
223
|
+
spinner.text = 'Installing Claude Code hooks...';
|
|
224
|
+
const hooksInstalled = await installClaudeHooks(targetPath);
|
|
225
|
+
|
|
220
226
|
// 10. Save version info
|
|
221
227
|
spinner.text = 'Saving version info...';
|
|
222
228
|
const cliVersion = getInstalledCLIVersion();
|
|
@@ -251,6 +257,7 @@ Run \`morph-spec detect\` to analyze your project.
|
|
|
251
257
|
logger.dim(` ✓ .morph/templates/ (Bicep, integrations, saas, ...)`);
|
|
252
258
|
logger.dim(` ✓ .morph/project/ (context, standards, outputs)`);
|
|
253
259
|
logger.dim(` ✓ .claude/commands/ (slash commands)`);
|
|
260
|
+
logger.dim(` ✓ .claude/settings.local.json (agent-teams hooks)`);
|
|
254
261
|
|
|
255
262
|
if (symlinkCount > 0) {
|
|
256
263
|
const linkType = process.platform === 'win32' ? 'junction-linked' : 'symlinked';
|
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import { join } from 'path';
|
|
1
|
+
import { join, dirname } from 'path';
|
|
2
|
+
import { fileURLToPath } from 'url';
|
|
3
|
+
|
|
4
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
2
5
|
import fs from 'fs-extra';
|
|
3
6
|
import ora from 'ora';
|
|
4
7
|
import chalk from 'chalk';
|
|
@@ -19,6 +22,7 @@ import {
|
|
|
19
22
|
getUpdateInstructions,
|
|
20
23
|
detectInstallMethod
|
|
21
24
|
} from '../../utils/version-checker.js';
|
|
25
|
+
import { installClaudeHooks } from '../../utils/hooks-installer.js';
|
|
22
26
|
import { AutoContextOrchestrator } from '../../core/orchestrator.js';
|
|
23
27
|
import { detectClaudeCode } from '../../llm/environment-detector.js';
|
|
24
28
|
|
|
@@ -117,8 +121,9 @@ export async function updateCommand(options) {
|
|
|
117
121
|
}
|
|
118
122
|
|
|
119
123
|
// Update .claude commands and skills
|
|
124
|
+
// Source: framework root .claude/ (canonical for all stacks)
|
|
120
125
|
updateSpinner.text = 'Updating Claude commands and skills...';
|
|
121
|
-
const claudeSrc = join(
|
|
126
|
+
const claudeSrc = join(__dirname, '..', '..', '..', '.claude');
|
|
122
127
|
const claudeDest = join(targetPath, '.claude');
|
|
123
128
|
if (await pathExists(claudeSrc)) {
|
|
124
129
|
// Copy commands (always copy, these are small)
|
|
@@ -154,6 +159,10 @@ export async function updateCommand(options) {
|
|
|
154
159
|
}
|
|
155
160
|
}
|
|
156
161
|
|
|
162
|
+
// Update agent-teams hooks in .claude/settings.local.json
|
|
163
|
+
updateSpinner.text = 'Updating Claude Code hooks...';
|
|
164
|
+
await installClaudeHooks(targetPath);
|
|
165
|
+
|
|
157
166
|
// Update CLAUDE.md
|
|
158
167
|
updateSpinner.text = 'Updating CLAUDE.md...';
|
|
159
168
|
const claudeMdSrc = join(contentDir, 'CLAUDE.md');
|
|
@@ -192,6 +201,7 @@ export async function updateCommand(options) {
|
|
|
192
201
|
if (updateStandards) logger.dim(' ✓ .morph/standards/');
|
|
193
202
|
logger.dim(' ✓ .morph/config/agents.json');
|
|
194
203
|
logger.dim(' ✓ .claude/commands/ and .claude/skills/');
|
|
204
|
+
logger.dim(' ✓ .claude/settings.local.json (agent-teams hooks)');
|
|
195
205
|
logger.dim(' ✓ CLAUDE.md');
|
|
196
206
|
logger.blank();
|
|
197
207
|
logger.info('Your config.json was preserved.');
|
|
@@ -30,7 +30,7 @@ const PHASE_ORDER = ['proposal', 'setup', 'uiux', 'design', 'clarify', 'tasks',
|
|
|
30
30
|
/**
|
|
31
31
|
* Get the next phase after the current one
|
|
32
32
|
*/
|
|
33
|
-
function getNextPhase(currentPhase, feature, skipOptional) {
|
|
33
|
+
function getNextPhase(currentPhase, feature, skipOptional, featureName) {
|
|
34
34
|
// Load workflow config if workflow is set
|
|
35
35
|
let workflowConfig = null;
|
|
36
36
|
if (feature.workflow && feature.workflow !== 'auto') {
|
|
@@ -80,7 +80,7 @@ function getNextPhase(currentPhase, feature, skipOptional) {
|
|
|
80
80
|
const condition = workflowConfig.phases.skipIfCondition[candidate];
|
|
81
81
|
if (condition) {
|
|
82
82
|
// Evaluate condition (simple conditions for now)
|
|
83
|
-
if (condition === '!hasUIAgents' && !hasUIAgentsActive(
|
|
83
|
+
if (condition === '!hasUIAgents' && !hasUIAgentsActive(process.cwd(), featureName)) {
|
|
84
84
|
console.log(chalk.gray(` ⏩ Skipping ${candidate}: no UI agents active`));
|
|
85
85
|
continue;
|
|
86
86
|
}
|
|
@@ -145,7 +145,7 @@ export async function advancePhaseCommand(feature, options = {}) {
|
|
|
145
145
|
console.log(chalk.gray('Workflow:'), featureData.workflow || 'auto');
|
|
146
146
|
|
|
147
147
|
// Determine next phase
|
|
148
|
-
const nextPhase = getNextPhase(currentPhase, featureData, options.skipOptional);
|
|
148
|
+
const nextPhase = getNextPhase(currentPhase, featureData, options.skipOptional, feature);
|
|
149
149
|
|
|
150
150
|
if (!nextPhase) {
|
|
151
151
|
console.log(chalk.green('\n✓ Feature is at the final phase!'));
|
|
@@ -304,7 +304,7 @@ export async function advancePhaseCommand(feature, options = {}) {
|
|
|
304
304
|
|
|
305
305
|
// Gate: Check design system when advancing to implement with UI agents
|
|
306
306
|
if (nextPhase === 'implement') {
|
|
307
|
-
const gateResult = designSystemGate(feature);
|
|
307
|
+
const gateResult = designSystemGate(feature, process.cwd());
|
|
308
308
|
|
|
309
309
|
if (gateResult.blocked) {
|
|
310
310
|
console.log(chalk.red(`\n✗ ${gateResult.message}`));
|
|
@@ -327,6 +327,21 @@ export async function advancePhaseCommand(feature, options = {}) {
|
|
|
327
327
|
state.features[feature].updatedAt = new Date().toISOString();
|
|
328
328
|
saveState(state);
|
|
329
329
|
|
|
330
|
+
// Run PhaseAdvanced agent-teams hook (non-blocking)
|
|
331
|
+
try {
|
|
332
|
+
const { executeHook, formatHookResults } = await import('../../lib/hooks/hook-executor.js');
|
|
333
|
+
const hookResult = await executeHook(process.cwd(), feature, 'PhaseAdvanced', {
|
|
334
|
+
fromPhase: currentPhase,
|
|
335
|
+
toPhase: nextPhase
|
|
336
|
+
});
|
|
337
|
+
if (!hookResult.passed && hookResult.errors.length > 0) {
|
|
338
|
+
const output = formatHookResults(hookResult, 'PhaseAdvanced');
|
|
339
|
+
console.log(output);
|
|
340
|
+
}
|
|
341
|
+
} catch {
|
|
342
|
+
// Hook executor unavailable — non-blocking
|
|
343
|
+
}
|
|
344
|
+
|
|
330
345
|
console.log(chalk.green(`\n✓ Advanced to ${nextPhaseDef.name}`));
|
|
331
346
|
|
|
332
347
|
// Show what's needed in the new phase
|
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* CLI wrapper for state management operations
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
import { readFileSync, existsSync } from 'fs';
|
|
6
8
|
import ora from 'ora';
|
|
7
9
|
import chalk from 'chalk';
|
|
8
10
|
import { logger } from '../../utils/logger.js';
|
|
@@ -77,10 +79,30 @@ async function initCommand(options) {
|
|
|
77
79
|
|
|
78
80
|
const spinner = ora('Initializing state.json...').start();
|
|
79
81
|
|
|
82
|
+
// Read project name and stack from config.json if not provided via options
|
|
83
|
+
let projectName = options.project;
|
|
84
|
+
let projectType = options.type;
|
|
85
|
+
if (!projectName || !projectType) {
|
|
86
|
+
const configPath = join(process.cwd(), '.morph', 'config', 'config.json');
|
|
87
|
+
if (existsSync(configPath)) {
|
|
88
|
+
try {
|
|
89
|
+
const config = JSON.parse(readFileSync(configPath, 'utf8'));
|
|
90
|
+
projectName = projectName || config.project?.name || 'unknown';
|
|
91
|
+
projectType = projectType || config.project?.stack || 'unknown';
|
|
92
|
+
} catch {
|
|
93
|
+
projectName = projectName || 'unknown';
|
|
94
|
+
projectType = projectType || 'unknown';
|
|
95
|
+
}
|
|
96
|
+
} else {
|
|
97
|
+
projectName = projectName || 'unknown';
|
|
98
|
+
projectType = projectType || 'unknown';
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
80
102
|
StateManager.initState({
|
|
81
103
|
force: options.force,
|
|
82
|
-
projectName
|
|
83
|
-
projectType
|
|
104
|
+
projectName,
|
|
105
|
+
projectType
|
|
84
106
|
});
|
|
85
107
|
|
|
86
108
|
spinner.succeed('State initialized!');
|
|
@@ -181,13 +203,13 @@ async function checkpointCommand(featureName, note, options) {
|
|
|
181
203
|
try {
|
|
182
204
|
const spinner = ora('Creating checkpoint...').start();
|
|
183
205
|
|
|
184
|
-
const checkpoint = StateManager.addCheckpoint(featureName, note);
|
|
206
|
+
const checkpoint = await StateManager.addCheckpoint(featureName, note);
|
|
185
207
|
|
|
186
208
|
spinner.succeed(`Checkpoint registered for ${chalk.cyan(featureName)}`);
|
|
187
209
|
logger.blank();
|
|
188
|
-
logger.dim(` ${checkpoint.note}`);
|
|
210
|
+
logger.dim(` ${checkpoint.summary?.note || note}`);
|
|
189
211
|
logger.dim(` Phase: ${checkpoint.phase}`);
|
|
190
|
-
logger.dim(` Tasks completed: ${checkpoint.completedTasks}`);
|
|
212
|
+
logger.dim(` Tasks completed: ${checkpoint.summary?.completedTasks ?? 0}`);
|
|
191
213
|
logger.blank();
|
|
192
214
|
|
|
193
215
|
} catch (error) {
|
|
@@ -208,8 +230,10 @@ async function listCommand(options) {
|
|
|
208
230
|
const features = StateManager.listFeatures();
|
|
209
231
|
|
|
210
232
|
// Project info
|
|
211
|
-
|
|
212
|
-
|
|
233
|
+
const projectName = summary.project?.name || '(unnamed)';
|
|
234
|
+
const projectType = summary.project?.type || '(unknown)';
|
|
235
|
+
logger.info(`Project: ${chalk.cyan(projectName)}`);
|
|
236
|
+
logger.info(`Type: ${chalk.cyan(projectType)}`);
|
|
213
237
|
logger.blank();
|
|
214
238
|
|
|
215
239
|
if (features.length === 0) {
|
|
@@ -232,21 +256,21 @@ async function listCommand(options) {
|
|
|
232
256
|
archived: '📦'
|
|
233
257
|
}[feature.status] || '❓';
|
|
234
258
|
|
|
235
|
-
const
|
|
236
|
-
|
|
259
|
+
const tasks = feature.tasks || {};
|
|
260
|
+
const progress = (tasks.total || 0) > 0
|
|
261
|
+
? `${tasks.completed || 0}/${tasks.total}`
|
|
237
262
|
: '0/0';
|
|
238
263
|
|
|
239
264
|
logger.info(`${statusEmoji} ${chalk.bold(name)}`);
|
|
240
|
-
logger.dim(` Phase: ${feature.phase.padEnd(16)} │ Tasks: ${progress}`);
|
|
241
|
-
logger.dim(` Agents: ${feature.activeAgents.slice(0, 5).join(', ') || 'None'}`);
|
|
265
|
+
logger.dim(` Phase: ${(feature.phase || 'unknown').padEnd(16)} │ Tasks: ${progress}`);
|
|
266
|
+
logger.dim(` Agents: ${(feature.activeAgents || []).slice(0, 5).join(', ') || 'None'}`);
|
|
242
267
|
logger.blank();
|
|
243
268
|
});
|
|
244
269
|
|
|
245
270
|
// Summary
|
|
246
271
|
logger.header('Summary:');
|
|
247
|
-
logger.info(`Total Features: ${chalk.cyan(summary.metadata.
|
|
248
|
-
logger.info(`Completed: ${chalk.cyan(summary.metadata
|
|
249
|
-
logger.info(`Estimated Cost: ${chalk.cyan(`$${summary.metadata.totalCostEstimated.toFixed(2)}/month`)}`);
|
|
272
|
+
logger.info(`Total Features: ${chalk.cyan(summary.metadata?.totalFeatures ?? features.length)}`);
|
|
273
|
+
logger.info(`Completed: ${chalk.cyan(summary.metadata?.completedFeatures ?? 0)}`);
|
|
250
274
|
logger.blank();
|
|
251
275
|
|
|
252
276
|
} catch (error) {
|
|
@@ -9,7 +9,7 @@ import { dirname, join } from 'path';
|
|
|
9
9
|
import chalk from 'chalk';
|
|
10
10
|
|
|
11
11
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
12
|
-
const taskManagerPath = join(__dirname, '..', '..', 'bin', 'task-manager.cjs');
|
|
12
|
+
const taskManagerPath = join(__dirname, '..', '..', '..', 'bin', 'task-manager.cjs');
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Execute task-manager.js with given arguments
|
|
@@ -53,7 +53,7 @@ const THREAD_TYPE_INFO = {
|
|
|
53
53
|
};
|
|
54
54
|
|
|
55
55
|
export async function threadTemplateListCommand(options) {
|
|
56
|
-
console.log(chalk.cyan('\n Thread Types
|
|
56
|
+
console.log(chalk.cyan('\n Thread Types\n'));
|
|
57
57
|
console.log(' ' + '─'.repeat(70));
|
|
58
58
|
|
|
59
59
|
for (const [type, info] of Object.entries(THREAD_TYPE_INFO)) {
|
|
@@ -188,7 +188,7 @@ async function ensureFeature(featureName, options = {}) {
|
|
|
188
188
|
proposal: { created: false, path: `.morph/project/outputs/${featureName}/proposal.md` },
|
|
189
189
|
spec: { created: false, path: `.morph/project/outputs/${featureName}/spec.md` },
|
|
190
190
|
contracts: { created: false, path: `.morph/project/outputs/${featureName}/contracts.cs` },
|
|
191
|
-
tasks: { created: false, path: `.morph/project/outputs/${featureName}/tasks.
|
|
191
|
+
tasks: { created: false, path: `.morph/project/outputs/${featureName}/tasks.md` },
|
|
192
192
|
uiDesignSystem: { created: false, path: `.morph/project/outputs/${featureName}/ui-design-system.md` },
|
|
193
193
|
uiMockups: { created: false, path: `.morph/project/outputs/${featureName}/ui-mockups.md` },
|
|
194
194
|
uiComponents: { created: false, path: `.morph/project/outputs/${featureName}/ui-components.md` },
|
|
@@ -294,10 +294,15 @@ export async function addCheckpoint(featureName, note) {
|
|
|
294
294
|
const feature = state.features[featureName];
|
|
295
295
|
|
|
296
296
|
const checkpoint = {
|
|
297
|
+
passed: true,
|
|
298
|
+
checkpointNum: feature.checkpoints.length + 1,
|
|
297
299
|
timestamp: new Date().toISOString(),
|
|
298
300
|
phase: feature.phase,
|
|
299
|
-
|
|
300
|
-
|
|
301
|
+
results: [],
|
|
302
|
+
summary: {
|
|
303
|
+
note: note,
|
|
304
|
+
completedTasks: feature.tasks.completed
|
|
305
|
+
}
|
|
301
306
|
};
|
|
302
307
|
|
|
303
308
|
feature.checkpoints.push(checkpoint);
|
|
@@ -393,21 +398,20 @@ export async function markOutput(featureName, outputType) {
|
|
|
393
398
|
}
|
|
394
399
|
|
|
395
400
|
/**
|
|
396
|
-
* Sync
|
|
401
|
+
* Sync progress counters from taskList array into feature.progress
|
|
397
402
|
* @param {Object} feature - Feature object
|
|
398
403
|
*/
|
|
399
404
|
function syncTasksCount(feature) {
|
|
400
|
-
|
|
401
|
-
if (
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
}
|
|
405
|
+
const list = feature.taskList;
|
|
406
|
+
if (!Array.isArray(list) || list.length === 0) return;
|
|
407
|
+
const completed = list.filter(t => t.status === 'completed').length;
|
|
408
|
+
feature.progress = {
|
|
409
|
+
total: list.length,
|
|
410
|
+
completed,
|
|
411
|
+
inProgress: list.filter(t => t.status === 'in_progress').length,
|
|
412
|
+
pending: list.filter(t => t.status === 'pending').length,
|
|
413
|
+
percentage: Math.round((completed / list.length) * 100)
|
|
414
|
+
};
|
|
411
415
|
}
|
|
412
416
|
|
|
413
417
|
/**
|
|
@@ -36,7 +36,7 @@ export function loadTemplateRegistry(projectPath = null) {
|
|
|
36
36
|
// Default to framework registry
|
|
37
37
|
const registryPath = projectPath
|
|
38
38
|
? join(projectPath, 'framework/templates/REGISTRY.json')
|
|
39
|
-
: join(__dirname, '
|
|
39
|
+
: join(__dirname, '../../../framework/templates/REGISTRY.json');
|
|
40
40
|
|
|
41
41
|
if (!existsSync(registryPath)) {
|
|
42
42
|
throw new Error(`Template registry not found: ${registryPath}`);
|