@polymorphism-tech/morph-spec 4.9.0 → 4.10.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 (124) 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 +99 -98
  8. package/framework/agents.json +37 -7
  9. package/framework/commands/commit.md +166 -0
  10. package/framework/commands/morph-apply.md +13 -2
  11. package/framework/commands/morph-archive.md +8 -2
  12. package/framework/commands/morph-infra.md +6 -0
  13. package/framework/commands/morph-preflight.md +6 -0
  14. package/framework/commands/morph-proposal.md +56 -7
  15. package/framework/commands/morph-status.md +6 -0
  16. package/framework/commands/morph-troubleshoot.md +6 -0
  17. package/framework/hooks/claude-code/notification/approval-reminder.js +3 -2
  18. package/framework/hooks/claude-code/post-tool-use/dispatch.js +154 -31
  19. package/framework/hooks/claude-code/post-tool-use/skill-reminder.js +7 -84
  20. package/framework/hooks/claude-code/post-tool-use/validator-feedback.js +8 -17
  21. package/framework/hooks/claude-code/pre-compact/save-morph-context.js +16 -3
  22. package/framework/hooks/claude-code/pre-tool-use/enforce-phase-writes.js +4 -3
  23. package/framework/hooks/claude-code/pre-tool-use/protect-spec-files.js +3 -2
  24. package/framework/hooks/claude-code/pre-tool-use/task-tracking-guard.js +60 -0
  25. package/framework/hooks/claude-code/session-start/inject-morph-context.js +55 -2
  26. package/framework/hooks/claude-code/session-start/post-compact-restore.js +41 -0
  27. package/framework/hooks/claude-code/stop/validate-completion.js +2 -15
  28. package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +23 -5
  29. package/framework/hooks/shared/compact-restore.js +100 -0
  30. package/framework/hooks/shared/dispatch-helpers.js +116 -0
  31. package/framework/hooks/shared/phase-utils.js +9 -5
  32. package/framework/hooks/shared/state-reader.js +27 -3
  33. package/framework/phases.json +30 -7
  34. package/framework/rules/morph-workflow.md +88 -86
  35. package/framework/skills/level-0-meta/mcp-registry.json +86 -51
  36. package/framework/skills/level-0-meta/{brainstorming → morph-brainstorming}/SKILL.md +13 -16
  37. package/framework/skills/level-0-meta/{code-review → morph-code-review}/SKILL.md +1 -1
  38. package/framework/skills/level-0-meta/{code-review-nextjs → morph-code-review-nextjs}/SKILL.md +2 -2
  39. package/framework/skills/level-0-meta/{frontend-review → morph-frontend-review}/SKILL.md +5 -5
  40. package/framework/skills/level-0-meta/morph-init/SKILL.md +72 -7
  41. package/framework/skills/level-0-meta/{post-implementation → morph-post-implementation}/SKILL.md +9 -9
  42. package/framework/skills/level-0-meta/morph-replicate/SKILL.md +1 -1
  43. package/framework/skills/level-0-meta/{terminal-title → morph-terminal-title}/SKILL.md +1 -1
  44. package/framework/skills/level-0-meta/{tool-usage-guide → morph-tool-usage-guide}/SKILL.md +2 -3
  45. package/framework/skills/level-0-meta/{tool-usage-guide → morph-tool-usage-guide}/references/tools-per-phase.md +1 -2
  46. package/framework/skills/level-0-meta/{verification-before-completion → morph-verification-before-completion}/SKILL.md +1 -1
  47. package/framework/skills/level-0-meta/{verification-before-completion → morph-verification-before-completion}/scripts/check-phase-outputs.mjs +2 -2
  48. package/framework/skills/level-1-workflows/morph-phase-clarify/SKILL.md +238 -0
  49. package/framework/skills/level-1-workflows/{phase-codebase-analysis → morph-phase-codebase-analysis}/SKILL.md +251 -251
  50. package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +507 -0
  51. package/framework/skills/level-1-workflows/{phase-implement → morph-phase-implement}/SKILL.md +590 -491
  52. package/framework/skills/level-1-workflows/morph-phase-implement/prompts/code-quality-reviewer-prompt.md +50 -0
  53. package/framework/skills/level-1-workflows/morph-phase-implement/prompts/implementer-prompt.md +45 -0
  54. package/framework/skills/level-1-workflows/morph-phase-implement/prompts/spec-reviewer-prompt.md +47 -0
  55. package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +254 -0
  56. package/framework/skills/level-1-workflows/{phase-setup → morph-phase-setup}/SKILL.md +237 -194
  57. package/framework/skills/level-1-workflows/{phase-tasks → morph-phase-tasks}/SKILL.md +307 -270
  58. package/framework/skills/level-1-workflows/{phase-tasks → morph-phase-tasks}/scripts/validate-tasks.mjs +3 -3
  59. package/framework/skills/level-1-workflows/{phase-uiux → morph-phase-uiux}/SKILL.md +320 -285
  60. package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +97 -0
  61. package/framework/standards/integration/mcp/mcp-tools.md +25 -7
  62. package/framework/templates/docs/onboarding.md +2 -2
  63. package/package.json +1 -2
  64. package/src/commands/agents/dispatch-agents.js +50 -3
  65. package/src/commands/mcp/mcp-setup.js +39 -2
  66. package/src/commands/phase/phase-reset.js +74 -0
  67. package/src/commands/project/doctor.js +19 -5
  68. package/src/commands/scope/escalate.js +215 -0
  69. package/src/commands/state/advance-phase.js +27 -53
  70. package/src/commands/state/state.js +1 -1
  71. package/src/commands/task/expand.js +100 -0
  72. package/src/core/paths/output-schema.js +4 -3
  73. package/src/core/state/phase-state-machine.js +7 -4
  74. package/src/core/state/state-manager.js +4 -3
  75. package/src/lib/detectors/claude-config-detector.js +93 -347
  76. package/src/lib/detectors/design-system-detector.js +189 -189
  77. package/src/lib/detectors/index.js +155 -57
  78. package/src/lib/generators/context-generator.js +2 -2
  79. package/src/lib/installers/mcp-installer.js +37 -5
  80. package/src/lib/phase-chain/phase-validator.js +22 -16
  81. package/src/lib/scope/impact-analyzer.js +106 -0
  82. package/src/lib/tasks/task-parser.js +1 -1
  83. package/src/lib/validators/shared/emit-validator-dispatch.js +64 -0
  84. package/src/scripts/setup-infra.js +15 -0
  85. package/src/utils/agents-installer.js +32 -12
  86. package/src/utils/file-copier.js +0 -1
  87. package/src/utils/hooks-installer.js +15 -1
  88. package/framework/skills/level-1-workflows/phase-clarify/SKILL.md +0 -216
  89. package/framework/skills/level-1-workflows/phase-design/SKILL.md +0 -383
  90. package/src/commands/project/index.js +0 -8
  91. package/src/core/index.js +0 -10
  92. package/src/core/state/index.js +0 -8
  93. package/src/core/templates/index.js +0 -9
  94. package/src/core/templates/template-data-sources.js +0 -325
  95. package/src/core/workflows/index.js +0 -7
  96. package/src/lib/detectors/config-detector.js +0 -223
  97. package/src/lib/detectors/standards-generator.js +0 -335
  98. package/src/lib/detectors/structure-detector.js +0 -275
  99. package/src/lib/monitor/agent-resolver.js +0 -144
  100. package/src/lib/monitor/renderer.js +0 -230
  101. package/src/lib/orchestration/index.js +0 -7
  102. package/src/lib/orchestration/team-orchestrator.js +0 -404
  103. package/src/sanitizer/context-sanitizer.js +0 -221
  104. package/src/sanitizer/patterns.js +0 -163
  105. package/src/writer/file-writer.js +0 -86
  106. /package/framework/skills/level-0-meta/{brainstorming → morph-brainstorming}/references/proposal-example.md +0 -0
  107. /package/framework/skills/level-0-meta/{code-review → morph-code-review}/references/review-example.md +0 -0
  108. /package/framework/skills/level-0-meta/{code-review → morph-code-review}/references/review-guidelines.md +0 -0
  109. /package/framework/skills/level-0-meta/{code-review → morph-code-review}/scripts/scan-csharp.mjs +0 -0
  110. /package/framework/skills/level-0-meta/{code-review-nextjs → morph-code-review-nextjs}/references/review-example-nextjs.md +0 -0
  111. /package/framework/skills/level-0-meta/{code-review-nextjs → morph-code-review-nextjs}/scripts/scan-nextjs.mjs +0 -0
  112. /package/framework/skills/level-0-meta/{frontend-review → morph-frontend-review}/scripts/scan-accessibility.mjs +0 -0
  113. /package/framework/skills/level-0-meta/{post-implementation → morph-post-implementation}/scripts/detect-dev-server.mjs +0 -0
  114. /package/framework/skills/level-0-meta/{post-implementation → morph-post-implementation}/scripts/detect-stack.mjs +0 -0
  115. /package/framework/skills/level-0-meta/{simulation-checklist → morph-simulation-checklist}/SKILL.md +0 -0
  116. /package/framework/skills/level-0-meta/{terminal-title → morph-terminal-title}/scripts/set_title.sh +0 -0
  117. /package/framework/skills/level-1-workflows/{phase-clarify → morph-phase-clarify}/references/clarifications-example.md +0 -0
  118. /package/framework/skills/level-1-workflows/{phase-design → morph-phase-design}/references/architecture-analysis-guide.md +0 -0
  119. /package/framework/skills/level-1-workflows/{phase-design → morph-phase-design}/references/spec-authoring-guide.md +0 -0
  120. /package/framework/skills/level-1-workflows/{phase-design → morph-phase-design}/references/spec-example.md +0 -0
  121. /package/framework/skills/level-1-workflows/{phase-implement → morph-phase-implement}/references/recap-example.md +0 -0
  122. /package/framework/skills/level-1-workflows/{phase-implement → morph-phase-implement}/references/vsa-implementation-guide.md +0 -0
  123. /package/framework/skills/level-1-workflows/{phase-tasks → morph-phase-tasks}/references/task-planning-patterns.md +0 -0
  124. /package/framework/skills/level-1-workflows/{phase-tasks → morph-phase-tasks}/references/tasks-example.md +0 -0
@@ -0,0 +1,97 @@
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
+ ---
7
+
8
+ # Scope Escalation Workflow
9
+
10
+ Use this skill when a task during implementation reveals significantly more complexity than estimated.
11
+
12
+ ## Prerequisites
13
+
14
+ - Feature must be in `implement` phase
15
+ - You must have identified a specific task that triggered the discovery
16
+
17
+ ## Workflow
18
+
19
+ ### Step 1: COLLECT Evidence
20
+
21
+ Ask the user (using `AskUserQuestion`):
22
+
23
+ 1. **Which task triggered the discovery?** (task ID from tasks.md)
24
+ 2. **What did you discover?** (specific complexity: hidden dependencies, wrong assumptions, missing abstractions)
25
+ 3. **Show evidence** — read the relevant code files to understand the actual complexity
26
+
27
+ ### Step 2: ANALYZE Impact
28
+
29
+ Run dry-run analysis:
30
+
31
+ ```bash
32
+ npx morph-spec scope escalate <feature> --task <id> --reason "<reason>" --dry-run
33
+ ```
34
+
35
+ Read the recommendation output. Additionally:
36
+
37
+ - Read `tasks.md` to understand which tasks are affected
38
+ - Read `spec.md` to check if the spec assumed simpler architecture
39
+ - Check completed tasks for potential impact
40
+
41
+ ### Step 3: CLASSIFY and PROPOSE
42
+
43
+ Present the recommendation to the user:
44
+
45
+ | Impact | Action | When |
46
+ |--------|--------|------|
47
+ | **Low** (1-3 tasks) | Task Expansion | The task is bigger than expected, but scope is contained |
48
+ | **Medium** (4+ tasks, spec ok) | Regress to tasks | Multiple tasks need rewriting, but the spec is correct |
49
+ | **High** (spec wrong) | Regress to design | The spec made incorrect assumptions about the codebase |
50
+
51
+ Explain WHY you recommend this classification based on the evidence.
52
+
53
+ ### Step 4: APPROVE
54
+
55
+ Pause and wait for user confirmation using `AskUserQuestion`:
56
+
57
+ - "Do you agree with the [impact] classification?"
58
+ - "Should we proceed with [action]?"
59
+ - Allow override: "Or would you prefer a different target phase?"
60
+
61
+ **DO NOT proceed without explicit user approval.**
62
+
63
+ ### Step 5: EXECUTE
64
+
65
+ Based on approved action:
66
+
67
+ **For expansion (low impact):**
68
+ ```bash
69
+ npx morph-spec task expand <feature> <task-id> --into "T017a: <title>" "T017b: <title>" ...
70
+ ```
71
+
72
+ **For regression (medium/high impact):**
73
+ ```bash
74
+ npx morph-spec scope escalate <feature> --task <id> --reason "<reason>"
75
+ ```
76
+
77
+ Or with target override:
78
+ ```bash
79
+ npx morph-spec scope escalate <feature> --task <id> --reason "<reason>" --target design
80
+ ```
81
+
82
+ ### Step 6: GUIDE Next Steps
83
+
84
+ After escalation:
85
+
86
+ - **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."
87
+ - **If regressed to design:** "Re-analyze the spec. Update spec.md with the discovered architecture. Then regenerate tasks."
88
+ - **If expanded:** "Continue implementing. Use `morph-spec task start <feature> <sub-task-id>` to start the first sub-task."
89
+
90
+ Always remind: "Completed tasks flagged with `needsReview` should be checked for compatibility with the new scope."
91
+
92
+ ## Anti-Patterns
93
+
94
+ - **DO NOT** skip the approval step
95
+ - **DO NOT** escalate without evidence — read the actual code first
96
+ - **DO NOT** regress to design when only tasks need rewriting
97
+ - **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.0",
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
  },
@@ -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
+ }
@@ -84,7 +84,11 @@ const REQUIRED_COMMAND_FILES = [
84
84
  'src/commands/validation/validate-feature.js',
85
85
  'src/commands/templates/template-render.js',
86
86
  'src/commands/agents/dispatch-agents.js',
87
- 'src/commands/project/worktree.js'
87
+ 'src/commands/project/worktree.js',
88
+ 'src/commands/phase/phase-reset.js',
89
+ 'src/commands/scope/escalate.js',
90
+ 'src/commands/task/expand.js',
91
+ 'src/lib/scope/impact-analyzer.js'
88
92
  ];
89
93
 
90
94
  // framework standards
@@ -296,10 +300,18 @@ async function doctorMcpCommand(targetPath) {
296
300
  for (const [name, config] of Object.entries(allMcpServers)) {
297
301
  const issues = [];
298
302
  let status = 'ok';
303
+ let isRemote = false;
299
304
 
300
- // ── 1. Binary check ────────────────────────────────────────────────────
305
+ // ── 0. Remote MCP detection ────────────────────────────────────────────
306
+ // Remote MCPs use HTTP transport (type: "http" or url property) — no binary to check
307
+ if (config.type === 'http' || (config.url && !config.command)) {
308
+ isRemote = true;
309
+ // Remote MCPs are always "ok" from a config perspective — auth happens at runtime
310
+ }
311
+
312
+ // ── 1. Binary check (stdio MCPs only) ──────────────────────────────────
301
313
  const cmd = config.command || '';
302
- if (cmd && !KNOWN_RUNTIMES.has(cmd)) {
314
+ if (!isRemote && cmd && !KNOWN_RUNTIMES.has(cmd)) {
303
315
  try {
304
316
  execSync(isWindows ? `where "${cmd}"` : `which "${cmd}"`, { stdio: 'ignore' });
305
317
  } catch {
@@ -329,12 +341,14 @@ async function doctorMcpCommand(targetPath) {
329
341
  }
330
342
  }
331
343
 
332
- checks.push({ name, status, issues, cmd });
344
+ checks.push({ name, status, issues, cmd, isRemote });
333
345
  }
334
346
 
335
347
  // ── Display ────────────────────────────────────────────────────────────────
336
348
  for (const c of checks) {
337
- const typeLabel = c.cmd ? chalk.gray(` [${c.cmd}]`) : '';
349
+ const typeLabel = c.isRemote
350
+ ? chalk.gray(` [remote: ${allMcpServers[c.name]?.url || 'http'}]`)
351
+ : c.cmd ? chalk.gray(` [${c.cmd}]`) : '';
338
352
 
339
353
  if (c.status === 'ok') {
340
354
  console.log(chalk.green(` ✓ ${c.name}`) + typeLabel);