@polymorphism-tech/morph-spec 4.7.1 → 4.7.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 (232) hide show
  1. package/.morph/.morphversion +5 -0
  2. package/.morph/analytics/threads-log.jsonl +5 -0
  3. package/.morph/config/config.json +8 -0
  4. package/.morph/framework/agents.json +1815 -0
  5. package/.morph/framework/hooks/README.md +205 -0
  6. package/.morph/framework/hooks/claude-code/notification/approval-reminder.js +54 -0
  7. package/.morph/framework/hooks/claude-code/post-tool-use/dispatch.js +83 -0
  8. package/.morph/framework/hooks/claude-code/post-tool-use/handle-tool-failure.js +42 -0
  9. package/.morph/framework/hooks/claude-code/pre-compact/save-morph-context.js +61 -0
  10. package/.morph/framework/hooks/claude-code/pre-tool-use/enforce-phase-writes.js +71 -0
  11. package/.morph/framework/hooks/claude-code/pre-tool-use/protect-readonly-files.js +58 -0
  12. package/.morph/framework/hooks/claude-code/pre-tool-use/protect-spec-files.js +64 -0
  13. package/.morph/framework/hooks/claude-code/session-start/inject-morph-context.js +94 -0
  14. package/.morph/framework/hooks/claude-code/statusline.py +538 -0
  15. package/.morph/framework/hooks/claude-code/statusline.sh +7 -0
  16. package/.morph/framework/hooks/claude-code/stop/validate-completion.js +88 -0
  17. package/.morph/framework/hooks/claude-code/user-prompt/enrich-prompt.js +91 -0
  18. package/.morph/framework/hooks/git/commit-msg/conventional-commits.sh +33 -0
  19. package/.morph/framework/hooks/git/pre-commit/agents.sh +25 -0
  20. package/.morph/framework/hooks/git/pre-commit/orchestrator.sh +64 -0
  21. package/.morph/framework/hooks/git/pre-commit/specs.sh +50 -0
  22. package/.morph/framework/hooks/git/pre-push/run-tests.sh +44 -0
  23. package/.morph/framework/hooks/shared/hook-response.js +45 -0
  24. package/.morph/framework/hooks/shared/phase-utils.js +129 -0
  25. package/.morph/framework/hooks/shared/state-reader.js +138 -0
  26. package/.morph/framework/hooks/shared/stdin-reader.js +26 -0
  27. package/.morph/framework/standards/STANDARDS.json +933 -0
  28. package/.morph/framework/standards/ai-agents/blazor-ui.md +364 -0
  29. package/.morph/framework/standards/ai-agents/production.md +415 -0
  30. package/.morph/framework/standards/ai-agents/setup.md +418 -0
  31. package/.morph/framework/standards/ai-agents/team-orchestration.md +479 -0
  32. package/.morph/framework/standards/ai-agents/workflows.md +354 -0
  33. package/.morph/framework/standards/architecture/ddd/aggregates.md +120 -0
  34. package/.morph/framework/standards/architecture/ddd/bounded-contexts.md +105 -0
  35. package/.morph/framework/standards/architecture/ddd/complexity-levels.md +108 -0
  36. package/.morph/framework/standards/architecture/ddd/entities.md +99 -0
  37. package/.morph/framework/standards/architecture/ddd/ubiquitous-language.md +58 -0
  38. package/.morph/framework/standards/architecture/ddd/value-objects.md +124 -0
  39. package/.morph/framework/standards/backend/api/minimal-api.md +494 -0
  40. package/.morph/framework/standards/backend/api/rest.md +492 -0
  41. package/.morph/framework/standards/backend/api/validation.md +88 -0
  42. package/.morph/framework/standards/backend/authentication/passkeys.md +428 -0
  43. package/.morph/framework/standards/backend/database/ef-core.md +199 -0
  44. package/.morph/framework/standards/backend/database/migrations.md +393 -0
  45. package/.morph/framework/standards/backend/database/postgresql/database.md +352 -0
  46. package/.morph/framework/standards/backend/database/repository-patterns.md +528 -0
  47. package/.morph/framework/standards/backend/database/vector-search-rag.md +541 -0
  48. package/.morph/framework/standards/backend/dotnet/async.md +366 -0
  49. package/.morph/framework/standards/backend/dotnet/core.md +117 -0
  50. package/.morph/framework/standards/backend/dotnet/di.md +439 -0
  51. package/.morph/framework/standards/backend/dotnet/program-cs-checklist.md +92 -0
  52. package/.morph/framework/standards/backend/integrations/asaas/asaas-api.md +216 -0
  53. package/.morph/framework/standards/backend/integrations/clerk/clerk-auth.md +290 -0
  54. package/.morph/framework/standards/backend/integrations/hangfire/hangfire-jobs.md +350 -0
  55. package/.morph/framework/standards/backend/integrations/resend/resend-email.md +385 -0
  56. package/.morph/framework/standards/context/analytics.md +96 -0
  57. package/.morph/framework/standards/context/bundles.md +110 -0
  58. package/.morph/framework/standards/context/priming.md +78 -0
  59. package/.morph/framework/standards/core/architecture.md +185 -0
  60. package/.morph/framework/standards/core/coding.md +214 -0
  61. package/.morph/framework/standards/core/git-branching-strategy.md +403 -0
  62. package/.morph/framework/standards/core/git.md +185 -0
  63. package/.morph/framework/standards/core/testing.md +295 -0
  64. package/.morph/framework/standards/data/nosql/blob-storage.md +102 -0
  65. package/.morph/framework/standards/data/nosql/cache/redis.md +97 -0
  66. package/.morph/framework/standards/data/nosql/cosmos-db.md +118 -0
  67. package/.morph/framework/standards/data/vector-search/azure-ai-search.md +121 -0
  68. package/.morph/framework/standards/data/vector-search/rag-chunking.md +104 -0
  69. package/.morph/framework/standards/frontend/blazor/design-checklist.md +222 -0
  70. package/.morph/framework/standards/frontend/blazor/fluent-ui-setup.md +595 -0
  71. package/.morph/framework/standards/frontend/blazor/fluent-ui.md +137 -0
  72. package/.morph/framework/standards/frontend/blazor/html-conversion.md +184 -0
  73. package/.morph/framework/standards/frontend/blazor/lifecycle.md +195 -0
  74. package/.morph/framework/standards/frontend/blazor/pitfalls.md +198 -0
  75. package/.morph/framework/standards/frontend/blazor/state.md +191 -0
  76. package/.morph/framework/standards/frontend/design-system/animations.md +151 -0
  77. package/.morph/framework/standards/frontend/design-system/naming.md +64 -0
  78. package/.morph/framework/standards/frontend/nextjs/app-router.md +123 -0
  79. package/.morph/framework/standards/frontend/nextjs/components.md +132 -0
  80. package/.morph/framework/standards/frontend/nextjs/data-fetching.md +126 -0
  81. package/.morph/framework/standards/frontend/nextjs/forms.md +128 -0
  82. package/.morph/framework/standards/frontend/nextjs/naming-conventions.md +67 -0
  83. package/.morph/framework/standards/frontend/nextjs/nextjs-patterns.md +215 -0
  84. package/.morph/framework/standards/frontend/nextjs/project-structure.md +102 -0
  85. package/.morph/framework/standards/frontend/nextjs/state-management.md +72 -0
  86. package/.morph/framework/standards/frontend/nextjs/testing.md +111 -0
  87. package/.morph/framework/standards/infrastructure/azure/azure.md +624 -0
  88. package/.morph/framework/standards/infrastructure/azure/bicep/bicep-patterns.md +422 -0
  89. package/.morph/framework/standards/infrastructure/azure/devops/azure-devops-setup.md +516 -0
  90. package/.morph/framework/standards/infrastructure/azure/devops/local-development.md +520 -0
  91. package/.morph/framework/standards/infrastructure/azure/services/functions.md +486 -0
  92. package/.morph/framework/standards/infrastructure/azure/services/service-bus.md +459 -0
  93. package/.morph/framework/standards/infrastructure/azure/services/storage.md +407 -0
  94. package/.morph/framework/standards/infrastructure/docker/easypanel-deploy.md +196 -0
  95. package/.morph/framework/standards/infrastructure/supabase/mcp-setup.md +252 -0
  96. package/.morph/framework/standards/infrastructure/supabase/supabase-auth.md +176 -0
  97. package/.morph/framework/standards/infrastructure/supabase/supabase-pgvector.md +169 -0
  98. package/.morph/framework/standards/infrastructure/supabase/supabase-rls.md +184 -0
  99. package/.morph/framework/standards/infrastructure/supabase/supabase-storage.md +153 -0
  100. package/.morph/framework/standards/integration/api/graphql.md +91 -0
  101. package/.morph/framework/standards/integration/api/grpc.md +114 -0
  102. package/.morph/framework/standards/integration/api/rest-design.md +95 -0
  103. package/.morph/framework/standards/integration/event-driven/cqrs.md +101 -0
  104. package/.morph/framework/standards/integration/event-driven/event-sourcing.md +124 -0
  105. package/.morph/framework/standards/integration/event-driven/service-bus.md +95 -0
  106. package/.morph/framework/standards/integration/mcp/mcp-tools.md +384 -0
  107. package/.morph/framework/standards/observability/logging.md +131 -0
  108. package/.morph/framework/standards/observability/metrics.md +121 -0
  109. package/.morph/framework/standards/observability/monitoring.md +114 -0
  110. package/.morph/framework/standards/observability/tracing.md +132 -0
  111. package/.morph/framework/standards/workflows/parallel-execution.md +112 -0
  112. package/.morph/framework/standards/workflows/thread-management.md +113 -0
  113. package/.morph/framework/templates/.idea/morph-templates.xml +92 -0
  114. package/.morph/framework/templates/.vscode/morph-templates.code-snippets +186 -0
  115. package/.morph/framework/templates/IDE-SNIPPETS.md +266 -0
  116. package/.morph/framework/templates/README.md +814 -0
  117. package/.morph/framework/templates/REGISTRY.json +1888 -0
  118. package/.morph/framework/templates/code/dotnet/backend/repository.cs +141 -0
  119. package/.morph/framework/templates/code/dotnet/backend/service.cs +139 -0
  120. package/.morph/framework/templates/code/dotnet/contracts/Commands.cs +74 -0
  121. package/.morph/framework/templates/code/dotnet/contracts/Entities.cs +25 -0
  122. package/.morph/framework/templates/code/dotnet/contracts/Queries.cs +74 -0
  123. package/.morph/framework/templates/code/dotnet/contracts/README.md +74 -0
  124. package/.morph/framework/templates/code/dotnet/contracts/api-contracts.cs +173 -0
  125. package/.morph/framework/templates/code/dotnet/contracts/contracts-level1.cs +69 -0
  126. package/.morph/framework/templates/code/dotnet/contracts/contracts-level2.cs +86 -0
  127. package/.morph/framework/templates/code/dotnet/contracts/contracts-level3.cs +41 -0
  128. package/.morph/framework/templates/code/dotnet/database/migration.cs +83 -0
  129. package/.morph/framework/templates/code/dotnet/frontend/component.razor +239 -0
  130. package/.morph/framework/templates/code/dotnet/jobs/agent.cs +163 -0
  131. package/.morph/framework/templates/code/dotnet/jobs/job.cs +171 -0
  132. package/.morph/framework/templates/code/dotnet/test.cs +239 -0
  133. package/.morph/framework/templates/code/sql/rls-policy.sql +57 -0
  134. package/.morph/framework/templates/code/sql/supabase-migration.sql +100 -0
  135. package/.morph/framework/templates/code/sql/supabase-migration.template.sql +113 -0
  136. package/.morph/framework/templates/code/typescript/contracts.ts +168 -0
  137. package/.morph/framework/templates/context/CONTEXT-FEATURE.md +276 -0
  138. package/.morph/framework/templates/context/CONTEXT.md +181 -0
  139. package/.morph/framework/templates/docs/clarifications.md +253 -0
  140. package/.morph/framework/templates/docs/onboarding.md +123 -0
  141. package/.morph/framework/templates/docs/proposal.md +182 -0
  142. package/.morph/framework/templates/docs/schema-analysis.md +119 -0
  143. package/.morph/framework/templates/docs/spec.md +198 -0
  144. package/.morph/framework/templates/docs/ui-components.md +124 -0
  145. package/.morph/framework/templates/docs/ui-design-system.md +76 -0
  146. package/.morph/framework/templates/docs/ui-flows.md +167 -0
  147. package/.morph/framework/templates/docs/ui-mockups.md +98 -0
  148. package/.morph/framework/templates/docs/user-stories.md +34 -0
  149. package/.morph/framework/templates/examples/design-system-examples.md +357 -0
  150. package/.morph/framework/templates/examples/spec-examples.md +90 -0
  151. package/.morph/framework/templates/feature/decisions.md +187 -0
  152. package/.morph/framework/templates/feature/recap.md +146 -0
  153. package/.morph/framework/templates/feature/tasks.md +199 -0
  154. package/.morph/framework/templates/frontend/nextjs/Dockerfile.nextjs.hbs +43 -0
  155. package/.morph/framework/templates/frontend/nextjs/client-component.tsx.hbs +26 -0
  156. package/.morph/framework/templates/frontend/nextjs/env.mjs.hbs +32 -0
  157. package/.morph/framework/templates/frontend/nextjs/feature-form.tsx.hbs +56 -0
  158. package/.morph/framework/templates/frontend/nextjs/page.tsx.hbs +22 -0
  159. package/.morph/framework/templates/frontend/nextjs/tsconfig.json.hbs +26 -0
  160. package/.morph/framework/templates/frontend/nextjs/use-feature.ts.hbs +54 -0
  161. package/.morph/framework/templates/infrastructure/azure/Dockerfile.example +82 -0
  162. package/.morph/framework/templates/infrastructure/azure/README.md +286 -0
  163. package/.morph/framework/templates/infrastructure/azure/app-insights.bicep +63 -0
  164. package/.morph/framework/templates/infrastructure/azure/app-service.bicep +164 -0
  165. package/.morph/framework/templates/infrastructure/azure/container-app-env.bicep +49 -0
  166. package/.morph/framework/templates/infrastructure/azure/container-app.bicep +156 -0
  167. package/.morph/framework/templates/infrastructure/azure/deploy-checklist.md +426 -0
  168. package/.morph/framework/templates/infrastructure/azure/deploy.ps1 +229 -0
  169. package/.morph/framework/templates/infrastructure/azure/deploy.sh +208 -0
  170. package/.morph/framework/templates/infrastructure/azure/key-vault.bicep +91 -0
  171. package/.morph/framework/templates/infrastructure/azure/main.bicep +189 -0
  172. package/.morph/framework/templates/infrastructure/azure/parameters.dev.json +29 -0
  173. package/.morph/framework/templates/infrastructure/azure/parameters.prod.json +29 -0
  174. package/.morph/framework/templates/infrastructure/azure/parameters.staging.json +29 -0
  175. package/.morph/framework/templates/infrastructure/azure/sql-database.bicep +103 -0
  176. package/.morph/framework/templates/infrastructure/azure/storage.bicep +106 -0
  177. package/.morph/framework/templates/infrastructure/docker/Dockerfile.template +58 -0
  178. package/.morph/framework/templates/infrastructure/docker/docker-compose.template.yml +67 -0
  179. package/.morph/framework/templates/infrastructure/docker/dockerfile-api.dockerfile +38 -0
  180. package/.morph/framework/templates/infrastructure/docker/dockerfile-web.dockerfile +48 -0
  181. package/.morph/framework/templates/infrastructure/docker/easypanel.template.json +54 -0
  182. package/.morph/framework/templates/infrastructure/github/README.md +593 -0
  183. package/.morph/framework/templates/infrastructure/github/actions/azure-auth/action.yml.hbs +22 -0
  184. package/.morph/framework/templates/infrastructure/github/actions/docker-build-push/action.yml.hbs +45 -0
  185. package/.morph/framework/templates/infrastructure/github/actions/health-check/action.yml.hbs +27 -0
  186. package/.morph/framework/templates/infrastructure/github/workflows/deploy-azure-app-service.yml.hbs +61 -0
  187. package/.morph/framework/templates/infrastructure/github/workflows/deploy-easypanel.yml.hbs +31 -0
  188. package/.morph/framework/templates/infrastructure/github/workflows/docker-build-push.yml.hbs +59 -0
  189. package/.morph/framework/templates/infrastructure/github/workflows/dotnet-build.yml.hbs +39 -0
  190. package/.morph/framework/templates/integrations/asaas-client.cs +387 -0
  191. package/.morph/framework/templates/integrations/asaas-webhook.cs +351 -0
  192. package/.morph/framework/templates/integrations/azure-identity-config.cs +288 -0
  193. package/.morph/framework/templates/integrations/clerk-config.cs +258 -0
  194. package/.morph/framework/templates/meta-prompts/fusion/fusion-agent.md +76 -0
  195. package/.morph/framework/templates/meta-prompts/fusion/fusion-aggregator.md +100 -0
  196. package/.morph/framework/templates/meta-prompts/hops/hop-retry.md +78 -0
  197. package/.morph/framework/templates/meta-prompts/hops/hop-validation.md +97 -0
  198. package/.morph/framework/templates/meta-prompts/hops/hop-wrapper.md +36 -0
  199. package/.morph/framework/templates/meta-prompts/parallel-workers/parallel-coordinator.md +113 -0
  200. package/.morph/framework/templates/meta-prompts/parallel-workers/parallel-worker.md +80 -0
  201. package/.morph/framework/templates/meta-prompts/squad-leaders/backend-squad.md +90 -0
  202. package/.morph/framework/templates/meta-prompts/squad-leaders/frontend-squad.md +126 -0
  203. package/.morph/framework/templates/meta-prompts/squad-leaders/squad-leader.md +43 -0
  204. package/.morph/framework/templates/meta-prompts/validators/checkpoint-validator.md +107 -0
  205. package/.morph/framework/templates/meta-prompts/validators/pre-commit-validator.md +95 -0
  206. package/.morph/framework/templates/project-structure/dotnet-ddd.md +70 -0
  207. package/.morph/framework/templates/saas/subscription.cs +347 -0
  208. package/.morph/framework/templates/saas/tenant.cs +338 -0
  209. package/.morph/framework/templates/state.template.json +17 -0
  210. package/.morph/framework/templates/ui/FluentDesignTheme.cs +149 -0
  211. package/.morph/framework/templates/ui/MudTheme.cs +281 -0
  212. package/.morph/framework/templates/ui/design-system.css +226 -0
  213. package/.morph/logs/tool-failures.log +17 -0
  214. package/.morph/memory/pre-compact-2026-02-24T17-43-30-049Z.json +16 -0
  215. package/.morph/plans/eager-watching-bunny.md +105 -0
  216. package/.morph/plans/temporal-seeking-nebula.md +45 -0
  217. package/.morph/state.json +48 -0
  218. package/CLAUDE.md +1 -1
  219. package/README.md +2 -2
  220. package/bin/morph-spec.js +0 -9
  221. package/framework/CLAUDE.md +1 -1
  222. package/framework/hooks/README.md +10 -6
  223. package/framework/hooks/claude-code/notification/approval-reminder.js +2 -0
  224. package/framework/hooks/claude-code/post-tool-use/dispatch.js +1 -1
  225. package/framework/hooks/claude-code/stop/validate-completion.js +1 -1
  226. package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +1 -1
  227. package/package.json +1 -1
  228. package/src/commands/project/init.js +15 -42
  229. package/src/commands/project/update.js +22 -37
  230. package/src/lib/installers/mcp-installer.js +18 -3
  231. package/src/utils/hooks-installer.js +5 -15
  232. package/src/commands/project/detect.js +0 -114
@@ -0,0 +1,105 @@
1
+ # Plan: Fix Statusline Not Being Installed
2
+
3
+ ## Context
4
+
5
+ `morph-spec init` is supposed to install the global statusline to `~/.claude/` so
6
+ it appears in every Claude Code session. Two bugs exist:
7
+
8
+ 1. **`update.js` never calls `installGlobalStatusline`** — running `morph-spec update`
9
+ leaves the statusline missing or stale, and there is no path for existing users to
10
+ get it without running `init` from scratch.
11
+ 2. **No success confirmation in `init.js` output** — after a successful installation the
12
+ "Files installed:" list never mentions `~/.claude/statusline.sh`, so users assume
13
+ it was skipped (especially since failures are silently swallowed by a bare `catch {}`).
14
+
15
+ Root cause confirmed by: reading `update.js` (no `installGlobalStatusline` import or call)
16
+ and `init.js` lines 462–505 (success block omits statusline entry). Tests for
17
+ `installGlobalStatusline` in isolation pass; there is no integration test covering the
18
+ init/update flow.
19
+
20
+ ---
21
+
22
+ ## Critical Files
23
+
24
+ | File | Change |
25
+ |------|--------|
26
+ | `src/commands/project/update.js` | Add `installGlobalStatusline` import + call |
27
+ | `src/commands/project/init.js` | Add `✓ ~/.claude/statusline.sh` to success output |
28
+ | `test/hooks/hooks-installer.test.js` | Already has good coverage — no change needed |
29
+ | `test/commands/init.test.js` | Add `statusline-installation` describe suite |
30
+
31
+ ---
32
+
33
+ ## Implementation Steps
34
+
35
+ ### 1. `update.js` — Add statusline installation
36
+
37
+ **File:** `src/commands/project/update.js`
38
+
39
+ **Import change** (line 27 — extend existing destructure):
40
+ ```js
41
+ import { installClaudeHooks, installGlobalStatusline } from '../../utils/claude-settings-manager.js';
42
+ ```
43
+
44
+ **Call** — insert after the CLAUDE.md sync block (after line 280, before "Update Claude
45
+ Code hooks" at line 282):
46
+ ```js
47
+ // Sync statusline globally to ~/.claude/
48
+ updateSpinner.text = 'Syncing statusline to ~/.claude/...';
49
+ const HOOKS_SRC = join(__dirname, '..', '..', '..', 'framework', 'hooks', 'claude-code');
50
+ try {
51
+ await installGlobalStatusline(HOOKS_SRC);
52
+ } catch {
53
+ // Non-critical: global dir may not be writable in all environments
54
+ logger.dim(' ⚠ Could not install statusline globally (non-critical)');
55
+ }
56
+ ```
57
+
58
+ **Success output** — add line after `.claude/CLAUDE.md` entry (around line 324):
59
+ ```js
60
+ logger.dim(' ✓ ~/.claude/statusline.sh (global statusline synced)');
61
+ ```
62
+
63
+ Note: `update.js` already uses `__dirname` (defined at line 6 via `fileURLToPath`),
64
+ so use `__dirname` instead of `import.meta.dirname` to stay consistent with the file.
65
+
66
+ ---
67
+
68
+ ### 2. `init.js` — Add statusline to success output
69
+
70
+ **File:** `src/commands/project/init.js`
71
+
72
+ After line 505 (`logger.dim(' ✓ .claude/agents/...')`), add:
73
+ ```js
74
+ logger.dim(' ✓ ~/.claude/statusline.sh (global statusline installed)');
75
+ ```
76
+
77
+ This line is unconditional — the installation is always attempted and the message
78
+ reflects the intent (mirrors how skills/agents are always listed even without a flag).
79
+
80
+ ---
81
+
82
+ ### 3. `test/commands/init.test.js` — Add statusline integration test suite
83
+
84
+ Add a new `describe('statusline-installation')` block that:
85
+ - Calls `installGlobalStatusline` directly with a `globalClaudeDirOverride` temp dir
86
+ and the real `framework/hooks/claude-code` source path
87
+ - Asserts `statusline.sh` and `statusline.py` were copied
88
+ - Asserts `settings.json` has a `statusLine` key pointing to `statusline.sh`
89
+
90
+ This mirrors the pattern used by the `rules-installation` suite.
91
+
92
+ ---
93
+
94
+ ## Verification
95
+
96
+ ```bash
97
+ # Run full test suite — must stay green (678+ pass, 0 fail)
98
+ node --test --test-concurrency=1
99
+
100
+ # Smoke test update path
101
+ node bin/morph-spec.js update --skip-detection --skip-mcp 2>&1 | grep -i statusline
102
+
103
+ # Manually verify ~/.claude/statusline.sh exists and settings.json has statusLine key
104
+ node -e "const s = require('fs').readFileSync(require('os').homedir()+'/.claude/settings.json','utf8'); console.log(JSON.parse(s).statusLine)"
105
+ ```
@@ -0,0 +1,45 @@
1
+ # Plan: Remove `detect` command and fix `init` for PowerShell execution
2
+
3
+ ## Context
4
+
5
+ `morph-spec init` is run from PowerShell (not inside Claude Code), so `detectClaudeCode()` always returns false, making step 13 a dead code branch that shows a confusing warning. `morph-spec detect` is registered but provides no additional value beyond what `init` already does with `detectProject()`. `--wizard` is referenced in messages but was never registered as a CLI option. This plan removes the dead code and makes `init` self-sufficient.
6
+
7
+ ## What changes
8
+
9
+ ### 1. Delete `src/commands/project/detect.js`
10
+ The command is obsolete — its functionality (stack/arch detection + saving to `.morph/project/context/`) is superseded by the `detectProject()` call already inside `init` at step 11c.
11
+
12
+ ### 2. `bin/morph-spec.js`
13
+ - Remove `import { detectCommand }` (line 14)
14
+ - Remove the `.command('detect')` block (lines 131–136)
15
+
16
+ ### 3. `src/commands/project/init.js`
17
+ - Remove imports: `AutoContextOrchestrator` (line 21), `detectClaudeCode` (line 22)
18
+ - **Remove step 13 entirely** (lines 509–540) — the entire `if (!options.skipDetection && detectClaudeCode())` / `else if` / `else` block
19
+ - Fix context README.md template (line 110): remove `Run \`morph-spec detect\`` sentence, replace with `Edit this file to describe your project context.`
20
+ - Fix Next Steps (line 470): remove `logger.step(1, 'Run detection: morph-spec detect')`, renumber remaining steps (step 1 → "Review .morph/config/config.json", step 2 → "Open project in VS Code with Claude Code", step 3 → "Start your first feature:")
21
+
22
+ ### 4. `src/commands/project/update.js`
23
+ - Remove imports: `AutoContextOrchestrator`, `detectClaudeCode` (lines ~3–4 in that file)
24
+ - Remove the `if (!options.skipDetection && detectClaudeCode())` / `else if` / `else` block (lines 331–363)
25
+
26
+ ## Files to modify
27
+ - `bin/morph-spec.js`
28
+ - `src/commands/project/init.js`
29
+ - `src/commands/project/update.js`
30
+
31
+ ## Files to delete
32
+ - `src/commands/project/detect.js`
33
+
34
+ ## Files NOT changed
35
+ - `test/integration/wizard-fallback.test.js` — tests `mapAnswersToConfig()` from `wizard-questions.js`, unrelated to detect command; still passes
36
+ - `test/commands/init.test.js` — no references to detect/wizard/detectClaudeCode; unaffected
37
+ - `src/core/orchestrator.js`, `src/ui/wizard-questions.js`, `src/llm/environment-detector.js` — left in place (may be used elsewhere); just remove imports/usage from init+update
38
+ - `src/lib/detectors/index.js` + `detectProject()` — **kept** in init (step 11c); this is the static file-based stack detection that works without Claude Code
39
+
40
+ ## Verification
41
+ 1. `node bin/morph-spec.js --help` — `detect` command should no longer appear
42
+ 2. `node bin/morph-spec.js init --help` — no `--skip-detection` or `--wizard` references
43
+ 3. `node bin/morph-spec.js update --help` — same
44
+ 4. Run test suite: `npm test` — should still pass 678 tests (no tests reference detect/wizard in init.test.js)
45
+ 5. Manual: run `morph-spec init` from PowerShell in a test project — should complete without the "Claude Code not detected" warning
@@ -0,0 +1,48 @@
1
+ {
2
+ "version": "4.0.0",
3
+ "features": {
4
+ "override-feature": {
5
+ "status": "in_progress",
6
+ "phase": "implement",
7
+ "tasks": {
8
+ "total": 20,
9
+ "completed": 30
10
+ },
11
+ "checkpoints": [
12
+ {
13
+ "passed": true
14
+ },
15
+ {
16
+ "passed": true
17
+ },
18
+ {
19
+ "passed": false
20
+ },
21
+ {
22
+ "passed": false
23
+ },
24
+ {
25
+ "passed": false
26
+ },
27
+ {
28
+ "passed": false
29
+ },
30
+ {
31
+ "passed": false
32
+ },
33
+ {
34
+ "passed": false
35
+ },
36
+ {
37
+ "passed": false
38
+ },
39
+ {
40
+ "passed": false
41
+ }
42
+ ],
43
+ "trustConfig": {}
44
+ }
45
+ },
46
+ "threads": {},
47
+ "metadata": {}
48
+ }
package/CLAUDE.md CHANGED
@@ -56,7 +56,7 @@
56
56
  proposal → setup → [uiux] → design → clarify → tasks → implement → [sync]
57
57
  ```
58
58
 
59
- Use `morph-spec state show {feature}` to see current phase and pending approval gates.
59
+ Use `morph-spec status {feature}` to see current phase and pending approval gates.
60
60
 
61
61
  ---
62
62
 
package/README.md CHANGED
@@ -3,7 +3,7 @@
3
3
  > Spec-driven development framework for multi-stack projects. Turns feature requests into implementation-ready code through structured, AI-orchestrated phases.
4
4
 
5
5
  **Package:** `@polymorphism-tech/morph-spec`
6
- **Version:** 4.7.1
6
+ **Version:** 4.7.2
7
7
  **Requires:** Node.js 18+, Claude Code
8
8
 
9
9
  ---
@@ -282,7 +282,7 @@ Path-scoped rules are installed to `.claude/rules/` and activate automatically b
282
282
  | `morph-workflow.md` | Always active — spec-first mandate, phase commands |
283
283
  | `csharp-standards.md` | `**/*.cs`, `**/*.csproj` |
284
284
  | `frontend-standards.md` | `**/*.razor`, `**/*.tsx`, `**/*.ts`, `**/*.css` |
285
- | `testing-standards.md` | `tests/**`, `**/*.test.*`, `**/*.spec.*`, `**/*Tests.cs` |
285
+ | `testing-standards.md` | `tests/`**, `**/*.test.*`, `**/*.spec.*`, `**/*Tests.cs` |
286
286
  | `infrastructure-standards.md` | `**/*.bicep`, `**/Dockerfile`, `**/pipelines/**` |
287
287
 
288
288
 
package/bin/morph-spec.js CHANGED
@@ -11,7 +11,6 @@ import { initCommand } from '../src/commands/project/init.js';
11
11
  import { updateCommand } from '../src/commands/project/update.js';
12
12
  import { updateAgentsCommand } from '../src/commands/project/update-agents.js';
13
13
  import { doctorCommand } from '../src/commands/project/doctor.js';
14
- import { detectCommand } from '../src/commands/project/detect.js';
15
14
 
16
15
  import { syncCommand } from '../src/commands/project/sync.js';
17
16
  import { statusCommand } from '../src/commands/project/status.js';
@@ -127,14 +126,6 @@ program
127
126
  .option('--reset', 'Remove morph-managed entries from .claude/settings.local.json')
128
127
  .action(doctorCommand);
129
128
 
130
- program
131
- .command('detect')
132
- .description('Detect project stack, architecture, and patterns')
133
- .option('-p, --path <path>', 'Project path (default: current directory)')
134
- .option('-v, --verbose', 'Show detailed detection results')
135
- .option('--no-save', 'Do not save results to .morph/project/')
136
- .action(detectCommand);
137
-
138
129
  program
139
130
  .command('sync')
140
131
  .description('Sync standards from feature decisions')
@@ -56,7 +56,7 @@
56
56
  proposal → setup → [uiux] → design → clarify → tasks → implement → [sync]
57
57
  ```
58
58
 
59
- Use `morph-spec state show {feature}` to see current phase and pending approval gates.
59
+ Use `morph-spec status {feature}` to see current phase and pending approval gates.
60
60
 
61
61
  ---
62
62
 
@@ -47,13 +47,13 @@ framework/hooks/
47
47
  |-------|------|------|---------|
48
48
  | **SessionStart** | inject-morph-context.js | Inject context | Shows active feature, phase, pending approvals |
49
49
  | **UserPromptSubmit** | enrich-prompt.js | Inject context | Warns about wrong-phase work, injects commands |
50
- | **PreToolUse** (Write\|Edit) | protect-readonly-files.js | Block | Blocks edits to state.json and .morph/framework/ |
50
+ | **PreToolUse** (Write\|Edit) | _(native permissions.deny)_ | Block | Blocks edits to state.json and .morph/framework/ |
51
51
  | **PreToolUse** (Write\|Edit) | protect-spec-files.js | Block | Blocks edits to spec files after approval |
52
52
  | **PreToolUse** (Write\|Edit) | enforce-phase-writes.js | Block | Ensures writes go to current phase directory |
53
53
  | **PreToolUse** (Bash) | _(prompt-type inline guard)_ | Block | Blocks `rm -rf .morph/` and direct state edits via Claude's reasoning |
54
- | **PostToolUse** (Write) | track-output-creation.js | Auto-state | Marks outputs as created when files are written |
55
54
  | **PostToolUse** (Bash) | dispatch.js | Dispatch | Triggers checkpoints on task completion |
56
- | **Stop** | validate-completion.js | Advisory | Warns about incomplete tasks/outputs |
55
+ | **PostToolUseFailure** | handle-tool-failure.js | Logging | Appends structured JSON to .morph/logs/tool-failures.log |
56
+ | **Stop** | validate-completion.js | Advisory | Warns about incomplete tasks/missing outputs/pending gates |
57
57
  | **PreCompact** | save-morph-context.js | Snapshot | Saves state to .morph/memory/ before compaction |
58
58
  | **Notification** | approval-reminder.js | Advisory | Reminds about pending approval gates |
59
59
 
@@ -69,6 +69,10 @@ framework/hooks/
69
69
 
70
70
  Hooks are automatically installed by `morph-spec init` and updated by `morph-spec update`.
71
71
 
72
+ During init/update, the entire `framework/hooks/` directory is copied to `.morph/framework/hooks/`.
73
+ Hook commands in `.claude/settings.local.json` reference `$CLAUDE_PROJECT_DIR/.morph/framework/hooks/`
74
+ so they work correctly in any project regardless of how morph-spec was installed.
75
+
72
76
  The installer writes to `.claude/settings.local.json`:
73
77
 
74
78
  ```json
@@ -122,10 +126,10 @@ Claude calls Write/Edit tool
122
126
 
123
127
  Claude Code sends JSON to stdin: { tool_input: { file_path: "..." } }
124
128
 
125
- protect-readonly-files.js
129
+ [native permissions.deny]
126
130
  ├── Is .morph/state.json? → BLOCK (use CLI)
127
131
  ├── Is .morph/framework/**? → BLOCK (read-only)
128
- └── Other → pass
132
+ └── Other → continue
129
133
 
130
134
  protect-spec-files.js
131
135
  ├── Is in .morph/features/{feature}/?
@@ -198,4 +202,4 @@ morph-spec doctor --reset
198
202
 
199
203
  ---
200
204
 
201
- *MORPH-SPEC v4.3.7 — Hooks Architecture v2*
205
+ *MORPH-SPEC v4.5.0 — Hooks Architecture v2.5*
@@ -26,6 +26,8 @@ try {
26
26
 
27
27
  // Only remind about gates relevant to the current phase
28
28
  const phaseGateRelevance = {
29
+ proposal: ['proposal'],
30
+ setup: ['proposal'],
29
31
  design: ['design'],
30
32
  clarify: ['design'],
31
33
  tasks: ['design', 'tasks'],
@@ -46,7 +46,7 @@ function dispatch(command) {
46
46
  const completed = (feature.tasks.completed || 0) + 1; // +1 because task-done hasn't executed yet
47
47
  if (completed > 0 && completed % 3 === 0) {
48
48
  const checkpointNum = Math.floor(completed / 3);
49
- run(`node bin/morph-spec.js checkpoint-save ${featureName} --note "Auto-checkpoint #${checkpointNum} at task ${completed}"`);
49
+ run(`morph-spec checkpoint-save ${featureName} --note "Auto-checkpoint #${checkpointNum} at task ${completed}"`);
50
50
  }
51
51
  }
52
52
  } catch {
@@ -58,7 +58,7 @@ try {
58
58
  // Check pending approval gates
59
59
  if (feature.approvalGates) {
60
60
  const pendingGates = Object.entries(feature.approvalGates)
61
- .filter(([, gate]) => !gate.approved && gate.timestamp === null)
61
+ .filter(([, gate]) => !gate.approved && !gate.timestamp)
62
62
  .map(([name]) => name);
63
63
 
64
64
  // Only warn about gates relevant to current/past phases
@@ -24,7 +24,7 @@ try {
24
24
  const payload = await readStdin();
25
25
  if (!payload) pass();
26
26
 
27
- const userPrompt = payload?.user_prompt || payload?.content || '';
27
+ const userPrompt = payload?.prompt || payload?.user_prompt || payload?.content || '';
28
28
  if (!userPrompt || userPrompt.length < 3) pass();
29
29
 
30
30
  const promptLower = userPrompt.toLowerCase();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polymorphism-tech/morph-spec",
3
- "version": "4.7.1",
3
+ "version": "4.7.2",
4
4
  "description": "MORPH-SPEC: AI-First development framework with validation pipeline and multi-stack support",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -18,8 +18,6 @@ import { saveProjectMorphVersion, getInstalledCLIVersion } from '../../utils/ver
18
18
  import { installClaudeHooks, installGlobalStatusline } from '../../utils/claude-settings-manager.js';
19
19
  import { installSkills } from '../../utils/skills-installer.js';
20
20
  import { installAgents, installDomainAgents } from '../../utils/agents-installer.js';
21
- import { AutoContextOrchestrator } from '../../core/orchestrator.js';
22
- import { detectClaudeCode } from '../../llm/environment-detector.js';
23
21
  import inquirer from 'inquirer';
24
22
  import { detectProject } from '../../lib/detectors/index.js';
25
23
  import { detectClaudeConfig, mapMcpsToPhases, formatConfigSummary } from '../../lib/detectors/claude-config-detector.js';
@@ -102,11 +100,11 @@ export async function initCommand(options) {
102
100
 
103
101
  ## Overview
104
102
 
105
- This file will be auto-updated by MORPH-SPEC detection system.
103
+ This file describes your project context for MORPH-SPEC agents.
106
104
 
107
105
  ## Stack
108
106
 
109
- Run \`morph-spec detect\` to analyze your project.
107
+ Edit this file to describe your project context.
110
108
 
111
109
  ## Technologies
112
110
 
@@ -139,6 +137,14 @@ Run \`morph-spec detect\` to analyze your project.
139
137
  logger.dim(' ✓ Copied framework standards: core/, backend/, frontend/, infrastructure/');
140
138
  }
141
139
 
140
+ // 6c. Copy hooks to .morph/framework/hooks/ (required for hook commands at runtime)
141
+ spinner.text = 'Copying hooks...';
142
+ const hooksSrc = join(import.meta.dirname, '..', '..', '..', 'framework', 'hooks');
143
+ const hooksDest = join(frameworkDestDir, 'hooks');
144
+ if (await pathExists(hooksSrc)) {
145
+ await copyDirectory(hooksSrc, hooksDest);
146
+ }
147
+
142
148
  // 7. Copy agents.json (sourced from framework/ — canonical single source of truth)
143
149
  spinner.text = 'Copying agents configuration...';
144
150
  const agentsSrc = join(import.meta.dirname, '..', '..', '..', 'framework', 'agents.json');
@@ -467,10 +473,9 @@ Run \`morph-spec detect\` to analyze your project.
467
473
  logger.blank();
468
474
  logger.header('Next Steps');
469
475
 
470
- logger.step(1, 'Run detection: morph-spec detect');
471
- logger.step(2, 'Review .morph/config/config.json and .morph/context/standards.md');
472
- logger.step(3, 'Open project in VS Code with Claude Code');
473
- logger.step(4, 'Start your first feature:');
476
+ logger.step(1, 'Review .morph/config/config.json');
477
+ logger.step(2, 'Open project in VS Code with Claude Code');
478
+ logger.step(3, 'Start your first feature:');
474
479
  logger.blank();
475
480
  logger.box([
476
481
  'Ask Claude Code to implement a feature'
@@ -480,7 +485,7 @@ Run \`morph-spec detect\` to analyze your project.
480
485
  logger.info('Files installed:');
481
486
  logger.dim(` ✓ CLAUDE.md`);
482
487
  logger.dim(` ✓ .morph/config/ (config.json)`);
483
- logger.dim(` ✓ .morph/framework/ (agents.json, standards/, templates/)`);
488
+ logger.dim(` ✓ .morph/framework/ (agents.json, standards/, templates/, hooks/)`);
484
489
  logger.dim(` ✓ .morph/context/ (project context)`);
485
490
  logger.dim(` ✓ .morph/features/ (feature outputs)`);
486
491
  if (commandsCopied) {
@@ -503,42 +508,10 @@ Run \`morph-spec detect\` to analyze your project.
503
508
 
504
509
  logger.dim(' ✓ .claude/skills/ (installed as skill directories)');
505
510
  logger.dim(' ✓ .claude/agents/ (native subagents installed)');
511
+ logger.dim(' ✓ ~/.claude/statusline.sh (global statusline installed)');
506
512
 
507
513
  logger.blank();
508
514
 
509
- // 13. LLM-based auto-detect project context (if Claude Code is available and not --skip-detection)
510
- if (!options.skipDetection && detectClaudeCode()) {
511
- logger.blank();
512
- logger.header('Auto-Detecting Project Context');
513
- logger.dim('Using Claude Code LLM to analyze your project...');
514
- logger.blank();
515
-
516
- try {
517
- const orchestrator = new AutoContextOrchestrator();
518
- const result = await orchestrator.execute(targetPath, {
519
- skipReview: false,
520
- fallbackOnError: true,
521
- wizardMode: options.wizard || false
522
- });
523
-
524
- if (result.success) {
525
- logger.success('Project context detected and saved to .morph/project.md');
526
- } else {
527
- logger.warn('Auto-detection incomplete. Run "morph-spec update" to retry.');
528
- }
529
- } catch (error) {
530
- logger.warn(`Auto-detection failed: ${error.message}`);
531
- logger.dim('You can run "morph-spec update" later to re-analyze your project.');
532
- }
533
- } else if (options.skipDetection) {
534
- logger.dim('\nSkipped auto-detection (--skip-detection flag)');
535
- logger.dim('Run "morph-spec update" later to analyze your project.');
536
- } else {
537
- logger.warn('\n⚠️ Claude Code not detected');
538
- logger.dim('Auto-detection requires Claude Code CLI.');
539
- logger.dim('Run "morph-spec update --wizard" to configure manually.');
540
- }
541
-
542
515
  // Suggest tutorial for first-time users
543
516
  if (integrationsCreated) {
544
517
  logger.blank();
@@ -24,11 +24,9 @@ import {
24
24
  getUpdateInstructions,
25
25
  detectInstallMethod
26
26
  } from '../../utils/version-checker.js';
27
- import { installClaudeHooks } from '../../utils/claude-settings-manager.js';
27
+ import { installClaudeHooks, installGlobalStatusline } from '../../utils/claude-settings-manager.js';
28
28
  import { installSkills } from '../../utils/skills-installer.js';
29
29
  import { installAgents, installDomainAgents } from '../../utils/agents-installer.js';
30
- import { AutoContextOrchestrator } from '../../core/orchestrator.js';
31
- import { detectClaudeCode } from '../../llm/environment-detector.js';
32
30
 
33
31
  /**
34
32
  * Backup user's config.json before cleaning
@@ -57,6 +55,7 @@ async function cleanFrameworkDirs(morphPath, targetPath) {
57
55
  const dirsToClean = [
58
56
  join(morphPath, 'framework', 'templates'),
59
57
  join(morphPath, 'framework', 'standards'),
58
+ join(morphPath, 'framework', 'hooks'),
60
59
  join(morphPath, 'config'),
61
60
  join(targetPath, '.claude')
62
61
  ];
@@ -208,6 +207,14 @@ export async function updateCommand(options) {
208
207
  await copyDirectory(standardsSrc, standardsDest);
209
208
  }
210
209
 
210
+ // Update hooks (runtime hook scripts under .morph/framework/hooks/)
211
+ updateSpinner.text = 'Updating hooks...';
212
+ const hooksSrc = join(__dirname, '..', '..', '..', 'framework', 'hooks');
213
+ const hooksDest = join(morphPath, 'framework', 'hooks');
214
+ if (await pathExists(hooksSrc)) {
215
+ await copyDirectory(hooksSrc, hooksDest);
216
+ }
217
+
211
218
  // Update agents.json (sourced from framework/ — canonical single source of truth)
212
219
  updateSpinner.text = 'Updating agents configuration...';
213
220
  const agentsSrc = join(__dirname, '..', '..', '..', 'framework', 'agents.json');
@@ -279,6 +286,16 @@ export async function updateCommand(options) {
279
286
  await copyFile(runtimeSrc, runtimeDest);
280
287
  }
281
288
 
289
+ // Sync statusline globally to ~/.claude/
290
+ updateSpinner.text = 'Syncing statusline to ~/.claude/...';
291
+ const HOOKS_SRC = join(__dirname, '..', '..', '..', 'framework', 'hooks', 'claude-code');
292
+ try {
293
+ await installGlobalStatusline(HOOKS_SRC);
294
+ } catch {
295
+ // Non-critical: global dir may not be writable in all environments
296
+ logger.dim(' ⚠ Could not install statusline globally (non-critical)');
297
+ }
298
+
282
299
  // Update Claude Code hooks in .claude/settings.local.json
283
300
  updateSpinner.text = 'Updating Claude Code hooks...';
284
301
  const hooksResult = await installClaudeHooks(targetPath);
@@ -314,6 +331,7 @@ export async function updateCommand(options) {
314
331
  logger.info('Updated files:');
315
332
  if (updateTemplates) logger.dim(' ✓ .morph/framework/templates/');
316
333
  if (updateStandards) logger.dim(' ✓ .morph/framework/standards/');
334
+ logger.dim(' ✓ .morph/framework/hooks/');
317
335
  logger.dim(' ✓ .morph/framework/agents.json');
318
336
  if (commandsCopied) logger.dim(' ✓ .claude/commands/');
319
337
 
@@ -322,46 +340,13 @@ export async function updateCommand(options) {
322
340
  logger.dim(' ✓ .claude/agents/ (native subagents refreshed)');
323
341
  logger.dim(' ✓ .claude/rules/ (path-scoped rules synced)');
324
342
  logger.dim(' ✓ .claude/CLAUDE.md (runtime quick reference)');
343
+ logger.dim(' ✓ ~/.claude/statusline.sh (global statusline synced)');
325
344
  logger.dim(' ✓ CLAUDE.md');
326
345
  logger.blank();
327
346
  logger.info('Your config.json was preserved.');
328
347
  logger.dim('Review the updated files for any new features.');
329
348
  logger.blank();
330
349
 
331
- // Re-analyze project context (unless --skip-detection)
332
- if (!options.skipDetection && detectClaudeCode()) {
333
- logger.header('Re-Analyzing Project Context');
334
- logger.dim('Using Claude Code LLM to update project detection...');
335
- logger.blank();
336
-
337
- try {
338
- const orchestrator = new AutoContextOrchestrator();
339
- const result = await orchestrator.execute(targetPath, {
340
- skipReview: false,
341
- fallbackOnError: true,
342
- wizardMode: options.wizard || false
343
- });
344
-
345
- if (result.success) {
346
- logger.success('Project context re-analyzed and updated');
347
- logger.dim(' ✓ .morph/project.md updated with latest detection');
348
- logger.dim(' ✓ .morph/config/config.json updated with stack info');
349
- } else {
350
- logger.warn('Context re-analysis incomplete');
351
- }
352
- } catch (error) {
353
- logger.warn(`Auto-detection failed: ${error.message}`);
354
- logger.dim('Your existing config.json was preserved.');
355
- }
356
-
357
- logger.blank();
358
- } else if (options.skipDetection) {
359
- logger.dim('Skipped auto-detection (--skip-detection flag)');
360
- } else {
361
- logger.warn('⚠️ Claude Code not detected - skipping auto-detection');
362
- logger.dim('Run with --wizard to configure manually.');
363
- }
364
-
365
350
  } catch (error) {
366
351
  updateSpinner.fail('Update failed');
367
352
  logger.error(error.message);
@@ -96,6 +96,21 @@ export function checkPrerequisites(mcpEntry) {
96
96
  return results;
97
97
  }
98
98
 
99
+ /**
100
+ * Patch MCP config for the current platform.
101
+ * On Windows, npx must be invoked via `cmd /C` to avoid ENOENT errors.
102
+ * @param {Object} config - MCP server config { command, args, env? }
103
+ * @returns {Object} Patched config (new object, original unmodified)
104
+ */
105
+ export function patchConfigForPlatform(config) {
106
+ if (process.platform !== 'win32' || config.command !== 'npx') return config;
107
+ return {
108
+ ...config,
109
+ command: 'cmd',
110
+ args: ['/C', 'npx', ...(config.args || [])]
111
+ };
112
+ }
113
+
99
114
  /**
100
115
  * Install auto-installable MCPs (no credentials, no prerequisites)
101
116
  * @param {string} targetPath - Project root directory
@@ -106,12 +121,12 @@ export async function installAutoMcps(targetPath, mcpsToInstall) {
106
121
  const servers = {};
107
122
 
108
123
  for (const [name, entry] of Object.entries(mcpsToInstall)) {
109
- const config = { ...entry.install.config };
124
+ let config = { ...entry.install.config };
110
125
  // Only include env if it has actual values
111
126
  if (config.env && Object.values(config.env).every(v => !v)) {
112
127
  delete config.env;
113
128
  }
114
- servers[name] = config;
129
+ servers[name] = patchConfigForPlatform(config);
115
130
  }
116
131
 
117
132
  return installMcpServers(targetPath, servers);
@@ -126,7 +141,7 @@ export async function installAutoMcps(targetPath, mcpsToInstall) {
126
141
  * @returns {Promise<Object>} Result from installMcpServers
127
142
  */
128
143
  export async function installMcpWithCredentials(targetPath, name, mcpEntry, credentialValues) {
129
- const config = { ...mcpEntry.install.config };
144
+ const config = patchConfigForPlatform({ ...mcpEntry.install.config });
130
145
  config.env = { ...config.env, ...credentialValues };
131
146
  return installMcpServers(targetPath, { [name]: config });
132
147
  }
@@ -14,7 +14,7 @@ import { existsSync, chmodSync } from 'fs';
14
14
  import { homedir } from 'os';
15
15
 
16
16
  /** Current hooks schema version — bump when hook definitions change */
17
- const HOOKS_VERSION = '2.4.0';
17
+ const HOOKS_VERSION = '2.5.0';
18
18
 
19
19
  /** Marker for old dispatch.js (v1) */
20
20
  const OLD_DISPATCH_COMMAND = 'node framework/hooks/agent-teams/dispatch.js';
@@ -104,19 +104,8 @@ Otherwise respond: {"ok": true}`
104
104
  event: 'Stop',
105
105
  matcher: null,
106
106
  hooks: [{
107
- type: 'agent',
108
- prompt: `Check if the active morph-spec feature phase outputs are complete.
109
- 1. Read the file .morph/state.json to find features with status "in_progress".
110
- 2. For each in_progress feature, check if required output files for the current phase exist and are non-empty.
111
- - proposal phase: .morph/features/{feature}/0-proposal/proposal.md
112
- - design phase: .morph/features/{feature}/1-design/spec.md
113
- - tasks phase: .morph/features/{feature}/3-tasks/tasks.md
114
- - implement phase: check tasks.completed vs tasks.total from state.json
115
- 3. If all required outputs exist and tasks are complete, return {"ok": true}.
116
- 4. If any required output is missing or empty, return {"ok": false, "reason": "Missing output: <path>"}.
117
- 5. If state.json does not exist or no feature is in_progress, return {"ok": true}.
118
- Do NOT modify any files. Read only.`,
119
- timeout: 60
107
+ type: 'command',
108
+ command: 'node framework/hooks/claude-code/stop/validate-completion.js'
120
109
  }]
121
110
  },
122
111
 
@@ -209,9 +198,10 @@ export async function installClaudeHooks(targetPath) {
209
198
  return agentHook;
210
199
  }
211
200
  // Command hooks: transform path to use $CLAUDE_PROJECT_DIR
201
+ // Hooks are copied to .morph/framework/hooks/ during `morph-spec init/update`
212
202
  return {
213
203
  type: h.type,
214
- command: `node "$CLAUDE_PROJECT_DIR/framework/hooks/claude-code/${getHookSubpath(h.command)}"`,
204
+ command: `node "$CLAUDE_PROJECT_DIR/.morph/framework/hooks/claude-code/${getHookSubpath(h.command)}"`,
215
205
  ...(h.timeout !== undefined ? { timeout: h.timeout } : {})
216
206
  };
217
207
  });