@polymorphism-tech/morph-spec 4.3.6 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (375) hide show
  1. package/.morph/.morphversion +3 -3
  2. package/.morph/analytics/threads-log.jsonl +44 -9
  3. package/.morph/config/config.json +2 -3
  4. package/.morph/framework/standards/STANDARDS.json +812 -0
  5. package/.morph/{standards → framework/standards}/ai-agents/team-orchestration.md +3 -3
  6. package/.morph/framework/standards/integration/mcp/mcp-tools.md +384 -0
  7. package/.morph/{templates → framework/templates}/README.md +17 -17
  8. package/.morph/{templates → framework/templates}/REGISTRY.json +48 -233
  9. package/.morph/framework/templates/code/dotnet/contracts/contracts.cs.hbs +172 -0
  10. package/.morph/{templates → framework/templates}/context/CONTEXT-FEATURE.md +1 -1
  11. package/.morph/{templates → framework/templates}/context/CONTEXT.md +3 -3
  12. package/.morph/framework/templates/docs/clarifications.md +253 -0
  13. package/.morph/framework/templates/docs/onboarding.md +123 -0
  14. package/.morph/framework/templates/docs/schema-analysis.md +119 -0
  15. package/.morph/{templates → framework/templates}/docs/spec.md +149 -149
  16. package/.morph/framework/templates/docs/ui-components.md +124 -0
  17. package/.morph/framework/templates/docs/ui-design-system.md +76 -0
  18. package/.morph/framework/templates/docs/ui-flows.md +167 -0
  19. package/.morph/framework/templates/docs/ui-mockups.md +98 -0
  20. package/.morph/{templates → framework/templates}/examples/spec-examples.md +1 -1
  21. package/.morph/{templates → framework/templates}/infrastructure/github/README.md +11 -11
  22. package/.morph/{templates → framework/templates}/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs +2 -2
  23. package/.morph/{templates → framework/templates}/meta-prompts/parallel-workers/parallel-worker.md +2 -2
  24. package/.morph/{templates → framework/templates}/meta-prompts/validators/pre-commit-validator.md +1 -1
  25. package/.morph/logs/tool-failures.log +51 -0
  26. package/.morph/memory/pre-compact-2026-02-22T17-01-01-658Z.json +16 -0
  27. package/.morph/state.json +1 -1
  28. package/CLAUDE.md +20 -119
  29. package/README.md +20 -18
  30. package/bin/detect-agents.js +1 -1
  31. package/bin/morph-spec.js +116 -266
  32. package/bin/task-manager.cjs +2 -2
  33. package/bin/validate.js +1 -1
  34. package/claude-plugin.json +14 -0
  35. package/docs/claude-alignment-report.md +137 -0
  36. package/docs/plans/2026-02-22-claude-docs-morph-alignment-analysis.md +512 -0
  37. package/docs/plans/2026-02-22-claude-settings.md +515 -0
  38. package/docs/plans/2026-02-22-morph-cc-alignment-impl.md +728 -0
  39. package/docs/plans/2026-02-22-morph-spec-next.md +478 -0
  40. package/docs/plans/2026-02-22-native-alignment-design.md +199 -0
  41. package/docs/plans/2026-02-22-native-alignment-impl.md +925 -0
  42. package/docs/plans/2026-02-22-native-enrichment-design.md +244 -0
  43. package/docs/plans/2026-02-22-native-enrichment.md +735 -0
  44. package/framework/CLAUDE.md +77 -0
  45. package/framework/commands/morph-apply.md +9 -9
  46. package/framework/commands/morph-archive.md +8 -8
  47. package/framework/commands/morph-infra.md +1 -1
  48. package/framework/commands/morph-proposal.md +9 -9
  49. package/framework/commands/morph-status.md +3 -3
  50. package/framework/commands/morph-troubleshoot.md +1 -1
  51. package/framework/hooks/README.md +201 -282
  52. package/framework/hooks/claude-code/notification/approval-reminder.js +52 -0
  53. package/framework/hooks/claude-code/post-tool-use/dispatch.js +83 -0
  54. package/framework/hooks/claude-code/post-tool-use/handle-tool-failure.js +42 -0
  55. package/framework/hooks/claude-code/pre-compact/save-morph-context.js +61 -0
  56. package/framework/hooks/claude-code/pre-tool-use/enforce-phase-writes.js +71 -0
  57. package/framework/hooks/claude-code/pre-tool-use/protect-readonly-files.js +58 -0
  58. package/framework/hooks/claude-code/pre-tool-use/protect-spec-files.js +64 -0
  59. package/framework/hooks/claude-code/session-start/inject-morph-context.js +94 -0
  60. package/framework/hooks/claude-code/statusline.py +239 -0
  61. package/framework/hooks/claude-code/statusline.sh +7 -0
  62. package/framework/hooks/claude-code/stop/validate-completion.js +88 -0
  63. package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +91 -0
  64. package/framework/hooks/shared/hook-response.js +45 -0
  65. package/framework/hooks/shared/phase-utils.js +129 -0
  66. package/framework/hooks/shared/state-reader.js +138 -0
  67. package/framework/hooks/shared/stdin-reader.js +26 -0
  68. package/framework/phases.json +145 -0
  69. package/framework/rules/csharp-standards.md +10 -0
  70. package/framework/rules/frontend-standards.md +14 -0
  71. package/framework/rules/infrastructure-standards.md +13 -0
  72. package/framework/rules/morph-workflow.md +86 -0
  73. package/framework/rules/testing-standards.md +11 -0
  74. package/framework/skills/level-0-meta/brainstorming.md +133 -0
  75. package/framework/skills/level-0-meta/code-review.md +12 -4
  76. package/framework/skills/level-0-meta/mcp-registry.json +207 -0
  77. package/framework/skills/level-0-meta/morph-checklist.md +9 -1
  78. package/framework/skills/level-0-meta/simulation-checklist.md +9 -1
  79. package/framework/skills/level-0-meta/tool-usage-guide.md +335 -0
  80. package/framework/skills/level-0-meta/verification-before-completion.md +145 -0
  81. package/framework/skills/level-1-workflows/morph-replicate.md +9 -1
  82. package/framework/skills/level-1-workflows/phase-clarify.md +65 -4
  83. package/framework/skills/level-1-workflows/phase-codebase-analysis.md +182 -0
  84. package/framework/skills/level-1-workflows/phase-design.md +342 -80
  85. package/framework/skills/level-1-workflows/phase-implement.md +254 -0
  86. package/framework/skills/level-1-workflows/phase-setup.md +76 -10
  87. package/framework/skills/level-1-workflows/phase-tasks.md +88 -7
  88. package/framework/skills/level-1-workflows/phase-uiux.md +95 -17
  89. package/framework/skills/level-2-domains/ai-agents/ai-system-architect.md +8 -1
  90. package/framework/skills/level-2-domains/architecture/po-pm-advisor.md +8 -1
  91. package/framework/skills/level-2-domains/architecture/prompt-engineer.md +8 -1
  92. package/framework/skills/level-2-domains/architecture/seo-growth-hacker.md +8 -1
  93. package/framework/skills/level-2-domains/architecture/standards-architect.md +11 -4
  94. package/framework/skills/level-2-domains/backend/api-designer.md +8 -1
  95. package/framework/skills/level-2-domains/backend/dotnet-senior.md +8 -1
  96. package/framework/skills/level-2-domains/backend/ef-modeler.md +8 -1
  97. package/framework/skills/level-2-domains/backend/hangfire-orchestrator.md +9 -2
  98. package/framework/skills/level-2-domains/backend/ms-agent-expert.md +8 -1
  99. package/framework/skills/level-2-domains/frontend/blazor-builder.md +8 -1
  100. package/framework/skills/level-2-domains/frontend/nextjs-expert.md +8 -1
  101. package/framework/skills/level-2-domains/frontend/ui-ux-designer.md +9 -2
  102. package/framework/skills/level-2-domains/infrastructure/azure-architect.md +8 -1
  103. package/framework/skills/level-2-domains/infrastructure/azure-deploy-specialist.md +8 -1
  104. package/framework/skills/level-2-domains/infrastructure/bicep-architect.md +8 -1
  105. package/framework/skills/level-2-domains/infrastructure/container-specialist.md +8 -1
  106. package/framework/skills/level-2-domains/infrastructure/devops-engineer.md +8 -1
  107. package/framework/skills/level-2-domains/integrations/asaas-financial.md +8 -1
  108. package/framework/skills/level-2-domains/integrations/azure-identity.md +8 -1
  109. package/framework/skills/level-2-domains/integrations/clerk-auth.md +8 -1
  110. package/framework/skills/level-2-domains/integrations/{hangfire-orchestrator.md → hangfire-integration.md} +8 -1
  111. package/framework/skills/level-2-domains/integrations/resend-email.md +8 -1
  112. package/framework/skills/level-2-domains/quality/code-analyzer.md +10 -3
  113. package/framework/skills/level-2-domains/quality/testing-specialist.md +8 -1
  114. package/framework/standards/STANDARDS.json +812 -0
  115. package/framework/standards/ai-agents/team-orchestration.md +3 -3
  116. package/framework/standards/frontend/nextjs/nextjs-patterns.md +17 -0
  117. package/framework/standards/integration/mcp/mcp-tools.md +384 -0
  118. package/framework/templates/README.md +17 -17
  119. package/framework/templates/REGISTRY.json +48 -233
  120. package/framework/templates/code/dotnet/contracts/contracts.cs.hbs +172 -0
  121. package/framework/templates/context/CONTEXT-FEATURE.md +1 -1
  122. package/framework/templates/context/CONTEXT.md +3 -3
  123. package/framework/templates/docs/clarifications.md +253 -0
  124. package/framework/templates/docs/onboarding.md +123 -0
  125. package/framework/templates/docs/schema-analysis.md +119 -0
  126. package/framework/templates/docs/spec.md +149 -149
  127. package/framework/templates/docs/ui-components.md +124 -0
  128. package/framework/templates/docs/ui-design-system.md +76 -0
  129. package/framework/templates/docs/ui-flows.md +167 -0
  130. package/framework/templates/docs/ui-mockups.md +98 -0
  131. package/framework/templates/docs/user-stories.md +34 -0
  132. package/framework/templates/examples/spec-examples.md +1 -1
  133. package/framework/templates/infrastructure/github/README.md +11 -11
  134. package/framework/templates/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs +2 -2
  135. package/framework/templates/meta-prompts/parallel-workers/parallel-worker.md +2 -2
  136. package/framework/templates/meta-prompts/validators/pre-commit-validator.md +1 -1
  137. package/framework/workflows/configs/express.json +45 -0
  138. package/framework/workflows/configs/spec-only.json +43 -0
  139. package/framework/workflows/docs/enforcement-pipeline.md +8 -8
  140. package/framework/workflows/docs/full-morph.md +3 -3
  141. package/package.json +3 -2
  142. package/scripts/generate-refs.js +336 -0
  143. package/scripts/generate-standards-registry.js +44 -0
  144. package/scripts/validate-real.mjs +255 -0
  145. package/src/commands/feature/create-story.js +362 -361
  146. package/src/commands/feature/shard-spec.js +225 -224
  147. package/src/commands/feature/sprint-status.js +1 -1
  148. package/src/commands/generation/generate-onboarding.js +169 -0
  149. package/src/commands/generation/generate.js +2 -2
  150. package/src/commands/mcp/mcp-setup.js +315 -0
  151. package/src/commands/project/changes.js +66 -0
  152. package/src/commands/project/checkpoint.js +209 -0
  153. package/src/commands/project/cost.js +179 -0
  154. package/src/commands/project/diff.js +278 -0
  155. package/src/commands/project/doctor.js +55 -7
  156. package/src/commands/project/init.js +318 -76
  157. package/src/commands/project/revert.js +173 -0
  158. package/src/commands/project/standards.js +80 -0
  159. package/src/commands/project/status.js +376 -0
  160. package/src/commands/project/update-agents.js +23 -0
  161. package/src/commands/project/update.js +63 -30
  162. package/src/commands/state/advance-phase.js +4 -3
  163. package/src/commands/state/state.js +10 -3
  164. package/src/commands/state/validate-phase.js +19 -2
  165. package/src/commands/templates/template-customize.js +4 -4
  166. package/src/commands/templates/template-render.js +1 -1
  167. package/src/commands/templates/template-show.js +1 -1
  168. package/src/commands/validation/validate-feature.js +359 -0
  169. package/src/core/orchestrator.js +3 -38
  170. package/src/core/paths/output-schema.js +135 -0
  171. package/src/core/state/state-manager.js +831 -592
  172. package/src/core/templates/template-registry.js +2 -2
  173. package/src/core/workflows/workflow-detector.js +17 -1
  174. package/src/lib/agents/micro-agent-factory.js +1 -1
  175. package/src/lib/context/context-bundler.js +2 -1
  176. package/src/lib/detectors/claude-config-detector.js +392 -0
  177. package/src/lib/detectors/conversation-analyzer.js +4 -4
  178. package/src/lib/detectors/design-system-detector.js +6 -5
  179. package/src/lib/detectors/standards-generator.js +2 -2
  180. package/src/lib/generators/context-generator.js +539 -538
  181. package/src/lib/generators/recap-generator.js +1 -1
  182. package/src/lib/generators/settings-generator.js +210 -0
  183. package/src/lib/hooks/hook-executor.js +1 -1
  184. package/src/lib/installers/mcp-installer.js +299 -0
  185. package/src/lib/learning/learning-system.js +3 -3
  186. package/src/lib/orchestration/team-orchestrator.js +1 -1
  187. package/src/lib/standards/standards-context-injector.js +7 -7
  188. package/src/lib/threads/thread-coordinator.js +1 -1
  189. package/src/lib/troubleshooting/troubleshoot-grep.js +1 -1
  190. package/src/lib/validators/contracts/contract-compliance-validator.js +274 -273
  191. package/src/lib/validators/design-system/design-system-validator.js +1 -1
  192. package/src/lib/validators/spec-validator.js +258 -258
  193. package/src/lib/validators/validation-runner.js +270 -269
  194. package/src/utils/agents-installer.js +206 -0
  195. package/src/utils/claude-settings-manager.js +258 -0
  196. package/src/utils/file-copier.js +1 -1
  197. package/src/utils/hooks-installer.js +354 -28
  198. package/src/utils/skills-installer.js +74 -0
  199. package/.morph/project/context/detection-log.md +0 -16
  200. package/.morph/project/standards/inferred.md +0 -59
  201. package/framework/hooks/agent-stop/validate-and-continue.js +0 -96
  202. package/framework/hooks/agent-stop/validate-checkpoints.js +0 -101
  203. package/framework/hooks/agent-stop/validate-tests.js +0 -109
  204. package/framework/hooks/agent-teams/dispatch.js +0 -67
  205. package/framework/hooks/agent-teams/phase-advanced.js +0 -80
  206. package/framework/hooks/agent-teams/task-completed.js +0 -76
  207. package/framework/hooks/agent-teams/teammate-idle.js +0 -70
  208. package/src/commands/agents/agents-fuse.js +0 -97
  209. package/src/commands/agents/micro-agent.js +0 -112
  210. package/src/commands/agents/spawn-team.js +0 -237
  211. package/src/commands/agents/squad-template.js +0 -146
  212. package/src/commands/analytics/analytics.js +0 -176
  213. package/src/commands/context/context-prime.js +0 -63
  214. package/src/commands/context/core-four.js +0 -54
  215. package/src/commands/generation/generate-context.js +0 -40
  216. package/src/commands/project/detect-agents.js +0 -207
  217. package/src/commands/project/detect-workflow.js +0 -174
  218. package/src/commands/threads/thread-template.js +0 -103
  219. package/src/commands/threads/threads.js +0 -261
  220. package/src/commands/utils/session-summary.js +0 -291
  221. package/src/llm/analyzer.js +0 -215
  222. package/src/llm/few-shot-examples.js +0 -216
  223. package/src/llm/project-config-schema.json +0 -188
  224. package/src/llm/prompt-builder.js +0 -96
  225. /package/.morph/{project/context → context}/README.md +0 -0
  226. /package/.morph/{config → framework}/agents.json +0 -0
  227. /package/.morph/{standards → framework/standards}/ai-agents/blazor-ui.md +0 -0
  228. /package/.morph/{standards → framework/standards}/ai-agents/production.md +0 -0
  229. /package/.morph/{standards → framework/standards}/ai-agents/setup.md +0 -0
  230. /package/.morph/{standards → framework/standards}/ai-agents/workflows.md +0 -0
  231. /package/.morph/{standards → framework/standards}/architecture/ddd/aggregates.md +0 -0
  232. /package/.morph/{standards → framework/standards}/architecture/ddd/entities.md +0 -0
  233. /package/.morph/{standards → framework/standards}/architecture/ddd/value-objects.md +0 -0
  234. /package/.morph/{standards → framework/standards}/backend/api/minimal-api.md +0 -0
  235. /package/.morph/{standards → framework/standards}/backend/api/rest.md +0 -0
  236. /package/.morph/{standards → framework/standards}/backend/api/validation.md +0 -0
  237. /package/.morph/{standards → framework/standards}/backend/authentication/passkeys.md +0 -0
  238. /package/.morph/{standards → framework/standards}/backend/database/ef-core.md +0 -0
  239. /package/.morph/{standards → framework/standards}/backend/database/migrations.md +0 -0
  240. /package/.morph/{standards → framework/standards}/backend/database/postgresql/database.md +0 -0
  241. /package/.morph/{standards → framework/standards}/backend/database/repository-patterns.md +0 -0
  242. /package/.morph/{standards → framework/standards}/backend/database/vector-search-rag.md +0 -0
  243. /package/.morph/{standards → framework/standards}/backend/dotnet/async.md +0 -0
  244. /package/.morph/{standards → framework/standards}/backend/dotnet/core.md +0 -0
  245. /package/.morph/{standards → framework/standards}/backend/dotnet/di.md +0 -0
  246. /package/.morph/{standards → framework/standards}/backend/dotnet/program-cs-checklist.md +0 -0
  247. /package/.morph/{standards → framework/standards}/backend/integrations/asaas/asaas-api.md +0 -0
  248. /package/.morph/{standards → framework/standards}/backend/integrations/clerk/clerk-auth.md +0 -0
  249. /package/.morph/{standards → framework/standards}/backend/integrations/hangfire/hangfire-jobs.md +0 -0
  250. /package/.morph/{standards → framework/standards}/backend/integrations/resend/resend-email.md +0 -0
  251. /package/.morph/{standards → framework/standards}/context/analytics.md +0 -0
  252. /package/.morph/{standards → framework/standards}/context/bundles.md +0 -0
  253. /package/.morph/{standards → framework/standards}/context/priming.md +0 -0
  254. /package/.morph/{standards → framework/standards}/core/architecture.md +0 -0
  255. /package/.morph/{standards → framework/standards}/core/coding.md +0 -0
  256. /package/.morph/{standards → framework/standards}/core/git-branching-strategy.md +0 -0
  257. /package/.morph/{standards → framework/standards}/core/git.md +0 -0
  258. /package/.morph/{standards → framework/standards}/core/testing.md +0 -0
  259. /package/.morph/{standards → framework/standards}/data/nosql/blob-storage.md +0 -0
  260. /package/.morph/{standards → framework/standards}/data/nosql/cache/redis.md +0 -0
  261. /package/.morph/{standards → framework/standards}/data/nosql/cosmos-db.md +0 -0
  262. /package/.morph/{standards → framework/standards}/data/vector-search/azure-ai-search.md +0 -0
  263. /package/.morph/{standards → framework/standards}/data/vector-search/rag-chunking.md +0 -0
  264. /package/.morph/{standards → framework/standards}/frontend/blazor/design-checklist.md +0 -0
  265. /package/.morph/{standards → framework/standards}/frontend/blazor/fluent-ui-setup.md +0 -0
  266. /package/.morph/{standards → framework/standards}/frontend/blazor/fluent-ui.md +0 -0
  267. /package/.morph/{standards → framework/standards}/frontend/blazor/html-conversion.md +0 -0
  268. /package/.morph/{standards → framework/standards}/frontend/blazor/lifecycle.md +0 -0
  269. /package/.morph/{standards → framework/standards}/frontend/blazor/pitfalls.md +0 -0
  270. /package/.morph/{standards → framework/standards}/frontend/blazor/state.md +0 -0
  271. /package/.morph/{standards → framework/standards}/frontend/design-system/animations.md +0 -0
  272. /package/.morph/{standards → framework/standards}/frontend/design-system/naming.md +0 -0
  273. /package/.morph/{standards → framework/standards}/frontend/nextjs/nextjs-patterns.md +0 -0
  274. /package/.morph/{standards → framework/standards}/infrastructure/azure/azure.md +0 -0
  275. /package/.morph/{standards → framework/standards}/infrastructure/azure/bicep/bicep-patterns.md +0 -0
  276. /package/.morph/{standards → framework/standards}/infrastructure/azure/devops/azure-devops-setup.md +0 -0
  277. /package/.morph/{standards → framework/standards}/infrastructure/azure/devops/local-development.md +0 -0
  278. /package/.morph/{standards → framework/standards}/infrastructure/azure/services/functions.md +0 -0
  279. /package/.morph/{standards → framework/standards}/infrastructure/azure/services/service-bus.md +0 -0
  280. /package/.morph/{standards → framework/standards}/infrastructure/azure/services/storage.md +0 -0
  281. /package/.morph/{standards → framework/standards}/infrastructure/docker/easypanel-deploy.md +0 -0
  282. /package/.morph/{standards → framework/standards}/infrastructure/supabase/mcp-setup.md +0 -0
  283. /package/.morph/{standards → framework/standards}/infrastructure/supabase/supabase-auth.md +0 -0
  284. /package/.morph/{standards → framework/standards}/infrastructure/supabase/supabase-pgvector.md +0 -0
  285. /package/.morph/{standards → framework/standards}/infrastructure/supabase/supabase-rls.md +0 -0
  286. /package/.morph/{standards → framework/standards}/infrastructure/supabase/supabase-storage.md +0 -0
  287. /package/.morph/{standards → framework/standards}/integration/api/graphql.md +0 -0
  288. /package/.morph/{standards → framework/standards}/integration/api/grpc.md +0 -0
  289. /package/.morph/{standards → framework/standards}/integration/api/rest-design.md +0 -0
  290. /package/.morph/{standards → framework/standards}/integration/event-driven/cqrs.md +0 -0
  291. /package/.morph/{standards → framework/standards}/integration/event-driven/event-sourcing.md +0 -0
  292. /package/.morph/{standards → framework/standards}/integration/event-driven/service-bus.md +0 -0
  293. /package/.morph/{standards → framework/standards}/observability/logging.md +0 -0
  294. /package/.morph/{standards → framework/standards}/observability/metrics.md +0 -0
  295. /package/.morph/{standards → framework/standards}/observability/monitoring.md +0 -0
  296. /package/.morph/{standards → framework/standards}/observability/tracing.md +0 -0
  297. /package/.morph/{standards → framework/standards}/workflows/parallel-execution.md +0 -0
  298. /package/.morph/{standards → framework/standards}/workflows/thread-management.md +0 -0
  299. /package/.morph/{templates → framework/templates}/.idea/morph-templates.xml +0 -0
  300. /package/.morph/{templates → framework/templates}/.vscode/morph-templates.code-snippets +0 -0
  301. /package/.morph/{templates → framework/templates}/IDE-SNIPPETS.md +0 -0
  302. /package/.morph/{templates → framework/templates}/code/dotnet/backend/repository.cs +0 -0
  303. /package/.morph/{templates → framework/templates}/code/dotnet/backend/service.cs +0 -0
  304. /package/.morph/{templates → framework/templates}/code/dotnet/contracts/Commands.cs +0 -0
  305. /package/.morph/{templates → framework/templates}/code/dotnet/contracts/Entities.cs +0 -0
  306. /package/.morph/{templates → framework/templates}/code/dotnet/contracts/Queries.cs +0 -0
  307. /package/.morph/{templates → framework/templates}/code/dotnet/contracts/README.md +0 -0
  308. /package/.morph/{templates → framework/templates}/code/dotnet/contracts/api-contracts.cs +0 -0
  309. /package/.morph/{templates → framework/templates}/code/dotnet/contracts/contracts.cs +0 -0
  310. /package/.morph/{templates → framework/templates}/code/dotnet/database/migration.cs +0 -0
  311. /package/.morph/{templates → framework/templates}/code/dotnet/frontend/component.razor +0 -0
  312. /package/.morph/{templates → framework/templates}/code/dotnet/jobs/agent.cs +0 -0
  313. /package/.morph/{templates → framework/templates}/code/dotnet/jobs/job.cs +0 -0
  314. /package/.morph/{templates → framework/templates}/code/dotnet/test.cs +0 -0
  315. /package/.morph/{templates → framework/templates}/code/sql/rls-policy.sql +0 -0
  316. /package/.morph/{templates → framework/templates}/code/sql/supabase-migration.sql +0 -0
  317. /package/.morph/{templates → framework/templates}/code/sql/supabase-migration.template.sql +0 -0
  318. /package/.morph/{templates → framework/templates}/code/typescript/contracts.ts +0 -0
  319. /package/.morph/{templates → framework/templates}/docs/proposal.md +0 -0
  320. /package/.morph/{templates → framework/templates}/examples/design-system-examples.md +0 -0
  321. /package/.morph/{templates → framework/templates}/feature/decisions.md +0 -0
  322. /package/.morph/{templates → framework/templates}/feature/recap.md +0 -0
  323. /package/.morph/{templates → framework/templates}/feature/tasks.md +0 -0
  324. /package/.morph/{templates → framework/templates}/infrastructure/azure/Dockerfile.example +0 -0
  325. /package/.morph/{templates → framework/templates}/infrastructure/azure/README.md +0 -0
  326. /package/.morph/{templates → framework/templates}/infrastructure/azure/app-insights.bicep +0 -0
  327. /package/.morph/{templates → framework/templates}/infrastructure/azure/app-service.bicep +0 -0
  328. /package/.morph/{templates → framework/templates}/infrastructure/azure/container-app-env.bicep +0 -0
  329. /package/.morph/{templates → framework/templates}/infrastructure/azure/container-app.bicep +0 -0
  330. /package/.morph/{templates → framework/templates}/infrastructure/azure/deploy-checklist.md +0 -0
  331. /package/.morph/{templates → framework/templates}/infrastructure/azure/deploy.ps1 +0 -0
  332. /package/.morph/{templates → framework/templates}/infrastructure/azure/deploy.sh +0 -0
  333. /package/.morph/{templates → framework/templates}/infrastructure/azure/key-vault.bicep +0 -0
  334. /package/.morph/{templates → framework/templates}/infrastructure/azure/main.bicep +0 -0
  335. /package/.morph/{templates → framework/templates}/infrastructure/azure/parameters.dev.json +0 -0
  336. /package/.morph/{templates → framework/templates}/infrastructure/azure/parameters.prod.json +0 -0
  337. /package/.morph/{templates → framework/templates}/infrastructure/azure/parameters.staging.json +0 -0
  338. /package/.morph/{templates → framework/templates}/infrastructure/azure/sql-database.bicep +0 -0
  339. /package/.morph/{templates → framework/templates}/infrastructure/azure/storage.bicep +0 -0
  340. /package/.morph/{templates → framework/templates}/infrastructure/docker/Dockerfile.template +0 -0
  341. /package/.morph/{templates → framework/templates}/infrastructure/docker/docker-compose.template.yml +0 -0
  342. /package/.morph/{templates → framework/templates}/infrastructure/docker/dockerfile-api.dockerfile +0 -0
  343. /package/.morph/{templates → framework/templates}/infrastructure/docker/dockerfile-web.dockerfile +0 -0
  344. /package/.morph/{templates → framework/templates}/infrastructure/docker/easypanel.template.json +0 -0
  345. /package/.morph/{templates → framework/templates}/infrastructure/github/actions/azure-auth/action.yml.hbs +0 -0
  346. /package/.morph/{templates → framework/templates}/infrastructure/github/actions/docker-build-push/action.yml.hbs +0 -0
  347. /package/.morph/{templates → framework/templates}/infrastructure/github/actions/health-check/action.yml.hbs +0 -0
  348. /package/.morph/{templates → framework/templates}/infrastructure/github/workflows/deploy-easypanel.yml.hbs +0 -0
  349. /package/.morph/{templates → framework/templates}/infrastructure/github/workflows/docker-build-push.yml.hbs +0 -0
  350. /package/.morph/{templates → framework/templates}/infrastructure/github/workflows/dotnet-build.yml.hbs +0 -0
  351. /package/.morph/{templates → framework/templates}/integrations/asaas-client.cs +0 -0
  352. /package/.morph/{templates → framework/templates}/integrations/asaas-webhook.cs +0 -0
  353. /package/.morph/{templates → framework/templates}/integrations/azure-identity-config.cs +0 -0
  354. /package/.morph/{templates → framework/templates}/integrations/clerk-config.cs +0 -0
  355. /package/.morph/{templates → framework/templates}/meta-prompts/fusion/fusion-agent.md +0 -0
  356. /package/.morph/{templates → framework/templates}/meta-prompts/fusion/fusion-aggregator.md +0 -0
  357. /package/.morph/{templates → framework/templates}/meta-prompts/hops/hop-retry.md +0 -0
  358. /package/.morph/{templates → framework/templates}/meta-prompts/hops/hop-validation.md +0 -0
  359. /package/.morph/{templates → framework/templates}/meta-prompts/hops/hop-wrapper.md +0 -0
  360. /package/.morph/{templates → framework/templates}/meta-prompts/parallel-workers/parallel-coordinator.md +0 -0
  361. /package/.morph/{templates → framework/templates}/meta-prompts/squad-leaders/backend-squad.md +0 -0
  362. /package/.morph/{templates → framework/templates}/meta-prompts/squad-leaders/frontend-squad.md +0 -0
  363. /package/.morph/{templates → framework/templates}/meta-prompts/squad-leaders/squad-leader.md +0 -0
  364. /package/.morph/{templates → framework/templates}/meta-prompts/validators/checkpoint-validator.md +0 -0
  365. /package/.morph/{templates → framework/templates}/saas/subscription.cs +0 -0
  366. /package/.morph/{templates → framework/templates}/saas/tenant.cs +0 -0
  367. /package/.morph/{templates → framework/templates}/state.template.json +0 -0
  368. /package/.morph/{templates → framework/templates}/ui/FluentDesignTheme.cs +0 -0
  369. /package/.morph/{templates → framework/templates}/ui/MudTheme.cs +0 -0
  370. /package/.morph/{templates → framework/templates}/ui/design-system.css +0 -0
  371. /package/framework/hooks/{commit-msg → git/commit-msg}/conventional-commits.sh +0 -0
  372. /package/framework/hooks/{pre-commit → git/pre-commit}/agents.sh +0 -0
  373. /package/framework/hooks/{pre-commit → git/pre-commit}/orchestrator.sh +0 -0
  374. /package/framework/hooks/{pre-commit → git/pre-commit}/specs.sh +0 -0
  375. /package/framework/hooks/{pre-push → git/pre-push}/run-tests.sh +0 -0
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * PreCompact Hook: Save Context Before Compaction
5
+ *
6
+ * Event: PreCompact
7
+ *
8
+ * Snapshots current morph-spec state to .morph/memory/ before context is lost
9
+ * to compaction. The SessionStart hook can use this to restore awareness.
10
+ *
11
+ * Fail-open: exits 0 on any error.
12
+ */
13
+
14
+ import { writeFileSync, mkdirSync, existsSync } from 'fs';
15
+ import { join } from 'path';
16
+ import { stateExists, loadState, getActiveFeature } from '../../shared/state-reader.js';
17
+ import { pass } from '../../shared/hook-response.js';
18
+
19
+ try {
20
+ if (!stateExists()) pass();
21
+
22
+ const state = loadState();
23
+ if (!state) pass();
24
+
25
+ const active = getActiveFeature();
26
+
27
+ const snapshot = {
28
+ timestamp: new Date().toISOString(),
29
+ event: 'pre-compact',
30
+ activeFeature: active ? active.name : null,
31
+ features: {}
32
+ };
33
+
34
+ // Save minimal feature summaries
35
+ for (const [name, feature] of Object.entries(state.features || {})) {
36
+ snapshot.features[name] = {
37
+ phase: feature.phase,
38
+ status: feature.status,
39
+ workflow: feature.workflow,
40
+ tasks: feature.tasks,
41
+ approvalGates: Object.fromEntries(
42
+ Object.entries(feature.approvalGates || {}).map(([gate, data]) => [gate, data.approved])
43
+ )
44
+ };
45
+ }
46
+
47
+ // Save to .morph/memory/
48
+ const memoryDir = join(process.cwd(), '.morph', 'memory');
49
+ if (!existsSync(memoryDir)) {
50
+ mkdirSync(memoryDir, { recursive: true });
51
+ }
52
+
53
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
54
+ const snapshotPath = join(memoryDir, `pre-compact-${timestamp}.json`);
55
+ writeFileSync(snapshotPath, JSON.stringify(snapshot, null, 2), 'utf-8');
56
+
57
+ pass();
58
+ } catch {
59
+ // Fail-open
60
+ process.exit(0);
61
+ }
@@ -0,0 +1,71 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * PreToolUse Hook: Enforce Phase-Appropriate File Writes
5
+ *
6
+ * Event: PreToolUse | Matcher: Write|Edit
7
+ *
8
+ * Ensures writes to .morph/features/{feature}/ go to the current phase's subfolder:
9
+ * proposal → only 0-proposal/
10
+ * design, clarify → only 1-design/
11
+ * uiux → only 2-ui/
12
+ * tasks → only 3-tasks/
13
+ * implement → 4-implement/ + any source code (unrestricted)
14
+ *
15
+ * Files outside .morph/features/ are always allowed.
16
+ *
17
+ * Fail-open: exits 0 on any error.
18
+ */
19
+
20
+ import { readStdin } from '../../shared/stdin-reader.js';
21
+ import { stateExists, getFeaturePhase } from '../../shared/state-reader.js';
22
+ import {
23
+ isFeaturePath,
24
+ extractFeatureName,
25
+ extractPhaseDir,
26
+ PHASE_DIRS
27
+ } from '../../shared/phase-utils.js';
28
+ import { block, pass } from '../../shared/hook-response.js';
29
+
30
+ try {
31
+ if (!stateExists()) pass();
32
+
33
+ const payload = await readStdin();
34
+ if (!payload) pass();
35
+
36
+ const filePath = payload?.tool_input?.file_path || payload?.tool_input?.path || '';
37
+ if (!filePath) pass();
38
+
39
+ // Only check files inside .morph/features/
40
+ if (!isFeaturePath(filePath)) pass();
41
+
42
+ const featureName = extractFeatureName(filePath);
43
+ if (!featureName) pass();
44
+
45
+ const phase = getFeaturePhase(featureName);
46
+ if (!phase) pass();
47
+
48
+ // During implement phase, all writes are allowed (source code is unrestricted)
49
+ if (phase === 'implement' || phase === 'sync') pass();
50
+
51
+ const targetDir = extractPhaseDir(filePath);
52
+ if (!targetDir) pass(); // File directly in feature root — allow
53
+
54
+ const allowedDir = PHASE_DIRS[phase];
55
+ if (!allowedDir) pass(); // Unknown phase — allow
56
+
57
+ if (targetDir !== allowedDir) {
58
+ const phaseLabel = phase.toUpperCase();
59
+ block(
60
+ `MORPH-SPEC: Writing to '${targetDir}/' is not allowed during ${phaseLabel} phase.\n` +
61
+ `Current phase '${phase}' only permits writes to '${allowedDir}/'.\n\n` +
62
+ `To write to '${targetDir}/', first advance to the appropriate phase:\n` +
63
+ ` morph-spec phase advance ${featureName}`
64
+ );
65
+ }
66
+
67
+ pass();
68
+ } catch {
69
+ // Fail-open
70
+ process.exit(0);
71
+ }
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * PreToolUse Hook: Protect state.json & Framework Files
5
+ *
6
+ * Event: PreToolUse | Matcher: Write|Edit
7
+ *
8
+ * Blocks direct edits to:
9
+ * - .morph/state.json → must use CLI commands
10
+ * - .morph/framework/** → read-only framework files
11
+ *
12
+ * Fail-open: exits 0 on any error.
13
+ */
14
+
15
+ import { readStdin } from '../../shared/stdin-reader.js';
16
+ import { stateExists } from '../../shared/state-reader.js';
17
+ import { isStatePath, isFrameworkPath } from '../../shared/phase-utils.js';
18
+ import { block, pass } from '../../shared/hook-response.js';
19
+
20
+ try {
21
+ // Skip if not a morph-spec project
22
+ if (!stateExists()) {
23
+ pass();
24
+ }
25
+
26
+ const payload = await readStdin();
27
+ if (!payload) pass();
28
+
29
+ const filePath = payload?.tool_input?.file_path || payload?.tool_input?.path || '';
30
+ if (!filePath) pass();
31
+
32
+ // Block edits to state.json
33
+ if (isStatePath(filePath)) {
34
+ block(
35
+ 'MORPH-SPEC: Direct edits to .morph/state.json are blocked.\n' +
36
+ 'Use CLI commands instead:\n' +
37
+ ' morph-spec state set <feature> <key> <value>\n' +
38
+ ' morph-spec phase advance <feature>\n' +
39
+ ' morph-spec task done <feature> <taskId>\n' +
40
+ ' morph-spec approve <feature> <gate>'
41
+ );
42
+ }
43
+
44
+ // Block edits to framework files
45
+ if (isFrameworkPath(filePath)) {
46
+ block(
47
+ 'MORPH-SPEC: Files in .morph/framework/ are read-only.\n' +
48
+ 'These files are managed by the framework and overwritten on update.\n' +
49
+ 'To customize, create project-specific overrides in .morph/context/ or .morph/config/.'
50
+ );
51
+ }
52
+
53
+ // All other files are allowed
54
+ pass();
55
+ } catch {
56
+ // Fail-open
57
+ process.exit(0);
58
+ }
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * PreToolUse Hook: Protect Approved Spec Files
5
+ *
6
+ * Event: PreToolUse | Matcher: Write|Edit
7
+ *
8
+ * Blocks Write/Edit to spec artifacts after their approval gate has passed:
9
+ * - 1-design/spec.md, contracts.cs, etc. → blocked if 'design' gate approved
10
+ * - 3-tasks/tasks.md → blocked if 'tasks' gate approved
11
+ * - 2-ui/design-system.md, etc. → blocked if 'uiux' gate approved
12
+ *
13
+ * Fail-open: exits 0 on any error.
14
+ */
15
+
16
+ import { readStdin } from '../../shared/stdin-reader.js';
17
+ import { stateExists, isGateApproved } from '../../shared/state-reader.js';
18
+ import {
19
+ isFeaturePath,
20
+ extractFeatureName,
21
+ getBasename,
22
+ PROTECTED_SPEC_FILES
23
+ } from '../../shared/phase-utils.js';
24
+ import { block, pass } from '../../shared/hook-response.js';
25
+
26
+ try {
27
+ if (!stateExists()) pass();
28
+
29
+ const payload = await readStdin();
30
+ if (!payload) pass();
31
+
32
+ const filePath = payload?.tool_input?.file_path || payload?.tool_input?.path || '';
33
+ if (!filePath) pass();
34
+
35
+ // Only check files inside .morph/features/
36
+ if (!isFeaturePath(filePath)) pass();
37
+
38
+ const featureName = extractFeatureName(filePath);
39
+ if (!featureName) pass();
40
+
41
+ const filename = getBasename(filePath);
42
+ const requiredGate = PROTECTED_SPEC_FILES[filename];
43
+
44
+ // Not a protected file
45
+ if (!requiredGate) pass();
46
+
47
+ // Check if the gate has been approved
48
+ if (isGateApproved(featureName, requiredGate)) {
49
+ block(
50
+ `MORPH-SPEC: '${filename}' is locked — the '${requiredGate}' gate has been approved.\n` +
51
+ `Editing approved specs breaks the spec contract.\n\n` +
52
+ `If changes are truly needed:\n` +
53
+ ` 1. Revoke approval: morph-spec approve ${featureName} ${requiredGate} --revoke\n` +
54
+ ` 2. Make your edits\n` +
55
+ ` 3. Re-approve: morph-spec approve ${featureName} ${requiredGate}`
56
+ );
57
+ }
58
+
59
+ // Gate not yet approved — allow editing
60
+ pass();
61
+ } catch {
62
+ // Fail-open
63
+ process.exit(0);
64
+ }
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * SessionStart Hook: Inject MORPH-SPEC Context
5
+ *
6
+ * Event: SessionStart | Matcher: startup|resume|compact
7
+ *
8
+ * Reads state.json and injects a summary as additionalContext so Claude
9
+ * knows the current morph-spec state at session start.
10
+ *
11
+ * Fail-open: exits 0 on any error.
12
+ */
13
+
14
+ import { loadState, getActiveFeature, getPendingGates, getMissingOutputs } from '../../shared/state-reader.js';
15
+ import { stateExists } from '../../shared/state-reader.js';
16
+ import { injectContext, pass } from '../../shared/hook-response.js';
17
+ import { readFileSync, existsSync } from 'fs';
18
+ import { join } from 'path';
19
+
20
+ const SPEC_MAX_CHARS = 3000;
21
+
22
+ try {
23
+ if (!stateExists()) pass();
24
+
25
+ const state = loadState();
26
+ if (!state?.features || Object.keys(state.features).length === 0) pass();
27
+
28
+ const active = getActiveFeature();
29
+ const lines = ['MORPH-SPEC Status:'];
30
+
31
+ if (active) {
32
+ const { name, feature } = active;
33
+ lines.push(`- Active feature: ${name} (phase: ${feature.phase}, workflow: ${feature.workflow || 'auto'})`);
34
+ lines.push(`- Status: ${feature.status}`);
35
+
36
+ // Task progress
37
+ if (feature.tasks) {
38
+ lines.push(`- Tasks: ${feature.tasks.completed || 0}/${feature.tasks.total || 0} completed`);
39
+ }
40
+
41
+ // Pending approvals
42
+ const pending = getPendingGates(name);
43
+ if (pending.length > 0) {
44
+ lines.push(`- Pending approvals: ${pending.join(', ')}`);
45
+ }
46
+
47
+ // Next required output
48
+ const missing = getMissingOutputs(name);
49
+ if (missing.length > 0) {
50
+ const next = missing[0];
51
+ lines.push(`- Next required output: ${next.type} → ${next.path}`);
52
+ }
53
+
54
+ // Checkpoints
55
+ if (feature.checkpoints?.length > 0) {
56
+ const lastCp = feature.checkpoints[feature.checkpoints.length - 1];
57
+ lines.push(`- Last checkpoint: #${lastCp.checkpointNum} (${lastCp.passed ? 'passed' : 'failed'})`);
58
+ }
59
+
60
+ // Active feature spec (truncated for context budget)
61
+ const specPath = join(process.cwd(), `.morph/features/${name}/1-design/spec.md`);
62
+ if (existsSync(specPath)) {
63
+ try {
64
+ const specContent = readFileSync(specPath, 'utf-8');
65
+ const truncated = specContent.length > SPEC_MAX_CHARS
66
+ ? specContent.slice(0, SPEC_MAX_CHARS) + `\n\n[... spec truncated — full file at .morph/features/${name}/1-design/spec.md]`
67
+ : specContent;
68
+ lines.push('');
69
+ lines.push(`--- Active feature spec (${name}/1-design/spec.md) ---`);
70
+ lines.push(truncated);
71
+ lines.push('--- End spec ---');
72
+ } catch {
73
+ // Non-blocking: skip spec injection on read error
74
+ }
75
+ }
76
+ } else {
77
+ // Show summary of all features
78
+ const featureNames = Object.keys(state.features);
79
+ lines.push(`- Features: ${featureNames.length} (${featureNames.join(', ')})`);
80
+
81
+ for (const [name, feature] of Object.entries(state.features)) {
82
+ lines.push(` - ${name}: phase=${feature.phase}, status=${feature.status}`);
83
+ }
84
+ }
85
+
86
+ // Remind about key commands
87
+ lines.push('');
88
+ lines.push('Key commands: morph-spec status <feature> | morph-spec phase advance <feature> | morph-spec approve <feature> <gate>');
89
+
90
+ injectContext(lines.join('\n'));
91
+ } catch {
92
+ // Fail-open
93
+ process.exit(0);
94
+ }
@@ -0,0 +1,239 @@
1
+ #!/usr/bin/env python3
2
+ # framework/hooks/claude-code/statusline.py
3
+ # Claude Code statusline for morph-spec
4
+ # Receives JSON via stdin from Claude Code after each response
5
+
6
+ import sys
7
+ import json
8
+ import os
9
+ import subprocess
10
+ import time
11
+ from pathlib import Path
12
+
13
+ # Ensure UTF-8 output on Windows (stdout defaults to CP1252 otherwise)
14
+ if hasattr(sys.stdout, 'reconfigure'):
15
+ sys.stdout.reconfigure(encoding='utf-8')
16
+
17
+ # ANSI colors
18
+ R = '\033[0m' # Reset
19
+ BOLD = '\033[1m'
20
+ CYAN = '\033[36m'
21
+ MAGENTA = '\033[35m'
22
+ GREEN = '\033[32m'
23
+ YELLOW = '\033[33m'
24
+ RED = '\033[31m'
25
+ BLUE = '\033[34m'
26
+ GRAY = '\033[90m'
27
+ WHITE = '\033[97m'
28
+
29
+
30
+ def ctx_color(pct):
31
+ if pct < 70:
32
+ return GREEN
33
+ if pct < 90:
34
+ return YELLOW
35
+ return RED
36
+
37
+
38
+ def progress_bar(pct, width=8):
39
+ filled = int(pct / 100 * width)
40
+ empty = width - filled
41
+ return f"{'█' * filled}{'░' * empty}"
42
+
43
+
44
+ def format_tokens(n):
45
+ if n >= 1000:
46
+ return f"{n // 1000}k"
47
+ return str(n)
48
+
49
+
50
+ def get_git_info(cwd):
51
+ """Get git branch and file stats. Uses a 5s file cache to avoid lag."""
52
+ try:
53
+ cache_file = Path(cwd) / '.morph' / '.git-cache'
54
+ try:
55
+ if cache_file.exists():
56
+ age = time.time() - cache_file.stat().st_mtime
57
+ if age < 5:
58
+ return cache_file.read_text().strip()
59
+ except Exception:
60
+ pass
61
+
62
+ branch = subprocess.check_output(
63
+ ['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
64
+ cwd=cwd, stderr=subprocess.DEVNULL, timeout=2
65
+ ).decode().strip()
66
+
67
+ status_out = subprocess.check_output(
68
+ ['git', 'status', '--porcelain'],
69
+ cwd=cwd, stderr=subprocess.DEVNULL, timeout=2
70
+ ).decode()
71
+
72
+ staged = sum(1 for l in status_out.splitlines() if l and l[0] in 'MADRC')
73
+ modified = sum(1 for l in status_out.splitlines() if l and l[1] in 'MD')
74
+ untracked = sum(1 for l in status_out.splitlines() if l.startswith('??'))
75
+
76
+ parts = [f"{BLUE} {branch}{R}"]
77
+ if staged:
78
+ parts.append(f"{GREEN}+{staged}{R}")
79
+ if modified:
80
+ parts.append(f"{YELLOW}~{modified}{R}")
81
+ if untracked:
82
+ parts.append(f"{GRAY}?{untracked}{R}")
83
+
84
+ result = ' '.join(parts)
85
+
86
+ try:
87
+ cache_file.parent.mkdir(parents=True, exist_ok=True)
88
+ cache_file.write_text(result)
89
+ except Exception:
90
+ pass
91
+
92
+ return result
93
+ except Exception:
94
+ return ""
95
+
96
+
97
+ def get_worktree_info(cwd):
98
+ """Detect if running in a git worktree (not the main worktree)."""
99
+ try:
100
+ worktrees_out = subprocess.check_output(
101
+ ['git', 'worktree', 'list', '--porcelain'],
102
+ cwd=cwd, stderr=subprocess.DEVNULL, timeout=2
103
+ ).decode()
104
+
105
+ entries = []
106
+ current = {}
107
+ for line in worktrees_out.splitlines():
108
+ if line.startswith('worktree '):
109
+ if current:
110
+ entries.append(current)
111
+ current = {'path': line.split(' ', 1)[1]}
112
+ elif line.startswith('branch '):
113
+ current['branch'] = line.split(' ', 1)[1]
114
+
115
+ if current:
116
+ entries.append(current)
117
+
118
+ if len(entries) > 1:
119
+ cwd_resolved = str(Path(cwd).resolve())
120
+ for entry in entries[1:]:
121
+ entry_path = str(Path(entry.get('path', '')).resolve())
122
+ if cwd_resolved == entry_path:
123
+ branch_ref = entry.get('branch', '')
124
+ branch = branch_ref.replace('refs/heads/', '')
125
+ return f"{MAGENTA}worktree:{branch}{R}"
126
+ except Exception:
127
+ pass
128
+ return ""
129
+
130
+
131
+ def get_morph_info(cwd):
132
+ """Read active feature info from .morph/state.json."""
133
+ state_path = Path(cwd) / '.morph' / 'state.json'
134
+ if not state_path.exists():
135
+ return None
136
+ try:
137
+ state = json.loads(state_path.read_text())
138
+ features = state.get('features', {})
139
+ active = [
140
+ (name, feat)
141
+ for name, feat in features.items()
142
+ if feat.get('status') == 'in_progress'
143
+ ]
144
+ if not active:
145
+ return None
146
+
147
+ name, feat = active[0]
148
+ phase = feat.get('phase', '?')
149
+ tasks = feat.get('tasks', {})
150
+ done = tasks.get('completed', 0)
151
+ total = tasks.get('total', 0)
152
+ gates = feat.get('approvalGates', {})
153
+ pending = [g for g, v in gates.items() if not v.get('approved')]
154
+
155
+ return {
156
+ 'name': name,
157
+ 'phase': phase,
158
+ 'tasks_done': done,
159
+ 'tasks_total': total,
160
+ 'pending_approval': pending[0] if pending else None,
161
+ }
162
+ except Exception:
163
+ return None
164
+
165
+
166
+ def main():
167
+ try:
168
+ raw = sys.stdin.read()
169
+ if not raw.strip():
170
+ sys.exit(0)
171
+ data = json.loads(raw)
172
+ except Exception:
173
+ sys.exit(0)
174
+
175
+ cwd = data.get('cwd', os.getcwd())
176
+
177
+ # === LINE 1: Morph status (only if morph project has active feature) ===
178
+ morph = get_morph_info(cwd)
179
+ if morph:
180
+ parts1 = [
181
+ f"{CYAN}{BOLD}{morph['name']}{R}",
182
+ f"{MAGENTA}phase:{morph['phase']}{R}",
183
+ ]
184
+ if morph['tasks_total'] > 0:
185
+ pct = morph['tasks_done'] / morph['tasks_total'] * 100
186
+ bar = progress_bar(pct, 6)
187
+ parts1.append(f"{GREEN}{bar} {morph['tasks_done']}/{morph['tasks_total']}{R}")
188
+ if morph['pending_approval']:
189
+ parts1.append(f"{YELLOW}⏳ {morph['pending_approval']} pending{R}")
190
+ print(' | '.join(parts1))
191
+
192
+ # === LINE 2: Session info (always shown) ===
193
+ parts2 = []
194
+
195
+ # Model
196
+ model = data.get('model', {})
197
+ model_name = model.get('display_name', model.get('id', ''))
198
+ if model_name:
199
+ short = model_name.replace('Claude ', '').replace(' (claude.ai)', '')
200
+ parts2.append(f"{WHITE}{BOLD}🤖 {short}{R}")
201
+
202
+ # Context window
203
+ ctx = data.get('context_window', {})
204
+ if ctx:
205
+ used_pct = ctx.get('used_percentage', 0)
206
+ cur = ctx.get('current_usage', 0)
207
+ total_ctx = ctx.get('context_window_size', 0)
208
+ color = ctx_color(used_pct)
209
+ bar = progress_bar(used_pct, 8)
210
+ toks = f"{format_tokens(cur)}/{format_tokens(total_ctx)}"
211
+ parts2.append(f"{color}{bar} {used_pct:.0f}% ({toks} tok){R}")
212
+
213
+ # Cost
214
+ cost = data.get('cost', {})
215
+ if cost.get('total_cost_usd'):
216
+ usd = cost['total_cost_usd']
217
+ parts2.append(f"{GRAY}${usd:.3f}{R}")
218
+
219
+ # Agent name (if running in agent mode)
220
+ agent = data.get('agent', {})
221
+ if agent.get('name'):
222
+ parts2.append(f"{BLUE}agent:{agent['name']}{R}")
223
+
224
+ # Git info (cached, non-blocking)
225
+ git = get_git_info(cwd)
226
+ if git:
227
+ parts2.append(git)
228
+
229
+ # Worktree info
230
+ wt = get_worktree_info(cwd)
231
+ if wt:
232
+ parts2.append(wt)
233
+
234
+ if parts2:
235
+ print(' | '.join(parts2))
236
+
237
+
238
+ if __name__ == '__main__':
239
+ main()
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bash
2
+ # morph-spec statusline — installed globally to ~/.claude/statusline.sh
3
+ # Claude Code invokes this with JSON via stdin after each response.
4
+ # Requires: Python 3 available as `python3` on PATH.
5
+
6
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7
+ python3 "${SCRIPT_DIR}/statusline.py" 2>/dev/null || true
@@ -0,0 +1,88 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Stop Hook: Validate Completion (Advisory)
5
+ *
6
+ * Event: Stop
7
+ *
8
+ * When Claude stops, checks for incomplete work:
9
+ * - In implement phase: checks uncompleted tasks
10
+ * - In spec phases: checks required outputs still created: false
11
+ * - Returns additionalContext with what remains (advisory, not blocking)
12
+ *
13
+ * Uses stop_hook_active env check to prevent infinite loops.
14
+ *
15
+ * Fail-open: exits 0 on any error.
16
+ */
17
+
18
+ import { stateExists, getActiveFeature, getMissingOutputs } from '../../shared/state-reader.js';
19
+ import { injectContext, pass } from '../../shared/hook-response.js';
20
+
21
+ try {
22
+ // Prevent infinite loop
23
+ if (process.env.MORPH_STOP_HOOK_ACTIVE === '1') pass();
24
+
25
+ if (!stateExists()) pass();
26
+
27
+ const active = getActiveFeature();
28
+ if (!active) pass();
29
+
30
+ const { name, feature } = active;
31
+ const warnings = [];
32
+
33
+ // Check for incomplete tasks during implement phase
34
+ if (feature.phase === 'implement' && feature.tasks) {
35
+ const remaining = (feature.tasks.total || 0) - (feature.tasks.completed || 0);
36
+ if (remaining > 0) {
37
+ warnings.push(`${remaining} task(s) remaining for feature '${name}'`);
38
+ if (feature.tasks.inProgress > 0) {
39
+ warnings.push(` ${feature.tasks.inProgress} task(s) still in progress`);
40
+ }
41
+ }
42
+ }
43
+
44
+ // Check for missing outputs in spec phases
45
+ if (['proposal', 'design', 'clarify', 'tasks', 'uiux'].includes(feature.phase)) {
46
+ const missing = getMissingOutputs(name);
47
+ if (missing.length > 0) {
48
+ warnings.push(`Missing outputs for '${name}' (${feature.phase} phase):`);
49
+ for (const output of missing.slice(0, 5)) {
50
+ warnings.push(` - ${output.type}: ${output.path}`);
51
+ }
52
+ if (missing.length > 5) {
53
+ warnings.push(` ... and ${missing.length - 5} more`);
54
+ }
55
+ }
56
+ }
57
+
58
+ // Check pending approval gates
59
+ if (feature.approvalGates) {
60
+ const pendingGates = Object.entries(feature.approvalGates)
61
+ .filter(([, gate]) => !gate.approved && gate.timestamp === null)
62
+ .map(([name]) => name);
63
+
64
+ // Only warn about gates relevant to current/past phases
65
+ const relevantGates = pendingGates.filter(gate => {
66
+ const gatePhaseMap = { proposal: 'proposal', uiux: 'uiux', design: 'design', tasks: 'tasks' };
67
+ return gatePhaseMap[gate] !== undefined;
68
+ });
69
+
70
+ if (relevantGates.length > 0) {
71
+ warnings.push(`Pending approvals: ${relevantGates.join(', ')}`);
72
+ }
73
+ }
74
+
75
+ if (warnings.length === 0) pass();
76
+
77
+ const message = [
78
+ 'MORPH-SPEC: Incomplete work detected:',
79
+ ...warnings.map(w => ` ${w}`),
80
+ '',
81
+ 'Resume with: morph-spec status ' + name
82
+ ].join('\n');
83
+
84
+ injectContext(message);
85
+ } catch {
86
+ // Fail-open
87
+ process.exit(0);
88
+ }