@polymorphism-tech/morph-spec 4.9.0 → 4.10.1

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 (164) hide show
  1. package/README.md +2 -2
  2. package/bin/morph-spec.js +30 -0
  3. package/bin/task-manager.js +34 -22
  4. package/claude-plugin.json +1 -1
  5. package/docs/CHEATSHEET.md +1 -1
  6. package/docs/QUICKSTART.md +1 -1
  7. package/framework/CLAUDE.md +35 -98
  8. package/framework/agents/backend/api-designer.md +3 -0
  9. package/framework/agents/backend/dotnet-senior.md +3 -0
  10. package/framework/agents/backend/ef-modeler.md +2 -0
  11. package/framework/agents/backend/hangfire-orchestrator.md +2 -0
  12. package/framework/agents/backend/ms-agent-expert.md +2 -0
  13. package/framework/agents/frontend/blazor-builder.md +2 -0
  14. package/framework/agents/frontend/nextjs-expert.md +2 -0
  15. package/framework/agents/infrastructure/azure-architect.md +2 -0
  16. package/framework/agents/infrastructure/azure-deploy-specialist.md +2 -0
  17. package/framework/agents/infrastructure/bicep-architect.md +2 -0
  18. package/framework/agents/infrastructure/container-specialist.md +2 -0
  19. package/framework/agents/infrastructure/devops-engineer.md +3 -0
  20. package/framework/agents/infrastructure/infra-architect.md +3 -0
  21. package/framework/agents/integrations/asaas-financial.md +2 -0
  22. package/framework/agents/integrations/azure-identity.md +2 -0
  23. package/framework/agents/integrations/clerk-auth.md +3 -0
  24. package/framework/agents/integrations/hangfire-integration.md +2 -0
  25. package/framework/agents/integrations/resend-email.md +2 -0
  26. package/framework/agents.json +37 -7
  27. package/framework/commands/commit.md +166 -0
  28. package/framework/commands/morph-apply.md +156 -155
  29. package/framework/commands/morph-archive.md +33 -27
  30. package/framework/commands/morph-infra.md +83 -77
  31. package/framework/commands/morph-preflight.md +97 -55
  32. package/framework/commands/morph-proposal.md +131 -58
  33. package/framework/commands/morph-status.md +36 -30
  34. package/framework/commands/morph-troubleshoot.md +68 -59
  35. package/framework/hooks/claude-code/notification/approval-reminder.js +3 -2
  36. package/framework/hooks/claude-code/post-tool-use/dispatch.js +154 -31
  37. package/framework/hooks/claude-code/post-tool-use/skill-reminder.js +7 -84
  38. package/framework/hooks/claude-code/post-tool-use/validator-feedback.js +8 -17
  39. package/framework/hooks/claude-code/pre-compact/save-morph-context.js +16 -3
  40. package/framework/hooks/claude-code/pre-tool-use/enforce-phase-writes.js +4 -3
  41. package/framework/hooks/claude-code/pre-tool-use/protect-spec-files.js +3 -2
  42. package/framework/hooks/claude-code/pre-tool-use/task-tracking-guard.js +60 -0
  43. package/framework/hooks/claude-code/session-start/inject-morph-context.js +55 -2
  44. package/framework/hooks/claude-code/session-start/post-compact-restore.js +41 -0
  45. package/framework/hooks/claude-code/stop/validate-completion.js +2 -15
  46. package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +23 -5
  47. package/framework/hooks/shared/compact-restore.js +100 -0
  48. package/framework/hooks/shared/dispatch-helpers.js +116 -0
  49. package/framework/hooks/shared/phase-utils.js +9 -5
  50. package/framework/hooks/shared/state-reader.js +27 -3
  51. package/framework/phases.json +30 -7
  52. package/framework/rules/csharp-standards.md +3 -0
  53. package/framework/rules/frontend-standards.md +2 -0
  54. package/framework/rules/infrastructure-standards.md +3 -0
  55. package/framework/rules/morph-workflow.md +143 -86
  56. package/framework/rules/nextjs-standards.md +2 -0
  57. package/framework/rules/testing-standards.md +3 -0
  58. package/framework/skills/level-0-meta/mcp-registry.json +86 -51
  59. package/framework/skills/level-0-meta/morph-brainstorming/SKILL.md +139 -0
  60. package/framework/skills/level-0-meta/morph-checklist/SKILL.md +42 -19
  61. package/framework/skills/level-0-meta/{code-review → morph-code-review}/SKILL.md +8 -5
  62. package/framework/skills/level-0-meta/{code-review-nextjs → morph-code-review-nextjs}/SKILL.md +8 -6
  63. package/framework/skills/level-0-meta/morph-frontend-review/SKILL.md +362 -0
  64. package/framework/skills/level-0-meta/morph-init/SKILL.md +114 -20
  65. package/framework/skills/level-0-meta/morph-post-implementation/SKILL.md +362 -0
  66. package/framework/skills/level-0-meta/morph-replicate/SKILL.md +95 -87
  67. package/framework/skills/level-0-meta/{simulation-checklist → morph-simulation-checklist}/SKILL.md +24 -0
  68. package/framework/skills/level-0-meta/{tool-usage-guide → morph-tool-usage-guide}/SKILL.md +43 -43
  69. package/framework/skills/level-0-meta/{tool-usage-guide → morph-tool-usage-guide}/references/tools-per-phase.md +1 -2
  70. package/framework/skills/level-0-meta/{verification-before-completion → morph-verification-before-completion}/SKILL.md +23 -12
  71. package/framework/skills/level-0-meta/{verification-before-completion → morph-verification-before-completion}/scripts/check-phase-outputs.mjs +2 -2
  72. package/framework/skills/level-1-workflows/morph-phase-clarify/SKILL.md +247 -0
  73. package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +270 -0
  74. package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +499 -0
  75. package/framework/skills/level-1-workflows/morph-phase-implement/.morph/logs/activity.json +38 -0
  76. package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +472 -0
  77. package/framework/skills/level-1-workflows/morph-phase-implement/prompts/code-quality-reviewer-prompt.md +50 -0
  78. package/framework/skills/level-1-workflows/morph-phase-implement/prompts/implementer-prompt.md +45 -0
  79. package/framework/skills/level-1-workflows/morph-phase-implement/prompts/spec-reviewer-prompt.md +47 -0
  80. package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +246 -0
  81. package/framework/skills/level-1-workflows/morph-phase-setup/SKILL.md +238 -0
  82. package/framework/skills/level-1-workflows/morph-phase-tasks/.morph/logs/activity.json +14 -0
  83. package/framework/skills/level-1-workflows/morph-phase-tasks/SKILL.md +312 -0
  84. package/framework/skills/level-1-workflows/{phase-tasks → morph-phase-tasks}/scripts/validate-tasks.mjs +3 -3
  85. package/framework/skills/level-1-workflows/morph-phase-uiux/SKILL.md +324 -0
  86. package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +146 -0
  87. package/framework/standards/integration/mcp/mcp-tools.md +25 -7
  88. package/framework/templates/docs/onboarding.md +2 -2
  89. package/package.json +3 -4
  90. package/src/commands/agents/dispatch-agents.js +50 -3
  91. package/src/commands/mcp/mcp-setup.js +39 -2
  92. package/src/commands/phase/phase-reset.js +74 -0
  93. package/src/commands/project/doctor.js +26 -7
  94. package/src/commands/project/update.js +4 -4
  95. package/src/commands/scope/escalate.js +215 -0
  96. package/src/commands/state/advance-phase.js +27 -53
  97. package/src/commands/state/state.js +1 -1
  98. package/src/commands/task/expand.js +100 -0
  99. package/src/core/paths/output-schema.js +4 -3
  100. package/src/core/state/phase-state-machine.js +7 -4
  101. package/src/core/state/state-manager.js +4 -3
  102. package/src/lib/detectors/claude-config-detector.js +93 -347
  103. package/src/lib/detectors/design-system-detector.js +189 -189
  104. package/src/lib/detectors/index.js +155 -57
  105. package/src/lib/generators/context-generator.js +2 -2
  106. package/src/lib/installers/mcp-installer.js +37 -5
  107. package/src/lib/phase-chain/phase-validator.js +22 -16
  108. package/src/lib/scope/impact-analyzer.js +106 -0
  109. package/src/lib/stack-filter.js +58 -0
  110. package/src/lib/tasks/task-parser.js +1 -1
  111. package/src/lib/validators/shared/emit-validator-dispatch.js +64 -0
  112. package/src/scripts/setup-infra.js +68 -18
  113. package/src/utils/agents-installer.js +51 -17
  114. package/src/utils/claude-md-injector.js +90 -0
  115. package/src/utils/file-copier.js +0 -1
  116. package/src/utils/hooks-installer.js +16 -5
  117. package/src/utils/skills-installer.js +67 -7
  118. package/CLAUDE.md +0 -98
  119. package/framework/memory/patterns-learned.md +0 -766
  120. package/framework/skills/level-0-meta/brainstorming/SKILL.md +0 -137
  121. package/framework/skills/level-0-meta/frontend-review/SKILL.md +0 -359
  122. package/framework/skills/level-0-meta/post-implementation/SKILL.md +0 -362
  123. package/framework/skills/level-0-meta/terminal-title/SKILL.md +0 -61
  124. package/framework/skills/level-0-meta/terminal-title/scripts/set_title.sh +0 -65
  125. package/framework/skills/level-1-workflows/phase-clarify/SKILL.md +0 -216
  126. package/framework/skills/level-1-workflows/phase-codebase-analysis/SKILL.md +0 -252
  127. package/framework/skills/level-1-workflows/phase-design/SKILL.md +0 -383
  128. package/framework/skills/level-1-workflows/phase-implement/SKILL.md +0 -492
  129. package/framework/skills/level-1-workflows/phase-setup/SKILL.md +0 -195
  130. package/framework/skills/level-1-workflows/phase-tasks/SKILL.md +0 -271
  131. package/framework/skills/level-1-workflows/phase-uiux/SKILL.md +0 -286
  132. package/src/commands/project/index.js +0 -8
  133. package/src/core/index.js +0 -10
  134. package/src/core/state/index.js +0 -8
  135. package/src/core/templates/index.js +0 -9
  136. package/src/core/templates/template-data-sources.js +0 -325
  137. package/src/core/workflows/index.js +0 -7
  138. package/src/lib/detectors/config-detector.js +0 -223
  139. package/src/lib/detectors/standards-generator.js +0 -335
  140. package/src/lib/detectors/structure-detector.js +0 -275
  141. package/src/lib/monitor/agent-resolver.js +0 -144
  142. package/src/lib/monitor/renderer.js +0 -230
  143. package/src/lib/orchestration/index.js +0 -7
  144. package/src/lib/orchestration/team-orchestrator.js +0 -404
  145. package/src/sanitizer/context-sanitizer.js +0 -221
  146. package/src/sanitizer/patterns.js +0 -163
  147. package/src/writer/file-writer.js +0 -86
  148. /package/framework/skills/level-0-meta/{brainstorming → morph-brainstorming}/references/proposal-example.md +0 -0
  149. /package/framework/skills/level-0-meta/{code-review → morph-code-review}/references/review-example.md +0 -0
  150. /package/framework/skills/level-0-meta/{code-review → morph-code-review}/references/review-guidelines.md +0 -0
  151. /package/framework/skills/level-0-meta/{code-review → morph-code-review}/scripts/scan-csharp.mjs +0 -0
  152. /package/framework/skills/level-0-meta/{code-review-nextjs → morph-code-review-nextjs}/references/review-example-nextjs.md +0 -0
  153. /package/framework/skills/level-0-meta/{code-review-nextjs → morph-code-review-nextjs}/scripts/scan-nextjs.mjs +0 -0
  154. /package/framework/skills/level-0-meta/{frontend-review → morph-frontend-review}/scripts/scan-accessibility.mjs +0 -0
  155. /package/framework/skills/level-0-meta/{post-implementation → morph-post-implementation}/scripts/detect-dev-server.mjs +0 -0
  156. /package/framework/skills/level-0-meta/{post-implementation → morph-post-implementation}/scripts/detect-stack.mjs +0 -0
  157. /package/framework/skills/level-1-workflows/{phase-clarify → morph-phase-clarify}/references/clarifications-example.md +0 -0
  158. /package/framework/skills/level-1-workflows/{phase-design → morph-phase-design}/references/architecture-analysis-guide.md +0 -0
  159. /package/framework/skills/level-1-workflows/{phase-design → morph-phase-design}/references/spec-authoring-guide.md +0 -0
  160. /package/framework/skills/level-1-workflows/{phase-design → morph-phase-design}/references/spec-example.md +0 -0
  161. /package/framework/skills/level-1-workflows/{phase-implement → morph-phase-implement}/references/recap-example.md +0 -0
  162. /package/framework/skills/level-1-workflows/{phase-implement → morph-phase-implement}/references/vsa-implementation-guide.md +0 -0
  163. /package/framework/skills/level-1-workflows/{phase-tasks → morph-phase-tasks}/references/task-planning-patterns.md +0 -0
  164. /package/framework/skills/level-1-workflows/{phase-tasks → morph-phase-tasks}/references/tasks-example.md +0 -0
@@ -0,0 +1,146 @@
1
+ ---
2
+ name: morph:scope-escalation
3
+ description: Guided workflow for mid-implementation scope escalation — analyzes complexity discovery, recommends action, and executes phase regression or task expansion
4
+ user-invocable: true
5
+ argument-hint: "[feature-name]"
6
+ allowed-tools: Read, Write, Edit, Bash, Glob, Grep, AskUserQuestion
7
+ ---
8
+
9
+ # Scope Escalation Workflow
10
+
11
+ Use this skill when a task during implementation reveals significantly more complexity than estimated.
12
+
13
+ ## Prerequisites
14
+
15
+ - Feature must be in `implement` phase
16
+ - You must have identified a specific task that triggered the discovery
17
+
18
+ ## Workflow
19
+
20
+ ### Step 1: COLLECT Evidence
21
+
22
+ Use `AskUserQuestion` to gather the details:
23
+
24
+ ```json
25
+ {
26
+ "questions": [
27
+ {
28
+ "header": "Task ID",
29
+ "question": "Which task triggered the complexity discovery?",
30
+ "multiSelect": false,
31
+ "options": [
32
+ { "label": "T001", "description": "First task" },
33
+ { "label": "T002", "description": "Second task" },
34
+ { "label": "Other", "description": "Type the task ID" }
35
+ ]
36
+ },
37
+ {
38
+ "header": "Discovery",
39
+ "question": "What complexity did you discover?",
40
+ "multiSelect": true,
41
+ "options": [
42
+ { "label": "Hidden dependencies", "description": "More systems involved than spec assumed" },
43
+ { "label": "Wrong assumptions", "description": "Spec assumed simpler architecture" },
44
+ { "label": "Missing abstractions", "description": "Need new patterns/interfaces not in contracts" },
45
+ { "label": "Other", "description": "Describe the discovery" }
46
+ ]
47
+ }
48
+ ]
49
+ }
50
+ ```
51
+
52
+ > Populate the Task ID options dynamically from the feature's `tasks.md`. After receiving answers, **read the relevant code files** to verify the evidence before classifying.
53
+
54
+ ### Step 2: ANALYZE Impact
55
+
56
+ Run dry-run analysis:
57
+
58
+ ```bash
59
+ npx morph-spec scope escalate <feature> --task <id> --reason "<reason>" --dry-run
60
+ ```
61
+
62
+ Read the recommendation output. Additionally:
63
+
64
+ - Read `tasks.md` to understand which tasks are affected
65
+ - Read `spec.md` to check if the spec assumed simpler architecture
66
+ - Check completed tasks for potential impact
67
+
68
+ ### Step 3: CLASSIFY and PROPOSE
69
+
70
+ Present the recommendation to the user:
71
+
72
+ | Impact | Action | When |
73
+ |--------|--------|------|
74
+ | **Low** (1-3 tasks) | Task Expansion | The task is bigger than expected, but scope is contained |
75
+ | **Medium** (4+ tasks, spec ok) | Regress to tasks | Multiple tasks need rewriting, but the spec is correct |
76
+ | **High** (spec wrong) | Regress to design | The spec made incorrect assumptions about the codebase |
77
+
78
+ Explain WHY you recommend this classification based on the evidence.
79
+
80
+ ### Step 4: APPROVE
81
+
82
+ Pause and wait for user confirmation using `AskUserQuestion`:
83
+
84
+ ```json
85
+ {
86
+ "questions": [
87
+ {
88
+ "header": "Severity",
89
+ "question": "Impact classified as {LOW|MEDIUM|HIGH}. Do you agree?",
90
+ "multiSelect": false,
91
+ "options": [
92
+ { "label": "Agree", "description": "Classification is correct" },
93
+ { "label": "Override", "description": "I think the impact is different" }
94
+ ]
95
+ },
96
+ {
97
+ "header": "Action",
98
+ "question": "Recommended action: {action}. Proceed?",
99
+ "multiSelect": false,
100
+ "options": [
101
+ { "label": "Proceed", "description": "{action description}" },
102
+ { "label": "Different target", "description": "I want to regress to a different phase" },
103
+ { "label": "Cancel", "description": "Do not escalate — continue as-is" }
104
+ ]
105
+ }
106
+ ]
107
+ }
108
+ ```
109
+
110
+ **DO NOT proceed without explicit user approval.** If user chooses "Cancel", stop the workflow entirely.
111
+
112
+ ### Step 5: EXECUTE
113
+
114
+ Based on approved action:
115
+
116
+ **For expansion (low impact):**
117
+ ```bash
118
+ npx morph-spec task expand <feature> <task-id> --into "T017a: <title>" "T017b: <title>" ...
119
+ ```
120
+
121
+ **For regression (medium/high impact):**
122
+ ```bash
123
+ npx morph-spec scope escalate <feature> --task <id> --reason "<reason>"
124
+ ```
125
+
126
+ Or with target override:
127
+ ```bash
128
+ npx morph-spec scope escalate <feature> --task <id> --reason "<reason>" --target design
129
+ ```
130
+
131
+ ### Step 6: GUIDE Next Steps
132
+
133
+ After escalation:
134
+
135
+ - **If regressed to tasks:** "Re-analyze the affected tasks. Rewrite tasks.md with accurate scope. Run `/morph-proposal <feature>` to continue from the tasks phase."
136
+ - **If regressed to design:** "Re-analyze the spec. Update spec.md with the discovered architecture. Then regenerate tasks."
137
+ - **If expanded:** "Continue implementing. Use `morph-spec task start <feature> <sub-task-id>` to start the first sub-task."
138
+
139
+ Always remind: "Completed tasks flagged with `needsReview` should be checked for compatibility with the new scope."
140
+
141
+ ## Anti-Patterns
142
+
143
+ - **DO NOT** skip the approval step
144
+ - **DO NOT** escalate without evidence — read the actual code first
145
+ - **DO NOT** regress to design when only tasks need rewriting
146
+ - **DO NOT** expand when 4+ tasks are affected — regress instead
@@ -49,15 +49,10 @@ const repo = await mcp__github__get_repo();
49
49
 
50
50
  | MCP | Use Case | Example |
51
51
  |-----|----------|---------|
52
- | **Figma** | Extract design tokens, components | `mcp__figma__get_file({ fileKey })` |
53
52
  | **Playwright** | Navigate, screenshot, inspect live pages | `mcp__playwright__browser_navigate({ url })` |
54
53
  | **Context7** | Component library documentation | `mcp__context7__query_docs({ libraryId, query })` |
55
54
 
56
55
  ```javascript
57
- // Get design tokens from Figma
58
- const file = await mcp__figma__get_file({ fileKey: "abc123" });
59
- // → colors, typography, spacing from design file
60
-
61
56
  // Screenshot existing app for design reference
62
57
  await mcp__playwright__browser_navigate({ url: "https://app.example.com/dashboard" });
63
58
  const screenshot = await mcp__playwright__browser_take_screenshot();
@@ -180,6 +175,7 @@ for (const task of tasks) {
180
175
  | **GitHub** | Create PR, push branches | `mcp__github__create_pull_request()` |
181
176
  | **Context7** | Look up API usage during coding | `mcp__context7__query_docs()` |
182
177
  | **Playwright** | Smoke test deployed features, verify UI | `mcp__playwright__browser_navigate()` |
178
+ | **Vercel** | Deploy, check logs, manage env vars | `mcp__vercel__list_projects()` |
183
179
  | **Azure** | Provision resources, check deployment status | Provider-specific |
184
180
  | **Docker** | Build images, manage containers | Provider-specific |
185
181
 
@@ -214,7 +210,25 @@ const logs = await mcp__playwright__browser_console_messages();
214
210
  // Screenshot for recap.md documentation
215
211
  const screenshot = await mcp__playwright__browser_take_screenshot();
216
212
 
217
- // Fallback: Bash for migrations, gh CLI for PRs
213
+ // === VERCEL (Deployment & Environment) ===
214
+
215
+ // List projects
216
+ const projects = await mcp__vercel__list_projects();
217
+
218
+ // Check deployment status and logs
219
+ const deployments = await mcp__vercel__get_deployments({ projectId: 'my-project' });
220
+ const logs = await mcp__vercel__get_deployment_logs({ deploymentId: deployments[0].uid });
221
+
222
+ // Manage environment variables
223
+ await mcp__vercel__manage_env_vars({
224
+ projectId: 'my-project',
225
+ action: 'set',
226
+ key: 'DATABASE_URL',
227
+ value: process.env.DATABASE_URL,
228
+ target: ['production', 'preview']
229
+ });
230
+
231
+ // Fallback: Bash for migrations, gh CLI for PRs, vercel CLI for deployments
218
232
  ```
219
233
 
220
234
  ---
@@ -225,7 +239,6 @@ const screenshot = await mcp__playwright__browser_take_screenshot();
225
239
  |------|----------|--------------------|
226
240
  | Database schema | Supabase/DB MCP | Grep queries + Read types |
227
241
  | Repo metadata | GitHub MCP | Bash `gh` CLI |
228
- | Design tokens | Figma MCP | Read CSS/SCSS variables |
229
242
  | Library docs | Context7 | WebSearch + WebFetch |
230
243
  | Live page preview | Playwright MCP | WebFetch URL |
231
244
  | Page interaction (click, type, navigate) | Playwright MCP | Manual testing |
@@ -233,6 +246,7 @@ const screenshot = await mcp__playwright__browser_take_screenshot();
233
246
  | Console error checking | Playwright MCP (`browser_console_messages`) | Browser DevTools |
234
247
  | Container ops | Docker MCP | Bash `docker` CLI |
235
248
  | Cloud resources | Azure MCP | Bash `az` CLI |
249
+ | Vercel deployments | Vercel MCP | Bash `vercel` CLI |
236
250
 
237
251
  **Rule:** MCP tools provide structured data (JSON responses). Native tools require manual parsing. **Always prefer MCP when available** — fall back to native when not.
238
252
 
@@ -332,6 +346,8 @@ await mcp__playwright__browser_file_upload({ ref: "s1e20", paths: ["/path/to/fil
332
346
 
333
347
  ### Supabase: Full Schema Discovery
334
348
 
349
+ > **v4 config:** Remote OAuth — `{ "type": "http", "url": "https://mcp.supabase.com/mcp" }`. Authenticate via `/mcp` in Claude Code.
350
+
335
351
  ```javascript
336
352
  // Complete workflow for Phase 2 schema analysis
337
353
  const tables = await mcp__supabase__list_tables();
@@ -362,6 +378,8 @@ const docs = await mcp__context7__query_docs({
362
378
 
363
379
  ### GitHub: Code Search Across Repo
364
380
 
381
+ > **v4 config:** Docker — `{ "command": "docker", "args": ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"] }`. Requires Docker Desktop.
382
+
365
383
  ```javascript
366
384
  // Find patterns in large codebase during Phase 2
367
385
  const results = await mcp__github__search_code({
@@ -97,8 +97,8 @@ morph-spec doctor
97
97
  │ ├── 0-proposal/
98
98
  │ ├── 1-design/
99
99
  │ ├── 2-ui/
100
- │ ├── 3-tasks/
101
- │ └── 4-implement/
100
+ │ ├── 4-tasks/
101
+ │ └── 5-implement/
102
102
  └── .claude/
103
103
  ├── commands/ # Slash commands
104
104
  ├── skills/ # Workflow skills
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polymorphism-tech/morph-spec",
3
- "version": "4.9.0",
3
+ "version": "4.10.1",
4
4
  "description": "MORPH-SPEC: AI-First development framework with validation pipeline and multi-stack support",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -47,7 +47,6 @@
47
47
  "docs": "jsdoc -c jsdoc.json",
48
48
  "docs:watch": "jsdoc -c jsdoc.json --watch",
49
49
  "docs:serve": "npx http-server docs/api -p 8080 -o",
50
- "version:bump": "node scripts/bump-version.js",
51
50
  "release": "node scripts/release.js",
52
51
  "postinstall": "node src/scripts/global-install.js"
53
52
  },
@@ -55,7 +54,7 @@
55
54
  "chalk": "^5.3.0",
56
55
  "commander": "^12.0.0",
57
56
  "fs-extra": "^11.2.0",
58
- "glob": "^10.3.0",
57
+ "glob": "^13.0.6",
59
58
  "handlebars": "^4.7.8",
60
59
  "inquirer": "^9.2.0",
61
60
  "minimatch": "^9.0.5",
@@ -76,7 +75,7 @@
76
75
  "access": "public"
77
76
  },
78
77
  "devDependencies": {
79
- "c8": "^10.1.3",
78
+ "c8": "^11.0.0",
80
79
  "docdash": "^2.0.2",
81
80
  "jsdoc": "^4.0.5"
82
81
  }
@@ -124,6 +124,51 @@ export function buildSkillsBlock(phase, phasesData) {
124
124
  }
125
125
  }
126
126
 
127
+ // ─────────────────────────────────────────────────────────────────────────────
128
+ // MCP Awareness Injection
129
+ // ─────────────────────────────────────────────────────────────────────────────
130
+
131
+ /**
132
+ * Build an MCP availability block for the given phase.
133
+ * Reads recommendedMCPs from phases.json and MCP usage info from mcp-registry.json.
134
+ * Returns null if no MCPs recommended for this phase.
135
+ *
136
+ * @param {string} phase - Phase id (e.g. 'implement')
137
+ * @param {Object|null} phasesData - Parsed phases.json content
138
+ * @param {Object} [opts] - Options
139
+ * @param {string} [opts.registryPath] - Override path to mcp-registry.json
140
+ * @returns {string|null}
141
+ */
142
+ export function buildMcpBlock(phase, phasesData, opts = {}) {
143
+ try {
144
+ const mcps = phasesData?.phases?.[phase]?.recommendedMCPs;
145
+ if (!mcps || mcps.length === 0) return null;
146
+
147
+ // Try to load registry for usage descriptions
148
+ let registry = null;
149
+ const registryPath = opts.registryPath || join(__dirname, '../../../framework/skills/level-0-meta/mcp-registry.json');
150
+ try {
151
+ if (existsSync(registryPath)) {
152
+ registry = JSON.parse(readFileSync(registryPath, 'utf8'));
153
+ }
154
+ } catch { /* non-blocking */ }
155
+
156
+ const lines = mcps.map(name => {
157
+ const usage = registry?.mcps?.[name]?.usage || '';
158
+ return usage ? `- ${name}: ${usage}` : `- ${name}`;
159
+ });
160
+
161
+ return [
162
+ `Available MCPs for ${phase} phase:`,
163
+ ...lines,
164
+ '',
165
+ 'Use MCP tools when available; fall back to native tools (Bash, Read, Grep) when not.',
166
+ ].join('\n');
167
+ } catch {
168
+ return null;
169
+ }
170
+ }
171
+
127
172
  // ─────────────────────────────────────────────────────────────────────────────
128
173
  // Helpers
129
174
  // ─────────────────────────────────────────────────────────────────────────────
@@ -201,7 +246,7 @@ export function parseAndGroupTasks(tasksPath) {
201
246
  const groups = {};
202
247
 
203
248
  // Match task headings: ### T001 — Title or ### T001: Title
204
- const taskHeadingRe = /^###\s+(T\d{3,})\s*[—:\-]\s*(.+)$/gm;
249
+ const taskHeadingRe = /^###\s+(T\d{3,})\s*[—–:\-]\s*(.+)$/gm;
205
250
  // Match category line within a task block: **category**: `domain` or - category: application
206
251
  const categoryRe = /(?:\*\*category\*\*\s*:\s*`?([a-z-]+)`?|category:\s*([a-z-]+))/i;
207
252
 
@@ -344,13 +389,15 @@ export async function buildDispatchConfig(projectPath, featureName, phase, opts
344
389
  rawPrompt = agentData.teammate.spawn_prompt;
345
390
  }
346
391
 
347
- // Append standards digest as Constraints block, then required skills block
392
+ // Append standards digest as Constraints block, then skills block, then MCP block
348
393
  const briefing = buildAgentBriefing(agentId, phase);
349
394
  const skillsBlock = buildSkillsBlock(phase, phasesData);
395
+ const mcpBlock = buildMcpBlock(phase, phasesData);
350
396
  const fullTaskPrompt = [
351
397
  rawPrompt,
352
398
  briefing ? `\n\nConstraints:\n${briefing}` : '',
353
399
  skillsBlock ? `\n\n${skillsBlock}` : '',
400
+ mcpBlock ? `\n\n${mcpBlock}` : '',
354
401
  ].join('');
355
402
 
356
403
  dispatchableAgents.push({
@@ -398,7 +445,7 @@ export async function buildDispatchConfig(projectPath, featureName, phase, opts
398
445
 
399
446
  if (phase === 'implement') {
400
447
  // Group tasks from tasks.md by domain category
401
- const tasksPath = join(projectPath, `.morph/features/${featureName}/3-tasks/tasks.md`);
448
+ const tasksPath = join(projectPath, `.morph/features/${featureName}/4-tasks/tasks.md`);
402
449
  const tasksByGroup = parseAndGroupTasks(tasksPath);
403
450
 
404
451
  for (const [group, taskIds] of Object.entries(tasksByGroup)) {
@@ -19,7 +19,8 @@ import {
19
19
  installMcpWithCredentials,
20
20
  generateSetupInstructions,
21
21
  formatMcpStatusTable,
22
- loadMcpRegistry
22
+ loadMcpRegistry,
23
+ isRemoteMcp
23
24
  } from '../../lib/installers/mcp-installer.js';
24
25
  import { detectClaudeConfig } from '../../lib/detectors/claude-config-detector.js';
25
26
  import { detectProject } from '../../lib/detectors/index.js';
@@ -187,7 +188,43 @@ async function setupSpecificMcp(targetPath, name, stack, existingMcps) {
187
188
  return;
188
189
  }
189
190
 
190
- // Needs credentials
191
+ // Remote HTTP MCP — show setup command and optionally auto-configure
192
+ if (isRemoteMcp(mcpEntry.install.config)) {
193
+ console.log(chalk.cyan(`\n Setting up ${name} MCP (remote)\n`));
194
+ console.log(chalk.gray(` Usage: ${mcpEntry.usage}`));
195
+ console.log('');
196
+
197
+ const instructions = generateSetupInstructions(name, mcpEntry);
198
+ console.log(chalk.white(` Run this command to add the MCP:`));
199
+ console.log(chalk.cyan(` ${instructions.cliCommand}`));
200
+ console.log('');
201
+
202
+ for (const warning of mcpEntry.install.warnings || []) {
203
+ console.log(chalk.yellow(` ⚠ ${warning}`));
204
+ }
205
+
206
+ const { installNow } = await inquirer.prompt([{
207
+ type: 'confirm',
208
+ name: 'installNow',
209
+ message: 'Add to .claude/settings.local.json now?',
210
+ default: true
211
+ }]);
212
+
213
+ if (installNow) {
214
+ const spinner = ora(`Configuring ${name}...`).start();
215
+ const result = await installAutoMcps(targetPath, { [name]: mcpEntry });
216
+ if (result.added.length > 0) {
217
+ spinner.succeed(`${name} MCP configured (authenticate via /mcp in Claude Code)`);
218
+ } else {
219
+ spinner.info(`${name} MCP already configured`);
220
+ }
221
+ }
222
+
223
+ console.log('');
224
+ return;
225
+ }
226
+
227
+ // Needs credentials (stdio MCPs)
191
228
  console.log(chalk.cyan(`\n Setting up ${name} MCP\n`));
192
229
  console.log(chalk.gray(` Usage: ${mcpEntry.usage}`));
193
230
  console.log('');
@@ -0,0 +1,74 @@
1
+ /**
2
+ * MORPH-SPEC Phase Reset Command
3
+ *
4
+ * Recovery tool for corrupted phase state.
5
+ * Sets the phase directly without approval gate checks.
6
+ *
7
+ * Usage:
8
+ * morph-spec phase reset <feature> <phase>
9
+ */
10
+
11
+ import chalk from 'chalk';
12
+ import { loadState, saveState, derivePhase } from '../../core/state/state-manager.js';
13
+ import { join } from 'path';
14
+
15
+ const VALID_PHASES = ['proposal', 'setup', 'uiux', 'design', 'clarify', 'plan', 'tasks', 'implement', 'sync'];
16
+
17
+ /**
18
+ * Core reset logic — exported for testing.
19
+ * @param {string} featureName
20
+ * @param {string} targetPhase
21
+ * @returns {{ success: boolean, error?: string, derivedPhase?: string }}
22
+ */
23
+ export function resetPhase(featureName, targetPhase) {
24
+ if (!VALID_PHASES.includes(targetPhase)) {
25
+ return {
26
+ success: false,
27
+ error: `Unknown phase: "${targetPhase}". Valid phases: ${VALID_PHASES.join(', ')}`
28
+ };
29
+ }
30
+
31
+ const state = loadState();
32
+ if (!state?.features?.[featureName]) {
33
+ return {
34
+ success: false,
35
+ error: `Feature "${featureName}" not found in state.json`
36
+ };
37
+ }
38
+
39
+ // Get filesystem-derived phase for comparison
40
+ const featureFolderPath = join(process.cwd(), '.morph', 'features', featureName);
41
+ const derivedPhase = derivePhase(featureFolderPath);
42
+
43
+ // Set phase directly — no approval gate checks
44
+ state.features[featureName].phase = targetPhase;
45
+ state.features[featureName].updatedAt = new Date().toISOString();
46
+ saveState(state);
47
+
48
+ return { success: true, derivedPhase };
49
+ }
50
+
51
+ /**
52
+ * CLI command handler
53
+ */
54
+ export async function phaseResetCommand(feature, phase) {
55
+ console.log(chalk.cyan('\n╔════════════════════════════════════════════════╗'));
56
+ console.log(chalk.cyan('║ MORPH-SPEC PHASE RESET ║'));
57
+ console.log(chalk.cyan('╚════════════════════════════════════════════════╝\n'));
58
+
59
+ const result = resetPhase(feature, phase);
60
+
61
+ if (!result.success) {
62
+ console.log(chalk.red(`\n✗ ${result.error}`));
63
+ process.exit(1);
64
+ }
65
+
66
+ console.log(chalk.green(`✓ Phase reset to "${phase}" for feature "${feature}"`));
67
+
68
+ if (result.derivedPhase !== phase) {
69
+ console.log(chalk.yellow(`\n⚠ Filesystem-derived phase is "${result.derivedPhase}" (folders on disk differ from state)`));
70
+ console.log(chalk.gray(` This is expected during recovery. The state.json value takes priority.`));
71
+ }
72
+
73
+ console.log('');
74
+ }
@@ -5,6 +5,7 @@ import fs from 'fs-extra';
5
5
  import chalk from 'chalk';
6
6
  import { logger } from '../../utils/logger.js';
7
7
  import { pathExists, readJson } from '../../utils/file-copier.js';
8
+ import { checkClaudeMdImport } from '../../utils/claude-md-injector.js';
8
9
  import {
9
10
  checkCLIOutdated,
10
11
  checkProjectOutdated,
@@ -84,7 +85,11 @@ const REQUIRED_COMMAND_FILES = [
84
85
  'src/commands/validation/validate-feature.js',
85
86
  'src/commands/templates/template-render.js',
86
87
  'src/commands/agents/dispatch-agents.js',
87
- 'src/commands/project/worktree.js'
88
+ 'src/commands/project/worktree.js',
89
+ 'src/commands/phase/phase-reset.js',
90
+ 'src/commands/scope/escalate.js',
91
+ 'src/commands/task/expand.js',
92
+ 'src/lib/scope/impact-analyzer.js'
88
93
  ];
89
94
 
90
95
  // framework standards
@@ -296,10 +301,18 @@ async function doctorMcpCommand(targetPath) {
296
301
  for (const [name, config] of Object.entries(allMcpServers)) {
297
302
  const issues = [];
298
303
  let status = 'ok';
304
+ let isRemote = false;
299
305
 
300
- // ── 1. Binary check ────────────────────────────────────────────────────
306
+ // ── 0. Remote MCP detection ────────────────────────────────────────────
307
+ // Remote MCPs use HTTP transport (type: "http" or url property) — no binary to check
308
+ if (config.type === 'http' || (config.url && !config.command)) {
309
+ isRemote = true;
310
+ // Remote MCPs are always "ok" from a config perspective — auth happens at runtime
311
+ }
312
+
313
+ // ── 1. Binary check (stdio MCPs only) ──────────────────────────────────
301
314
  const cmd = config.command || '';
302
- if (cmd && !KNOWN_RUNTIMES.has(cmd)) {
315
+ if (!isRemote && cmd && !KNOWN_RUNTIMES.has(cmd)) {
303
316
  try {
304
317
  execSync(isWindows ? `where "${cmd}"` : `which "${cmd}"`, { stdio: 'ignore' });
305
318
  } catch {
@@ -329,12 +342,14 @@ async function doctorMcpCommand(targetPath) {
329
342
  }
330
343
  }
331
344
 
332
- checks.push({ name, status, issues, cmd });
345
+ checks.push({ name, status, issues, cmd, isRemote });
333
346
  }
334
347
 
335
348
  // ── Display ────────────────────────────────────────────────────────────────
336
349
  for (const c of checks) {
337
- const typeLabel = c.cmd ? chalk.gray(` [${c.cmd}]`) : '';
350
+ const typeLabel = c.isRemote
351
+ ? chalk.gray(` [remote: ${allMcpServers[c.name]?.url || 'http'}]`)
352
+ : c.cmd ? chalk.gray(` [${c.cmd}]`) : '';
338
353
 
339
354
  if (c.status === 'ok') {
340
355
  console.log(chalk.green(` ✓ ${c.name}`) + typeLabel);
@@ -490,10 +505,14 @@ export async function doctorCommand(options = {}) {
490
505
  hasWarnings = true;
491
506
  }
492
507
 
493
- // Check CLAUDE.md
508
+ // Check CLAUDE.md has morph-spec @import
494
509
  const claudeMd = join(targetPath, 'CLAUDE.md');
495
- if (await pathExists(claudeMd)) {
510
+ const claudeMdStatus = await checkClaudeMdImport(claudeMd);
511
+ if (claudeMdStatus === 'ok') {
496
512
  checks.push({ name: 'CLAUDE.md', status: 'ok' });
513
+ } else if (claudeMdStatus === 'missing-import') {
514
+ checks.push({ name: 'CLAUDE.md', status: 'warn', msg: 'missing @.claude/CLAUDE.md import — run morph-spec update' });
515
+ hasWarnings = true;
497
516
  } else {
498
517
  checks.push({ name: 'CLAUDE.md', status: 'missing' });
499
518
  hasErrors = true;
@@ -28,6 +28,7 @@ import {
28
28
  import { installClaudeHooks, installGlobalStatusline, installVSCodeTerminalSettings, installShellIntegration } from '../../utils/claude-settings-manager.js';
29
29
  import { installSkills } from '../../utils/skills-installer.js';
30
30
  import { installAgents, installDomainAgents } from '../../utils/agents-installer.js';
31
+ import { injectMorphImport } from '../../utils/claude-md-injector.js';
31
32
 
32
33
  /**
33
34
  * Backup user's config.json before cleaning
@@ -321,11 +322,10 @@ export async function updateCommand(options) {
321
322
  logger.dim(' ⚠ Could not configure VS Code terminal settings (non-critical)');
322
323
  }
323
324
 
324
- // Update CLAUDE.md
325
- updateSpinner.text = 'Updating CLAUDE.md...';
326
- const claudeMdSrc = join(frameworkDir, 'CLAUDE.md');
325
+ // Ensure root CLAUDE.md has morph-spec @import (preserves user content)
326
+ updateSpinner.text = 'Checking CLAUDE.md import...';
327
327
  const claudeMdDest = join(targetPath, 'CLAUDE.md');
328
- await copyFile(claudeMdSrc, claudeMdDest);
328
+ await injectMorphImport(claudeMdDest);
329
329
 
330
330
  // Restore user config after framework reinstallation
331
331
  updateSpinner.text = 'Restoring user configuration...';