@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.
Files changed (209) hide show
  1. package/CLAUDE.md +155 -0
  2. package/bin/morph-spec.js +3 -3
  3. package/bin/task-manager.cjs +102 -14
  4. package/package.json +2 -1
  5. package/src/commands/agents/agents-fuse.js +2 -1
  6. package/src/commands/project/detect-agents.js +31 -1
  7. package/src/commands/project/detect.js +11 -1
  8. package/src/commands/project/doctor.js +76 -70
  9. package/src/commands/project/init.js +9 -2
  10. package/src/commands/project/update.js +12 -2
  11. package/src/commands/state/advance-phase.js +19 -4
  12. package/src/commands/state/state.js +38 -14
  13. package/src/commands/tasks/task.js +1 -1
  14. package/src/commands/threads/thread-template.js +1 -1
  15. package/src/core/state/state-manager.js +19 -15
  16. package/src/core/templates/template-registry.js +1 -1
  17. package/src/core/workflows/workflow-detector.js +16 -3
  18. package/src/lib/checkpoints/checkpoint-hooks.js +8 -3
  19. package/src/lib/detectors/index.js +1 -1
  20. package/src/lib/detectors/standards-generator.js +77 -17
  21. package/src/lib/detectors/structure-detector.js +67 -39
  22. package/src/lib/generators/recap-generator.js +30 -10
  23. package/src/lib/validators/validation-runner.js +8 -24
  24. package/src/utils/hooks-installer.js +69 -0
  25. package/stacks/blazor-azure/.claude/commands/morph-apply.md +221 -0
  26. package/stacks/blazor-azure/.claude/commands/morph-archive.md +79 -0
  27. package/stacks/blazor-azure/.claude/commands/morph-deploy.md +529 -0
  28. package/stacks/blazor-azure/.claude/commands/morph-infra.md +209 -0
  29. package/stacks/blazor-azure/.claude/commands/morph-preflight.md +227 -0
  30. package/stacks/blazor-azure/.claude/commands/morph-proposal.md +122 -0
  31. package/stacks/blazor-azure/.claude/commands/morph-status.md +86 -0
  32. package/stacks/blazor-azure/.claude/commands/morph-troubleshoot.md +122 -0
  33. package/stacks/blazor-azure/.morph/.morphversion +5 -5
  34. package/stacks/blazor-azure/.morph/archive/.gitkeep +25 -0
  35. package/stacks/blazor-azure/.morph/config/config.json +9 -0
  36. package/stacks/blazor-azure/.morph/features/.gitkeep +25 -0
  37. package/stacks/blazor-azure/.morph/project/context/README.md +17 -0
  38. package/stacks/blazor-azure/.morph/schemas/agent.schema.json +296 -0
  39. package/stacks/blazor-azure/.morph/schemas/tasks.schema.json +220 -0
  40. package/stacks/blazor-azure/.morph/specs/.gitkeep +20 -0
  41. package/stacks/blazor-azure/.morph/standards/ai-agents/blazor-ui.md +364 -0
  42. package/stacks/blazor-azure/.morph/standards/ai-agents/production.md +415 -0
  43. package/stacks/blazor-azure/.morph/standards/ai-agents/setup.md +418 -0
  44. package/stacks/blazor-azure/.morph/standards/ai-agents/team-orchestration.md +479 -0
  45. package/stacks/blazor-azure/.morph/standards/ai-agents/workflows.md +354 -0
  46. package/stacks/blazor-azure/.morph/standards/architecture/ddd/aggregates.md +120 -0
  47. package/stacks/blazor-azure/.morph/standards/architecture/ddd/entities.md +99 -0
  48. package/stacks/blazor-azure/.morph/standards/architecture/ddd/value-objects.md +124 -0
  49. package/stacks/blazor-azure/.morph/standards/backend/api/minimal-api.md +494 -0
  50. package/stacks/blazor-azure/.morph/standards/backend/api/rest.md +492 -0
  51. package/stacks/blazor-azure/.morph/standards/backend/api/validation.md +88 -0
  52. package/stacks/blazor-azure/.morph/standards/backend/authentication/passkeys.md +428 -0
  53. package/stacks/blazor-azure/.morph/standards/backend/database/ef-core.md +199 -0
  54. package/stacks/blazor-azure/.morph/standards/backend/database/migrations.md +393 -0
  55. package/stacks/blazor-azure/.morph/standards/backend/database/postgresql/database.md +352 -0
  56. package/stacks/blazor-azure/.morph/standards/backend/database/repository-patterns.md +528 -0
  57. package/stacks/blazor-azure/.morph/standards/backend/database/vector-search-rag.md +541 -0
  58. package/stacks/blazor-azure/.morph/standards/backend/dotnet/async.md +366 -0
  59. package/stacks/blazor-azure/.morph/standards/backend/dotnet/core.md +117 -0
  60. package/stacks/blazor-azure/.morph/standards/backend/dotnet/di.md +439 -0
  61. package/stacks/blazor-azure/.morph/standards/backend/dotnet/program-cs-checklist.md +92 -0
  62. package/stacks/blazor-azure/.morph/standards/backend/integrations/asaas/asaas-api.md +216 -0
  63. package/stacks/blazor-azure/.morph/standards/backend/integrations/clerk/clerk-auth.md +290 -0
  64. package/stacks/blazor-azure/.morph/standards/backend/integrations/hangfire/hangfire-jobs.md +350 -0
  65. package/stacks/blazor-azure/.morph/standards/backend/integrations/resend/resend-email.md +385 -0
  66. package/stacks/blazor-azure/.morph/standards/context/analytics.md +96 -0
  67. package/stacks/blazor-azure/.morph/standards/context/bundles.md +110 -0
  68. package/stacks/blazor-azure/.morph/standards/context/priming.md +78 -0
  69. package/stacks/blazor-azure/.morph/standards/core/architecture.md +185 -0
  70. package/stacks/blazor-azure/.morph/standards/core/coding.md +214 -0
  71. package/stacks/blazor-azure/.morph/standards/core/git-branching-strategy.md +403 -0
  72. package/stacks/blazor-azure/.morph/standards/core/git.md +185 -0
  73. package/stacks/blazor-azure/.morph/standards/core/testing.md +295 -0
  74. package/stacks/blazor-azure/.morph/standards/data/nosql/blob-storage.md +102 -0
  75. package/stacks/blazor-azure/.morph/standards/data/nosql/cache/redis.md +97 -0
  76. package/stacks/blazor-azure/.morph/standards/data/nosql/cosmos-db.md +118 -0
  77. package/stacks/blazor-azure/.morph/standards/data/vector-search/azure-ai-search.md +121 -0
  78. package/stacks/blazor-azure/.morph/standards/data/vector-search/rag-chunking.md +104 -0
  79. package/stacks/blazor-azure/.morph/standards/frontend/blazor/design-checklist.md +222 -0
  80. package/stacks/blazor-azure/.morph/standards/frontend/blazor/fluent-ui-setup.md +595 -0
  81. package/stacks/blazor-azure/.morph/standards/frontend/blazor/fluent-ui.md +137 -0
  82. package/stacks/blazor-azure/.morph/standards/frontend/blazor/html-conversion.md +184 -0
  83. package/stacks/blazor-azure/.morph/standards/frontend/blazor/lifecycle.md +195 -0
  84. package/stacks/blazor-azure/.morph/standards/frontend/blazor/pitfalls.md +198 -0
  85. package/stacks/blazor-azure/.morph/standards/frontend/blazor/state.md +191 -0
  86. package/stacks/blazor-azure/.morph/standards/frontend/design-system/animations.md +151 -0
  87. package/stacks/blazor-azure/.morph/standards/frontend/design-system/naming.md +64 -0
  88. package/stacks/blazor-azure/.morph/standards/frontend/nextjs/nextjs-patterns.md +198 -0
  89. package/stacks/blazor-azure/.morph/standards/infrastructure/azure/azure.md +624 -0
  90. package/stacks/blazor-azure/.morph/standards/infrastructure/azure/bicep/bicep-patterns.md +422 -0
  91. package/stacks/blazor-azure/.morph/standards/infrastructure/azure/devops/azure-devops-setup.md +516 -0
  92. package/stacks/blazor-azure/.morph/standards/infrastructure/azure/devops/local-development.md +520 -0
  93. package/stacks/blazor-azure/.morph/standards/infrastructure/azure/services/functions.md +486 -0
  94. package/stacks/blazor-azure/.morph/standards/infrastructure/azure/services/service-bus.md +459 -0
  95. package/stacks/blazor-azure/.morph/standards/infrastructure/azure/services/storage.md +407 -0
  96. package/stacks/blazor-azure/.morph/standards/infrastructure/docker/easypanel-deploy.md +196 -0
  97. package/stacks/blazor-azure/.morph/standards/infrastructure/supabase/mcp-setup.md +252 -0
  98. package/stacks/blazor-azure/.morph/standards/infrastructure/supabase/supabase-auth.md +176 -0
  99. package/stacks/blazor-azure/.morph/standards/infrastructure/supabase/supabase-pgvector.md +169 -0
  100. package/stacks/blazor-azure/.morph/standards/infrastructure/supabase/supabase-rls.md +184 -0
  101. package/stacks/blazor-azure/.morph/standards/infrastructure/supabase/supabase-storage.md +153 -0
  102. package/stacks/blazor-azure/.morph/standards/integration/api/graphql.md +91 -0
  103. package/stacks/blazor-azure/.morph/standards/integration/api/grpc.md +114 -0
  104. package/stacks/blazor-azure/.morph/standards/integration/api/rest-design.md +95 -0
  105. package/stacks/blazor-azure/.morph/standards/integration/event-driven/cqrs.md +101 -0
  106. package/stacks/blazor-azure/.morph/standards/integration/event-driven/event-sourcing.md +124 -0
  107. package/stacks/blazor-azure/.morph/standards/integration/event-driven/service-bus.md +95 -0
  108. package/stacks/blazor-azure/.morph/standards/observability/logging.md +131 -0
  109. package/stacks/blazor-azure/.morph/standards/observability/metrics.md +121 -0
  110. package/stacks/blazor-azure/.morph/standards/observability/monitoring.md +114 -0
  111. package/stacks/blazor-azure/.morph/standards/observability/tracing.md +132 -0
  112. package/stacks/blazor-azure/.morph/standards/workflows/parallel-execution.md +112 -0
  113. package/stacks/blazor-azure/.morph/standards/workflows/thread-management.md +113 -0
  114. package/stacks/blazor-azure/.morph/test-infra/example.bicep +59 -0
  115. package/stacks/blazor-azure/CLAUDE.md +106 -101
  116. package/stacks/nextjs-supabase/.claude/commands/morph-apply.md +221 -0
  117. package/stacks/nextjs-supabase/.claude/commands/morph-archive.md +79 -0
  118. package/stacks/nextjs-supabase/.claude/commands/morph-deploy.md +529 -0
  119. package/stacks/nextjs-supabase/.claude/commands/morph-infra.md +209 -0
  120. package/stacks/nextjs-supabase/.claude/commands/morph-preflight.md +227 -0
  121. package/stacks/nextjs-supabase/.claude/commands/morph-proposal.md +122 -0
  122. package/stacks/nextjs-supabase/.claude/commands/morph-status.md +86 -0
  123. package/stacks/nextjs-supabase/.claude/commands/morph-troubleshoot.md +122 -0
  124. package/stacks/nextjs-supabase/.morph/.morphversion +5 -0
  125. package/stacks/nextjs-supabase/.morph/config/agents.json +730 -127
  126. package/stacks/nextjs-supabase/.morph/config/config.json +9 -0
  127. package/stacks/nextjs-supabase/.morph/project/context/README.md +17 -0
  128. package/stacks/nextjs-supabase/.morph/standards/ai-agents/blazor-ui.md +364 -0
  129. package/stacks/nextjs-supabase/.morph/standards/ai-agents/production.md +415 -0
  130. package/stacks/nextjs-supabase/.morph/standards/ai-agents/setup.md +418 -0
  131. package/stacks/nextjs-supabase/.morph/standards/ai-agents/team-orchestration.md +479 -0
  132. package/stacks/nextjs-supabase/.morph/standards/ai-agents/workflows.md +354 -0
  133. package/stacks/nextjs-supabase/.morph/standards/architecture/ddd/aggregates.md +120 -0
  134. package/stacks/nextjs-supabase/.morph/standards/architecture/ddd/entities.md +99 -0
  135. package/stacks/nextjs-supabase/.morph/standards/architecture/ddd/value-objects.md +124 -0
  136. package/stacks/nextjs-supabase/.morph/standards/backend/api/minimal-api.md +494 -0
  137. package/stacks/nextjs-supabase/.morph/standards/backend/api/rest.md +492 -0
  138. package/stacks/nextjs-supabase/.morph/standards/backend/api/validation.md +88 -0
  139. package/stacks/nextjs-supabase/.morph/standards/backend/authentication/passkeys.md +428 -0
  140. package/stacks/nextjs-supabase/.morph/standards/backend/database/ef-core.md +199 -0
  141. package/stacks/nextjs-supabase/.morph/standards/backend/database/migrations.md +393 -0
  142. package/stacks/nextjs-supabase/.morph/standards/backend/database/postgresql/database.md +352 -0
  143. package/stacks/nextjs-supabase/.morph/standards/backend/database/repository-patterns.md +528 -0
  144. package/stacks/nextjs-supabase/.morph/standards/backend/database/vector-search-rag.md +541 -0
  145. package/stacks/nextjs-supabase/.morph/standards/backend/dotnet/async.md +366 -0
  146. package/stacks/nextjs-supabase/.morph/standards/backend/dotnet/core.md +117 -0
  147. package/stacks/nextjs-supabase/.morph/standards/backend/dotnet/di.md +439 -0
  148. package/stacks/nextjs-supabase/.morph/standards/backend/dotnet/program-cs-checklist.md +92 -0
  149. package/stacks/nextjs-supabase/.morph/standards/backend/integrations/asaas/asaas-api.md +216 -0
  150. package/stacks/nextjs-supabase/.morph/standards/backend/integrations/clerk/clerk-auth.md +290 -0
  151. package/stacks/nextjs-supabase/.morph/standards/backend/integrations/hangfire/hangfire-jobs.md +350 -0
  152. package/stacks/nextjs-supabase/.morph/standards/backend/integrations/resend/resend-email.md +385 -0
  153. package/stacks/nextjs-supabase/.morph/standards/context/analytics.md +96 -0
  154. package/stacks/nextjs-supabase/.morph/standards/context/bundles.md +110 -0
  155. package/stacks/nextjs-supabase/.morph/standards/context/priming.md +78 -0
  156. package/stacks/nextjs-supabase/.morph/standards/core/architecture.md +185 -0
  157. package/stacks/nextjs-supabase/.morph/standards/core/coding.md +214 -0
  158. package/stacks/nextjs-supabase/.morph/standards/core/git-branching-strategy.md +403 -0
  159. package/stacks/nextjs-supabase/.morph/standards/core/git.md +185 -0
  160. package/stacks/nextjs-supabase/.morph/standards/core/testing.md +295 -0
  161. package/stacks/nextjs-supabase/.morph/standards/data/nosql/blob-storage.md +102 -0
  162. package/stacks/nextjs-supabase/.morph/standards/data/nosql/cache/redis.md +97 -0
  163. package/stacks/nextjs-supabase/.morph/standards/data/nosql/cosmos-db.md +118 -0
  164. package/stacks/nextjs-supabase/.morph/standards/data/vector-search/azure-ai-search.md +121 -0
  165. package/stacks/nextjs-supabase/.morph/standards/data/vector-search/rag-chunking.md +104 -0
  166. package/stacks/nextjs-supabase/.morph/standards/frontend/blazor/design-checklist.md +222 -0
  167. package/stacks/nextjs-supabase/.morph/standards/frontend/blazor/fluent-ui-setup.md +595 -0
  168. package/stacks/nextjs-supabase/.morph/standards/frontend/blazor/fluent-ui.md +137 -0
  169. package/stacks/nextjs-supabase/.morph/standards/frontend/blazor/html-conversion.md +184 -0
  170. package/stacks/nextjs-supabase/.morph/standards/frontend/blazor/lifecycle.md +195 -0
  171. package/stacks/nextjs-supabase/.morph/standards/frontend/blazor/pitfalls.md +198 -0
  172. package/stacks/nextjs-supabase/.morph/standards/frontend/blazor/state.md +191 -0
  173. package/stacks/nextjs-supabase/.morph/standards/frontend/design-system/animations.md +151 -0
  174. package/stacks/nextjs-supabase/.morph/standards/frontend/design-system/naming.md +64 -0
  175. package/stacks/nextjs-supabase/.morph/standards/frontend/nextjs/nextjs-patterns.md +198 -0
  176. package/stacks/nextjs-supabase/.morph/standards/infrastructure/azure/azure.md +624 -0
  177. package/stacks/nextjs-supabase/.morph/standards/infrastructure/azure/bicep/bicep-patterns.md +422 -0
  178. package/stacks/nextjs-supabase/.morph/standards/infrastructure/azure/devops/azure-devops-setup.md +516 -0
  179. package/stacks/nextjs-supabase/.morph/standards/infrastructure/azure/devops/local-development.md +520 -0
  180. package/stacks/nextjs-supabase/.morph/standards/infrastructure/azure/services/functions.md +486 -0
  181. package/stacks/nextjs-supabase/.morph/standards/infrastructure/azure/services/service-bus.md +459 -0
  182. package/stacks/nextjs-supabase/.morph/standards/infrastructure/azure/services/storage.md +407 -0
  183. package/stacks/nextjs-supabase/.morph/standards/infrastructure/docker/easypanel-deploy.md +196 -0
  184. package/stacks/nextjs-supabase/.morph/standards/infrastructure/supabase/mcp-setup.md +252 -0
  185. package/stacks/nextjs-supabase/.morph/standards/infrastructure/supabase/supabase-auth.md +176 -0
  186. package/stacks/nextjs-supabase/.morph/standards/infrastructure/supabase/supabase-pgvector.md +169 -0
  187. package/stacks/nextjs-supabase/.morph/standards/infrastructure/supabase/supabase-rls.md +184 -0
  188. package/stacks/nextjs-supabase/.morph/standards/infrastructure/supabase/supabase-storage.md +153 -0
  189. package/stacks/nextjs-supabase/.morph/standards/integration/api/graphql.md +91 -0
  190. package/stacks/nextjs-supabase/.morph/standards/integration/api/grpc.md +114 -0
  191. package/stacks/nextjs-supabase/.morph/standards/integration/api/rest-design.md +95 -0
  192. package/stacks/nextjs-supabase/.morph/standards/integration/event-driven/cqrs.md +101 -0
  193. package/stacks/nextjs-supabase/.morph/standards/integration/event-driven/event-sourcing.md +124 -0
  194. package/stacks/nextjs-supabase/.morph/standards/integration/event-driven/service-bus.md +95 -0
  195. package/stacks/nextjs-supabase/.morph/standards/observability/logging.md +131 -0
  196. package/stacks/nextjs-supabase/.morph/standards/observability/metrics.md +121 -0
  197. package/stacks/nextjs-supabase/.morph/standards/observability/monitoring.md +114 -0
  198. package/stacks/nextjs-supabase/.morph/standards/observability/tracing.md +132 -0
  199. package/stacks/nextjs-supabase/.morph/standards/workflows/parallel-execution.md +112 -0
  200. package/stacks/nextjs-supabase/.morph/standards/workflows/thread-management.md +113 -0
  201. package/stacks/nextjs-supabase/CLAUDE.md +69 -63
  202. package/stacks/blazor-azure/.morph/templates/.gitkeep +0 -0
  203. package/stacks/blazor-azure/.morph/templates/infrastructure/github/workflows/cd-prod.yml.hbs +0 -41
  204. package/stacks/blazor-azure/.morph/templates/infrastructure/github/workflows/cd-staging.yml.hbs +0 -24
  205. package/stacks/blazor-azure/.morph/templates/infrastructure/github/workflows/ci-build.yml.hbs +0 -23
  206. package/stacks/nextjs-supabase/.morph/templates/.gitkeep +0 -0
  207. package/stacks/nextjs-supabase/.morph/templates/infrastructure/github/workflows/cd-prod.yml.hbs +0 -22
  208. package/stacks/nextjs-supabase/.morph/templates/infrastructure/github/workflows/cd-staging.yml.hbs +0 -22
  209. 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 V3_LIB_FILES = [
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
- // v3.0 command files (top-level new commands)
75
- const V3_COMMAND_FILES = [
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
- // v3.0 HOP templates (meta-prompts)
89
- const V3_HOP_TEMPLATES = [
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/meta-prompts/REGISTRY.json'
101
+ 'framework/templates/REGISTRY.json'
102
102
  ];
103
103
 
104
- // v3.0 new standards (framework-level)
105
- const V3_STANDARDS = [
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
- // v3.0 new agents expected in agents.json
132
- const V3_NEW_AGENTS = [
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 v3.0-specific health checks
140
+ * Run full health checks
141
141
  */
142
- async function doctorV3Command(frameworkRoot) {
143
- console.log(chalk.bold('\n🔬 MORPH-SPEC v3.0 Health Check\n'));
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. v3.0 Lib Files (15) ──────────────────────────────────────────────
161
- console.log(chalk.cyan('\n src/lib/ — v3.0 Core Libraries (15 files)'));
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 V3_LIB_FILES) {
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(`v3.0 lib files (${V3_LIB_FILES.length - missingLibs.length}/${V3_LIB_FILES.length})`,
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. v3.0 Command Files (11) ──────────────────────────────────────────
171
- console.log(chalk.cyan('\n src/commands/ — v3.0 Command Files (11 files)'));
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 V3_COMMAND_FILES) {
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(`v3.0 command files (${V3_COMMAND_FILES.length - missingCmds.length}/${V3_COMMAND_FILES.length})`,
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 (12) ───────────────────────────────────────────────
181
- console.log(chalk.cyan('\n framework/templates/meta-prompts/ — HOP Templates (12)'));
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 V3_HOP_TEMPLATES) {
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 templates (${V3_HOP_TEMPLATES.length - missingHOPs.length}/${V3_HOP_TEMPLATES.length})`,
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. New Standards (23) ───────────────────────────────────────────────
191
- console.log(chalk.cyan('\n framework/standards/ — v3.0 Standards (23 files)'));
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 V3_STANDARDS) {
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(`v3.0 standards (${V3_STANDARDS.length - missingStds.length}/${V3_STANDARDS.length})`,
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. New Agents in agents.json ────────────────────────────────────────
201
- console.log(chalk.cyan('\n .morph/config/agents.json — v3.0 Agents (4 new)'));
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 = V3_NEW_AGENTS.filter(id => !agents[id]);
208
- check(`v3.0 agents (${V3_NEW_AGENTS.length - missingAgents.length}/${V3_NEW_AGENTS.length})`,
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 v3.0 version ──────────────────────────────────────────
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 isV3 = state.version === '3.0.0';
230
- check(`state.json schema (v${state.version})`, isV3, true,
231
- isV3 ? '' : 'run: morph-spec migrate v2-to-v3');
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 — run "morph-spec migrate v2-to-v3" to fix\n`));
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 v3.0 checks passed!\n`));
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
- // v3-specific check mode
268
- if (options.v3) {
267
+ // full health check mode
268
+ if (options.full) {
269
269
  const frameworkRoot = process.cwd();
270
- return doctorV3Command(frameworkRoot);
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
- const codingStd = join(standardsPath, 'coding.md');
398
- const archStd = join(standardsPath, 'architecture.md');
399
- const azureStd = join(standardsPath, 'azure.md');
400
-
401
- const hasAll = await Promise.all([
402
- pathExists(codingStd),
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: 'some files missing' });
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 keyTemplates = ['proposal.md', 'spec.md', 'tasks.md', 'decisions.md'];
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
- const templatePath = join(templatesPath, template);
495
- if (!(await pathExists(templatePath))) {
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(contentDir, '.claude');
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(contentDir, '.claude');
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(feature)) {
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: options.project || '{PROJECT_NAME}',
83
- projectType: options.type || 'blazor-server'
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
- logger.info(`Project: ${chalk.cyan(summary.project.name)}`);
212
- logger.info(`Type: ${chalk.cyan(summary.project.type)}`);
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 progress = feature.tasks.total > 0
236
- ? `${feature.tasks.completed}/${feature.tasks.total}`
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.totalFeatures)}`);
248
- logger.info(`Completed: ${chalk.cyan(summary.metadata.completedFeatures)}`);
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 (v3.0)\n'));
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.json` },
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
- completedTasks: feature.tasks.completed,
300
- note: note
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 tasks count from tasks array (if exists)
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
- // If feature has tasks array (schema 3.0), count them
401
- if (feature.tasks && Array.isArray(feature.tasks)) {
402
- const tasks = feature.tasks;
403
- feature.progress = {
404
- total: tasks.length,
405
- completed: tasks.filter(t => t.status === 'completed').length,
406
- inProgress: tasks.filter(t => t.status === 'in_progress').length,
407
- pending: tasks.filter(t => t.status === 'pending').length,
408
- percentage: tasks.length > 0 ? Math.round((tasks.filter(t => t.status === 'completed').length / tasks.length) * 100) : 0
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, '../../framework/templates/REGISTRY.json');
39
+ : join(__dirname, '../../../framework/templates/REGISTRY.json');
40
40
 
41
41
  if (!existsSync(registryPath)) {
42
42
  throw new Error(`Template registry not found: ${registryPath}`);