@polymorphism-tech/morph-spec 4.8.19 → 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 (214) hide show
  1. package/CLAUDE.md +21 -0
  2. package/README.md +2 -2
  3. package/bin/morph-spec.js +44 -55
  4. package/bin/task-manager.js +133 -20
  5. package/bin/validate.js +67 -33
  6. package/claude-plugin.json +1 -1
  7. package/docs/CHEATSHEET.md +201 -203
  8. package/docs/QUICKSTART.md +2 -2
  9. package/framework/CLAUDE.md +99 -77
  10. package/framework/agents.json +734 -182
  11. package/framework/commands/commit.md +166 -0
  12. package/framework/commands/morph-apply.md +13 -2
  13. package/framework/commands/morph-archive.md +8 -2
  14. package/framework/commands/morph-infra.md +6 -0
  15. package/framework/commands/morph-preflight.md +6 -0
  16. package/framework/commands/morph-proposal.md +56 -7
  17. package/framework/commands/morph-status.md +6 -0
  18. package/framework/commands/morph-troubleshoot.md +6 -0
  19. package/framework/hooks/claude-code/notification/approval-reminder.js +3 -2
  20. package/framework/hooks/claude-code/post-tool-use/context-refresh.js +1 -1
  21. package/framework/hooks/claude-code/post-tool-use/dispatch.js +155 -32
  22. package/framework/hooks/claude-code/post-tool-use/skill-reminder.js +78 -0
  23. package/framework/hooks/claude-code/post-tool-use/validator-feedback.js +8 -17
  24. package/framework/hooks/claude-code/pre-compact/save-morph-context.js +16 -3
  25. package/framework/hooks/claude-code/pre-tool-use/enforce-phase-writes.js +4 -3
  26. package/framework/hooks/claude-code/pre-tool-use/protect-spec-files.js +4 -3
  27. package/framework/hooks/claude-code/pre-tool-use/task-tracking-guard.js +60 -0
  28. package/framework/hooks/claude-code/session-start/inject-morph-context.js +124 -2
  29. package/framework/hooks/claude-code/session-start/post-compact-restore.js +41 -0
  30. package/framework/hooks/claude-code/statusline.py +76 -30
  31. package/framework/hooks/claude-code/stop/validate-completion.js +2 -15
  32. package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +23 -5
  33. package/framework/hooks/claude-code/user-prompt/set-terminal-title.js +14 -6
  34. package/framework/hooks/shared/activity-logger.js +0 -24
  35. package/framework/hooks/shared/compact-restore.js +100 -0
  36. package/framework/hooks/shared/dispatch-helpers.js +116 -0
  37. package/framework/hooks/shared/phase-utils.js +12 -5
  38. package/framework/hooks/shared/skill-reminder-helpers.js +79 -0
  39. package/framework/hooks/shared/stale-task-reset.js +57 -0
  40. package/framework/hooks/shared/state-reader.js +29 -5
  41. package/framework/hooks/shared/worktree-helpers.js +53 -0
  42. package/framework/phases.json +69 -14
  43. package/framework/rules/morph-workflow.md +88 -86
  44. package/framework/skills/level-0-meta/mcp-registry.json +86 -51
  45. package/framework/skills/level-0-meta/{brainstorming → morph-brainstorming}/SKILL.md +14 -17
  46. package/framework/skills/level-0-meta/morph-checklist/SKILL.md +2 -2
  47. package/framework/skills/level-0-meta/{code-review → morph-code-review}/SKILL.md +2 -2
  48. package/framework/skills/level-0-meta/{code-review-nextjs → morph-code-review-nextjs}/SKILL.md +163 -163
  49. package/framework/skills/level-0-meta/{frontend-review → morph-frontend-review}/SKILL.md +9 -9
  50. package/framework/skills/level-0-meta/morph-init/SKILL.md +77 -12
  51. package/framework/skills/level-0-meta/{post-implementation → morph-post-implementation}/SKILL.md +62 -15
  52. package/framework/skills/level-0-meta/morph-replicate/SKILL.md +5 -5
  53. package/framework/skills/level-0-meta/morph-replicate/references/blazor-html-mapping.md +1 -1
  54. package/framework/skills/level-0-meta/{simulation-checklist → morph-simulation-checklist}/SKILL.md +1 -1
  55. package/framework/skills/level-0-meta/{terminal-title → morph-terminal-title}/SKILL.md +2 -2
  56. package/framework/skills/level-0-meta/{tool-usage-guide → morph-tool-usage-guide}/SKILL.md +3 -4
  57. package/framework/skills/level-0-meta/{tool-usage-guide → morph-tool-usage-guide}/references/tools-per-phase.md +7 -7
  58. package/framework/skills/level-0-meta/{verification-before-completion → morph-verification-before-completion}/SKILL.md +2 -2
  59. package/framework/skills/level-0-meta/{verification-before-completion → morph-verification-before-completion}/scripts/check-phase-outputs.mjs +2 -2
  60. package/framework/skills/level-1-workflows/morph-phase-clarify/SKILL.md +238 -0
  61. package/framework/skills/level-1-workflows/{phase-codebase-analysis → morph-phase-codebase-analysis}/SKILL.md +3 -3
  62. package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +507 -0
  63. package/framework/skills/level-1-workflows/{phase-implement → morph-phase-implement}/SKILL.md +168 -27
  64. package/framework/skills/level-1-workflows/morph-phase-implement/prompts/code-quality-reviewer-prompt.md +50 -0
  65. package/framework/skills/level-1-workflows/morph-phase-implement/prompts/implementer-prompt.md +45 -0
  66. package/framework/skills/level-1-workflows/morph-phase-implement/prompts/spec-reviewer-prompt.md +47 -0
  67. package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +254 -0
  68. package/framework/skills/level-1-workflows/{phase-setup → morph-phase-setup}/SKILL.md +50 -3
  69. package/framework/skills/level-1-workflows/{phase-tasks → morph-phase-tasks}/SKILL.md +48 -11
  70. package/framework/skills/level-1-workflows/{phase-tasks → morph-phase-tasks}/scripts/validate-tasks.mjs +3 -3
  71. package/framework/skills/level-1-workflows/{phase-uiux → morph-phase-uiux}/SKILL.md +46 -11
  72. package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +97 -0
  73. package/framework/standards/STANDARDS.json +640 -88
  74. package/framework/standards/infrastructure/vercel/vercel-database.md +106 -0
  75. package/framework/standards/integration/mcp/mcp-tools.md +25 -7
  76. package/framework/templates/REGISTRY.json +1825 -1909
  77. package/framework/templates/context/CONTEXT-FEATURE.md +276 -276
  78. package/framework/templates/docs/onboarding.md +3 -7
  79. package/package.json +2 -7
  80. package/src/commands/agents/dispatch-agents.js +104 -6
  81. package/src/commands/mcp/mcp-setup.js +39 -2
  82. package/src/commands/phase/phase-reset.js +74 -0
  83. package/src/commands/project/doctor.js +34 -51
  84. package/src/commands/project/init.js +1 -1
  85. package/src/commands/project/status.js +2 -2
  86. package/src/commands/project/update.js +381 -365
  87. package/src/commands/project/worktree.js +154 -0
  88. package/src/commands/scope/escalate.js +215 -0
  89. package/src/commands/state/advance-phase.js +132 -68
  90. package/src/commands/state/approve.js +2 -2
  91. package/src/commands/state/index.js +7 -8
  92. package/src/commands/state/phase-runner.js +1 -1
  93. package/src/commands/state/state.js +61 -6
  94. package/src/commands/task/expand.js +100 -0
  95. package/src/commands/tasks/task.js +78 -99
  96. package/src/commands/templates/template-render.js +93 -173
  97. package/src/commands/trust/trust.js +26 -21
  98. package/src/core/paths/output-schema.js +19 -3
  99. package/src/core/state/phase-state-machine.js +7 -4
  100. package/src/core/state/state-manager.js +32 -57
  101. package/src/core/workflows/workflow-detector.js +9 -87
  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 +336 -0
  108. package/src/lib/scope/impact-analyzer.js +106 -0
  109. package/src/lib/stack/stack-profile.js +88 -0
  110. package/src/lib/tasks/task-classifier.js +16 -0
  111. package/src/lib/tasks/task-parser.js +1 -1
  112. package/src/lib/tasks/test-runner.js +77 -0
  113. package/src/lib/trust/trust-manager.js +32 -144
  114. package/src/lib/validators/shared/emit-validator-dispatch.js +64 -0
  115. package/src/lib/validators/spec-validator.js +58 -4
  116. package/src/lib/validators/validation-runner.js +23 -11
  117. package/src/scripts/setup-infra.js +255 -224
  118. package/src/utils/agents-installer.js +34 -14
  119. package/src/utils/banner.js +1 -1
  120. package/src/utils/claude-settings-manager.js +1 -1
  121. package/src/utils/file-copier.js +1 -1
  122. package/src/utils/hooks-installer.js +272 -8
  123. package/framework/hooks/dev/check-sync-health.js +0 -117
  124. package/framework/hooks/dev/guard-version-numbers.js +0 -57
  125. package/framework/hooks/dev/sync-standards-registry.js +0 -60
  126. package/framework/hooks/dev/sync-template-registry.js +0 -60
  127. package/framework/hooks/dev/validate-skill-format.js +0 -70
  128. package/framework/hooks/dev/validate-standard-format.js +0 -73
  129. package/framework/skills/level-1-workflows/phase-clarify/SKILL.md +0 -190
  130. package/framework/skills/level-1-workflows/phase-design/SKILL.md +0 -366
  131. package/framework/templates/meta-prompts/hops/hop-retry.md +0 -78
  132. package/framework/templates/meta-prompts/hops/hop-validation.md +0 -97
  133. package/framework/templates/meta-prompts/hops/hop-wrapper.md +0 -36
  134. package/framework/workflows/configs/design-impl.json +0 -49
  135. package/framework/workflows/configs/express.json +0 -45
  136. package/framework/workflows/configs/fast-track.json +0 -42
  137. package/framework/workflows/configs/full-morph.json +0 -79
  138. package/framework/workflows/configs/fusion.json +0 -39
  139. package/framework/workflows/configs/long-running.json +0 -33
  140. package/framework/workflows/configs/spec-only.json +0 -43
  141. package/framework/workflows/configs/ui-refresh.json +0 -49
  142. package/framework/workflows/configs/zero-touch.json +0 -82
  143. package/src/commands/project/index.js +0 -8
  144. package/src/commands/project/monitor.js +0 -295
  145. package/src/commands/project/tutorial.js +0 -115
  146. package/src/commands/state/validate-phase.js +0 -238
  147. package/src/commands/templates/generate-contracts.js +0 -445
  148. package/src/core/index.js +0 -10
  149. package/src/core/orchestrator.js +0 -171
  150. package/src/core/registry/command-registry.js +0 -28
  151. package/src/core/registry/index.js +0 -8
  152. package/src/core/registry/validator-registry.js +0 -204
  153. package/src/core/state/index.js +0 -8
  154. package/src/core/templates/index.js +0 -9
  155. package/src/core/templates/template-data-sources.js +0 -325
  156. package/src/core/templates/template-validator.js +0 -296
  157. package/src/core/workflows/index.js +0 -7
  158. package/src/generator/config-generator.js +0 -206
  159. package/src/generator/templates/config.json.template +0 -40
  160. package/src/generator/templates/project.md.template +0 -67
  161. package/src/lib/agents/micro-agent-factory.js +0 -161
  162. package/src/lib/analysis/complexity-analyzer.js +0 -441
  163. package/src/lib/analysis/index.js +0 -7
  164. package/src/lib/analytics/analytics-engine.js +0 -345
  165. package/src/lib/checkpoints/checkpoint-hooks.js +0 -298
  166. package/src/lib/checkpoints/index.js +0 -7
  167. package/src/lib/context/context-bundler.js +0 -241
  168. package/src/lib/context/context-optimizer.js +0 -212
  169. package/src/lib/context/context-tracker.js +0 -273
  170. package/src/lib/context/core-four-tracker.js +0 -201
  171. package/src/lib/context/mcp-optimizer.js +0 -200
  172. package/src/lib/detectors/config-detector.js +0 -223
  173. package/src/lib/detectors/standards-generator.js +0 -335
  174. package/src/lib/detectors/structure-detector.js +0 -275
  175. package/src/lib/execution/fusion-executor.js +0 -304
  176. package/src/lib/execution/parallel-executor.js +0 -270
  177. package/src/lib/hooks/stop-hook-executor.js +0 -286
  178. package/src/lib/hops/hop-composer.js +0 -221
  179. package/src/lib/monitor/agent-resolver.js +0 -144
  180. package/src/lib/monitor/renderer.js +0 -230
  181. package/src/lib/orchestration/index.js +0 -7
  182. package/src/lib/orchestration/team-orchestrator.js +0 -404
  183. package/src/lib/phase-chain/eligibility-checker.js +0 -243
  184. package/src/lib/threads/thread-coordinator.js +0 -238
  185. package/src/lib/threads/thread-manager.js +0 -317
  186. package/src/lib/tracking/artifact-trail.js +0 -202
  187. package/src/sanitizer/context-sanitizer.js +0 -221
  188. package/src/sanitizer/patterns.js +0 -163
  189. package/src/scanner/project-scanner.js +0 -242
  190. package/src/ui/diff-display.js +0 -91
  191. package/src/ui/interactive-wizard.js +0 -96
  192. package/src/ui/user-review.js +0 -211
  193. package/src/ui/wizard-questions.js +0 -188
  194. package/src/utils/color-utils.js +0 -70
  195. package/src/utils/process-handler.js +0 -97
  196. package/src/writer/file-writer.js +0 -86
  197. /package/framework/skills/level-0-meta/{brainstorming → morph-brainstorming}/references/proposal-example.md +0 -0
  198. /package/framework/skills/level-0-meta/{code-review → morph-code-review}/references/review-example.md +0 -0
  199. /package/framework/skills/level-0-meta/{code-review → morph-code-review}/references/review-guidelines.md +0 -0
  200. /package/framework/skills/level-0-meta/{code-review → morph-code-review}/scripts/scan-csharp.mjs +0 -0
  201. /package/framework/skills/level-0-meta/{code-review-nextjs → morph-code-review-nextjs}/references/review-example-nextjs.md +0 -0
  202. /package/framework/skills/level-0-meta/{code-review-nextjs → morph-code-review-nextjs}/scripts/scan-nextjs.mjs +0 -0
  203. /package/framework/skills/level-0-meta/{frontend-review → morph-frontend-review}/scripts/scan-accessibility.mjs +0 -0
  204. /package/framework/skills/level-0-meta/{post-implementation → morph-post-implementation}/scripts/detect-dev-server.mjs +0 -0
  205. /package/framework/skills/level-0-meta/{post-implementation → morph-post-implementation}/scripts/detect-stack.mjs +0 -0
  206. /package/framework/skills/level-0-meta/{terminal-title → morph-terminal-title}/scripts/set_title.sh +0 -0
  207. /package/framework/skills/level-1-workflows/{phase-clarify → morph-phase-clarify}/references/clarifications-example.md +0 -0
  208. /package/framework/skills/level-1-workflows/{phase-design → morph-phase-design}/references/architecture-analysis-guide.md +0 -0
  209. /package/framework/skills/level-1-workflows/{phase-design → morph-phase-design}/references/spec-authoring-guide.md +0 -0
  210. /package/framework/skills/level-1-workflows/{phase-design → morph-phase-design}/references/spec-example.md +0 -0
  211. /package/framework/skills/level-1-workflows/{phase-implement → morph-phase-implement}/references/recap-example.md +0 -0
  212. /package/framework/skills/level-1-workflows/{phase-implement → morph-phase-implement}/references/vsa-implementation-guide.md +0 -0
  213. /package/framework/skills/level-1-workflows/{phase-tasks → morph-phase-tasks}/references/task-planning-patterns.md +0 -0
  214. /package/framework/skills/level-1-workflows/{phase-tasks → morph-phase-tasks}/references/tasks-example.md +0 -0
@@ -1,295 +0,0 @@
1
- /**
2
- * morph-spec monitor — Live TUI Dashboard
3
- *
4
- * Opens a live-updating terminal UI showing:
5
- * - Active agents by tier
6
- * - Hook events (chronological feed)
7
- * - Skills invoked this session
8
- * - Rules in effect
9
- * - Overview summary
10
- *
11
- * Reads .morph/logs/activity.json (written by hooks via activity-logger.js).
12
- * Uses fs.watch for live updates (no polling, no chokidar).
13
- *
14
- * Usage:
15
- * morph-spec monitor [feature]
16
- * morph-spec monitor --compact
17
- * morph-spec monitor --mode hooks
18
- */
19
-
20
- import { watch, existsSync, readFileSync, readdirSync, statSync } from 'fs';
21
- import { join, basename } from 'path';
22
- import chalk from 'chalk';
23
-
24
- import {
25
- renderBox,
26
- renderFeed,
27
- renderAgents,
28
- renderSkills,
29
- renderRules,
30
- renderOverview,
31
- renderStatusBar,
32
- renderHeader,
33
- } from '../../lib/monitor/renderer.js';
34
-
35
- import { getActiveAgents } from '../../lib/monitor/agent-resolver.js';
36
- import { readActivity } from '../../../framework/hooks/shared/activity-logger.js';
37
- import { loadState, getActiveFeature, derivePhaseForFeature } from '../../../framework/hooks/shared/state-reader.js';
38
-
39
- const MODES = ['overview', 'hooks', 'agents', 'skills', 'rules'];
40
- const ACTIVITY_FILE = '.morph/logs/activity.json';
41
- const RULES_DIR_PROJECT = '.claude/rules';
42
- const RULES_DIR_FRAMEWORK = '.morph/framework/rules';
43
-
44
- // ─────────────────────────────────────────────────────────
45
- // Rules loading
46
- // ─────────────────────────────────────────────────────────
47
-
48
- function loadRules(cwd) {
49
- const rules = [];
50
- const dirs = [
51
- join(cwd, RULES_DIR_PROJECT),
52
- join(cwd, RULES_DIR_FRAMEWORK),
53
- join(cwd, 'framework/rules'),
54
- ];
55
-
56
- for (const dir of dirs) {
57
- if (!existsSync(dir)) continue;
58
- try {
59
- const files = readdirSync(dir).filter(f => f.endsWith('.md'));
60
- for (const file of files) {
61
- // Parse front-matter paths glob if present
62
- let glob = '*';
63
- try {
64
- const content = readFileSync(join(dir, file), 'utf-8');
65
- const match = content.match(/paths:\s*\n((?:\s*-\s*.+\n?)+)/);
66
- if (match) {
67
- const paths = match[1].match(/- (.+)/g);
68
- if (paths) glob = paths.map(p => p.replace('- ', '').trim()).join(', ');
69
- }
70
- } catch { /* skip */ }
71
- rules.push({ name: basename(file, '.md'), glob });
72
- }
73
- } catch { /* skip */ }
74
- }
75
- return rules;
76
- }
77
-
78
- // ─────────────────────────────────────────────────────────
79
- // Available skills loading
80
- // ─────────────────────────────────────────────────────────
81
-
82
- function loadAvailableSkills(cwd) {
83
- const skillDirs = [
84
- join(cwd, '.claude/skills'),
85
- join(cwd, 'framework/skills'),
86
- ];
87
- const names = [];
88
- for (const dir of skillDirs) {
89
- if (!existsSync(dir)) continue;
90
- try {
91
- const entries = readdirSync(dir, { withFileTypes: true });
92
- for (const entry of entries) {
93
- if (entry.isDirectory()) {
94
- // Level-N-meta/skill-name or direct skill dirs
95
- const sub = readdirSync(join(dir, entry.name), { withFileTypes: true });
96
- for (const s of sub) {
97
- if (s.isDirectory()) names.push(s.name);
98
- }
99
- }
100
- }
101
- } catch { /* skip */ }
102
- }
103
- return [...new Set(names)];
104
- }
105
-
106
- // ─────────────────────────────────────────────────────────
107
- // Screen rendering
108
- // ─────────────────────────────────────────────────────────
109
-
110
- function render(state) {
111
- const { feature, phase, tasks, agentsByTier, activity, rules, availableSkills, mode, compact } = state;
112
-
113
- const hooks = activity?.hooks || [];
114
- const skills = activity?.skills || [];
115
-
116
- // Clear screen
117
- process.stdout.write('\x1Bc');
118
-
119
- // Header
120
- process.stdout.write(renderHeader(feature, phase, tasks) + '\n');
121
-
122
- if (compact) {
123
- // Compact: just show overview
124
- const overviewData = { feature, phase, agentsByTier, hooks, skills, rules };
125
- process.stdout.write(renderOverview(overviewData) + '\n');
126
- } else {
127
- switch (mode) {
128
- case 'hooks':
129
- process.stdout.write(renderFeed(hooks) + '\n');
130
- break;
131
-
132
- case 'agents':
133
- process.stdout.write(renderAgents(agentsByTier, phase) + '\n');
134
- break;
135
-
136
- case 'skills':
137
- process.stdout.write(renderSkills(skills, availableSkills) + '\n');
138
- break;
139
-
140
- case 'rules':
141
- process.stdout.write(renderRules(rules) + '\n');
142
- break;
143
-
144
- case 'overview':
145
- default: {
146
- const overviewData = { feature, phase, agentsByTier, hooks, skills, rules };
147
- process.stdout.write(renderOverview(overviewData) + '\n');
148
- break;
149
- }
150
- }
151
- }
152
-
153
- // Status bar
154
- process.stdout.write(renderStatusBar(mode, MODES) + '\n');
155
- }
156
-
157
- // ─────────────────────────────────────────────────────────
158
- // State loading
159
- // ─────────────────────────────────────────────────────────
160
-
161
- function loadMonitorState(cwd, featureArg) {
162
- let feature = featureArg || '';
163
- let phase = '';
164
- let tasks = null;
165
-
166
- try {
167
- const morphState = loadState(cwd);
168
- if (!feature && morphState) {
169
- const active = getActiveFeature(cwd);
170
- if (active) {
171
- feature = active.name;
172
- tasks = active.feature.tasks || null;
173
- }
174
- }
175
- if (feature) {
176
- phase = derivePhaseForFeature(feature, cwd);
177
- }
178
- } catch { /* fail-open */ }
179
-
180
- const agentsByTier = getActiveAgents(cwd, phase);
181
- const activity = readActivity(cwd);
182
- const rules = loadRules(cwd);
183
- const availableSkills = loadAvailableSkills(cwd);
184
-
185
- return { feature, phase, tasks, agentsByTier, activity, rules, availableSkills };
186
- }
187
-
188
- // ─────────────────────────────────────────────────────────
189
- // Main command
190
- // ─────────────────────────────────────────────────────────
191
-
192
- /**
193
- * @param {string|undefined} featureArg
194
- * @param {{ compact: boolean, mode: string }} opts
195
- */
196
- export function monitorCommand(featureArg, opts = {}) {
197
- const cwd = process.cwd();
198
- const compact = !!opts.compact;
199
- const startMode = MODES.includes(opts.mode) ? opts.mode : 'overview';
200
-
201
- let modeIndex = MODES.indexOf(startMode);
202
- let currentMode = startMode;
203
-
204
- // Initial render
205
- let monitorState = loadMonitorState(cwd, featureArg);
206
- render({ ...monitorState, mode: currentMode, compact });
207
-
208
- // Watch activity.json for changes
209
- const activityPath = join(cwd, ACTIVITY_FILE);
210
- let watcher = null;
211
-
212
- function startWatcher() {
213
- if (!existsSync(activityPath)) {
214
- // Retry watch setup when file is created
215
- setTimeout(startWatcher, 2000);
216
- return;
217
- }
218
-
219
- try {
220
- watcher = watch(activityPath, { persistent: true }, () => {
221
- try {
222
- monitorState = loadMonitorState(cwd, featureArg);
223
- render({ ...monitorState, mode: currentMode, compact });
224
- } catch { /* fail-open */ }
225
- });
226
- } catch {
227
- // fs.watch not supported — fall back to polling
228
- setInterval(() => {
229
- try {
230
- monitorState = loadMonitorState(cwd, featureArg);
231
- render({ ...monitorState, mode: currentMode, compact });
232
- } catch { /* fail-open */ }
233
- }, 2000);
234
- }
235
- }
236
-
237
- startWatcher();
238
-
239
- // Keyboard input: raw mode
240
- if (process.stdin.isTTY) {
241
- process.stdin.setRawMode(true);
242
- process.stdin.resume();
243
- process.stdin.setEncoding('utf8');
244
-
245
- process.stdin.on('data', (key) => {
246
- // q or Ctrl-C → quit
247
- if (key === 'q' || key === '\u0003') {
248
- if (watcher) watcher.close();
249
- process.stdin.setRawMode(false);
250
- process.stdout.write('\n' + chalk.gray('morph-spec monitor closed.\n'));
251
- process.exit(0);
252
- }
253
-
254
- // shift+tab → cycle modes (forward)
255
- // \x1b[Z is the standard escape for shift+tab
256
- if (key === '\x1b[Z' || key === '\t') {
257
- modeIndex = (modeIndex + 1) % MODES.length;
258
- currentMode = MODES[modeIndex];
259
- render({ ...monitorState, mode: currentMode, compact });
260
- }
261
-
262
- // Arrow keys: left/right also cycle
263
- if (key === '\x1b[C') { // right arrow
264
- modeIndex = (modeIndex + 1) % MODES.length;
265
- currentMode = MODES[modeIndex];
266
- render({ ...monitorState, mode: currentMode, compact });
267
- }
268
- if (key === '\x1b[D') { // left arrow
269
- modeIndex = (modeIndex - 1 + MODES.length) % MODES.length;
270
- currentMode = MODES[modeIndex];
271
- render({ ...monitorState, mode: currentMode, compact });
272
- }
273
-
274
- // r → force refresh
275
- if (key === 'r') {
276
- monitorState = loadMonitorState(cwd, featureArg);
277
- render({ ...monitorState, mode: currentMode, compact });
278
- }
279
- });
280
- } else {
281
- // Non-TTY: just render once and exit (useful for scripting/piping)
282
- process.stdout.write('\n' + chalk.gray('(non-interactive mode — run in a real terminal for live updates)\n'));
283
- }
284
-
285
- // Handle process signals
286
- process.on('SIGINT', () => {
287
- if (watcher) watcher.close();
288
- process.stdout.write('\n' + chalk.gray('morph-spec monitor closed.\n'));
289
- process.exit(0);
290
- });
291
- process.on('SIGTERM', () => {
292
- if (watcher) watcher.close();
293
- process.exit(0);
294
- });
295
- }
@@ -1,115 +0,0 @@
1
- /**
2
- * Tutorial Command
3
- *
4
- * Prints the MORPH-SPEC workflow pipeline and getting-started steps.
5
- * Pure stdout — no file I/O, no network, no side effects.
6
- *
7
- * Usage: morph-spec tutorial
8
- */
9
-
10
- import chalk from 'chalk';
11
-
12
- const PHASES = [
13
- {
14
- label: 'FASE 0 · PROPOSAL',
15
- what: 'Captures user story + acceptance criteria.',
16
- produces: '0-proposal/proposal.md',
17
- how: '/morph-proposal <feature> (in Claude Code)',
18
- },
19
- {
20
- label: 'FASE 1 · SETUP',
21
- what: 'Detects stack, activates agents, confirms environment.',
22
- produces: '.morph/state.json initialized',
23
- how: 'auto-triggered inside /morph-proposal',
24
- },
25
- {
26
- label: 'FASE 1.5 · UI/UX',
27
- what: 'Design system, mockups, component specs, user flows.',
28
- produces: '2-ui/{design-system,mockups,components,flows}.md',
29
- how: '/phase-uiux <feature> (in Claude Code)',
30
- optional: true,
31
- },
32
- {
33
- label: 'FASE 2 · DESIGN',
34
- what: 'Technical spec + C# contracts + architecture decisions.',
35
- produces: '1-design/{spec.md, contracts-level{N}.cs, decisions.md}',
36
- how: '/phase-design <feature> (in Claude Code)',
37
- },
38
- {
39
- label: 'FASE 3 · CLARIFY',
40
- what: 'Reviews spec for ambiguities, adds edge cases.',
41
- produces: '1-design/spec.md (updated with clarifications)',
42
- how: '/phase-clarify <feature> (in Claude Code)',
43
- },
44
- {
45
- label: 'FASE 4 · TASKS',
46
- what: 'Atomic task breakdown, DDD-aware.',
47
- produces: '3-tasks/tasks.md',
48
- how: 'auto-generated during /morph-proposal, or /phase-tasks <feature>',
49
- },
50
- {
51
- label: 'FASE 5 · IMPLEMENT',
52
- what: 'Code implementation with checkpoints every 3 tasks.',
53
- produces: '4-implement/recap.md + source code',
54
- how: '/morph-apply <feature> (in Claude Code)',
55
- },
56
- {
57
- label: 'FASE 6 · SYNC',
58
- what: 'Syncs decisions back to project standards.',
59
- produces: '.morph/framework/standards/ (updated)',
60
- how: 'morph-spec sync <feature>',
61
- optional: true,
62
- },
63
- ];
64
-
65
- const SEP = chalk.dim('─'.repeat(58));
66
-
67
- export function tutorialCommand() {
68
- console.log('');
69
- console.log(chalk.cyan.bold(' MORPH-SPEC Workflow Tutorial'));
70
- console.log(SEP);
71
- console.log('');
72
- console.log(
73
- chalk.white(
74
- ' MORPH-SPEC is spec-first: every feature goes through phases\n' +
75
- ' before any code is written. Each phase produces structured\n' +
76
- ' outputs that feed the next.'
77
- )
78
- );
79
- console.log('');
80
- console.log(SEP);
81
- console.log(chalk.cyan.bold(' PIPELINE'));
82
- console.log(SEP);
83
- console.log('');
84
- console.log(
85
- chalk.white(' proposal → setup → ') +
86
- chalk.dim('[uiux]') +
87
- chalk.white(' → design → clarify → tasks → implement → ') +
88
- chalk.dim('[sync]')
89
- );
90
- console.log(chalk.dim(' (phases in brackets are optional)'));
91
- console.log('');
92
-
93
- for (const phase of PHASES) {
94
- console.log(SEP);
95
- const label = phase.optional
96
- ? chalk.cyan.bold(` ${phase.label}`) + chalk.dim(' [optional]')
97
- : chalk.cyan.bold(` ${phase.label}`);
98
- console.log(label);
99
- console.log(chalk.white(` What: ${phase.what}`));
100
- console.log(chalk.dim(` Produces: ${phase.produces}`));
101
- console.log(chalk.green(` How: ${phase.how}`));
102
- console.log('');
103
- }
104
-
105
- console.log(SEP);
106
- console.log(chalk.cyan.bold(' GETTING STARTED'));
107
- console.log(SEP);
108
- console.log('');
109
- console.log(chalk.white(' 1. Open Claude Code in your project'));
110
- console.log(chalk.white(' 2. Run: ') + chalk.green('/morph-proposal <your-feature-name>'));
111
- console.log(chalk.white(' 3. Answer the questions — morph-spec handles the rest'));
112
- console.log('');
113
- console.log(chalk.dim(' Tip: run `morph-spec doctor` to verify your installation first.'));
114
- console.log('');
115
- }
@@ -1,238 +0,0 @@
1
- /**
2
- * MORPH-SPEC Phase Validator Command
3
- *
4
- * Validates that required previous phases have been completed before advancing.
5
- * Prevents skipping phases accidentally.
6
- *
7
- * Usage:
8
- * morph-spec validate-phase <feature-name> <target-phase>
9
- *
10
- * Example:
11
- * morph-spec validate-phase scheduled-reports implement
12
- */
13
-
14
- import fs from 'fs';
15
- import path from 'path';
16
- import chalk from 'chalk';
17
- import { loadState, getFeature } from '../../core/state/state-manager.js';
18
-
19
- // Phase definitions with requirements
20
- const PHASES = {
21
- 'proposal': {
22
- order: 0,
23
- name: 'FASE 0: PROPOSAL',
24
- requiredOutputs: [],
25
- description: 'Initial proposal and agent detection'
26
- },
27
- 'setup': {
28
- order: 1,
29
- name: 'FASE 1: SETUP',
30
- requiredOutputs: ['proposal.md'],
31
- description: 'Load context and standards'
32
- },
33
- 'uiux': {
34
- order: 2,
35
- name: 'FASE 1.5: UI/UX DESIGN',
36
- requiredOutputs: ['proposal.md'],
37
- optionalOutputs: ['ui-design-system.md', 'ui-mockups.md', 'ui-components.md', 'ui-flows.md'],
38
- description: 'UI/UX design (conditional - only if frontend)',
39
- optional: true
40
- },
41
- 'design': {
42
- order: 3,
43
- name: 'FASE 2: DESIGN',
44
- requiredOutputs: ['proposal.md'],
45
- description: 'Technical specification and contracts'
46
- },
47
- 'clarify': {
48
- order: 4,
49
- name: 'FASE 3: CLARIFY',
50
- requiredOutputs: ['proposal.md', 'spec.md'],
51
- description: 'Clarify ambiguities and edge cases'
52
- },
53
- 'tasks': {
54
- order: 5,
55
- name: 'FASE 4: TASKS',
56
- requiredOutputs: ['proposal.md', 'spec.md'],
57
- description: 'Break down into executable tasks'
58
- },
59
- 'implement': {
60
- order: 6,
61
- name: 'FASE 5: IMPLEMENT',
62
- requiredOutputs: ['proposal.md', 'spec.md'],
63
- description: 'Execute tasks and implement code'
64
- },
65
- 'sync': {
66
- order: 7,
67
- name: 'FASE 6: SYNC',
68
- requiredOutputs: ['proposal.md', 'spec.md', 'decisions.md'],
69
- description: 'Sync decisions to project standards',
70
- optional: true
71
- }
72
- };
73
-
74
- // Map output filenames to their phase subfolders
75
- const OUTPUT_PHASE_MAP = {
76
- 'proposal.md': '0-proposal',
77
- 'schema-analysis.md': '1-design',
78
- 'spec.md': '1-design',
79
- 'clarifications.md': '1-design',
80
- 'contracts.cs': '1-design',
81
- 'decisions.md': '1-design',
82
- 'ui-design-system.md': '2-ui',
83
- 'ui-mockups.md': '2-ui',
84
- 'ui-components.md': '2-ui',
85
- 'ui-flows.md': '2-ui',
86
- 'tasks.md': '3-tasks',
87
- 'recap.md': '4-implement'
88
- };
89
-
90
- /**
91
- * Check if output file exists
92
- */
93
- function checkOutput(featurePath, outputFile) {
94
- const phaseDir = OUTPUT_PHASE_MAP[outputFile] || '';
95
- const filePath = path.join(featurePath, phaseDir, outputFile);
96
- return fs.existsSync(filePath);
97
- }
98
-
99
- /**
100
- * Validate phase requirements
101
- */
102
- function validatePhase(featureName, targetPhase) {
103
- const featurePath = path.join(process.cwd(), '.morph/features', featureName);
104
-
105
- // Check if feature directory exists
106
- if (!fs.existsSync(featurePath)) {
107
- return {
108
- valid: false,
109
- error: `Feature directory not found: ${featurePath}`,
110
- suggestion: `Run 'morph-spec state set ${featureName} phase proposal' to start`,
111
- missingOutputs: [],
112
- phase: null
113
- };
114
- }
115
-
116
- // Get target phase definition
117
- const phaseDefinition = PHASES[targetPhase];
118
- if (!phaseDefinition) {
119
- return {
120
- valid: false,
121
- error: `Unknown phase: ${targetPhase}`,
122
- validPhases: Object.keys(PHASES),
123
- missingOutputs: [],
124
- phase: null
125
- };
126
- }
127
-
128
- // Check required outputs
129
- const missingOutputs = [];
130
- for (const output of phaseDefinition.requiredOutputs) {
131
- if (!checkOutput(featurePath, output)) {
132
- missingOutputs.push(output);
133
- }
134
- }
135
-
136
- // Check state.json for current phase
137
- let stateWarning = null;
138
- try {
139
- const feature = getFeature(featureName);
140
- if (feature) {
141
- const currentPhaseOrder = PHASES[feature.phase]?.order ?? -1;
142
- const targetPhaseOrder = phaseDefinition.order;
143
-
144
- if (targetPhaseOrder > currentPhaseOrder + 1) {
145
- stateWarning = `Skipping phases: current is '${feature.phase}' (order ${currentPhaseOrder}), target is '${targetPhase}' (order ${targetPhaseOrder})`;
146
- }
147
- }
148
- } catch {
149
- // State file may not exist, that's OK
150
- }
151
-
152
- // Special validation: if target is 'implement', check tasks exist in state
153
- if (targetPhase === 'implement') {
154
- try {
155
- const feature = getFeature(featureName);
156
- if (feature && (!feature.tasks || feature.tasks.total === 0)) {
157
- missingOutputs.push('tasks in state.json (run morph-spec task to add tasks)');
158
- }
159
- } catch {
160
- // State file may not exist
161
- }
162
- }
163
-
164
- return {
165
- valid: missingOutputs.length === 0,
166
- error: null,
167
- missingOutputs,
168
- phase: phaseDefinition,
169
- featurePath,
170
- stateWarning
171
- };
172
- }
173
-
174
- /**
175
- * Main command handler
176
- */
177
- export async function validatePhaseCommand(feature, phase, options = {}) {
178
- console.log(chalk.cyan('\n╔════════════════════════════════════════════════╗'));
179
- console.log(chalk.cyan('║ MORPH-SPEC PHASE VALIDATOR ║'));
180
- console.log(chalk.cyan('╚════════════════════════════════════════════════╝\n'));
181
-
182
- const result = validatePhase(feature, phase);
183
-
184
- console.log(chalk.gray('Feature:'), feature);
185
- console.log(chalk.gray('Target Phase:'), result.phase ? result.phase.name : phase);
186
-
187
- if (result.phase) {
188
- console.log(chalk.gray('Description:'), result.phase.description);
189
- }
190
-
191
- if (result.stateWarning) {
192
- console.log(chalk.yellow(`\n⚠️ Warning: ${result.stateWarning}`));
193
- }
194
-
195
- if (result.valid) {
196
- console.log(chalk.green('\n✓ VALIDATION PASSED'));
197
- console.log(chalk.green(' All required outputs are present.'));
198
- console.log(chalk.green(` Safe to proceed to ${result.phase.name}\n`));
199
-
200
- if (options.verbose) {
201
- console.log(chalk.gray('Required outputs found:'));
202
- result.phase.requiredOutputs.forEach(output => {
203
- console.log(chalk.gray(` ✓ ${output}`));
204
- });
205
- console.log('');
206
- }
207
- } else {
208
- console.log(chalk.red('\n✗ VALIDATION FAILED'));
209
-
210
- if (result.error) {
211
- console.log(chalk.red(` Error: ${result.error}\n`));
212
-
213
- if (result.suggestion) {
214
- console.log(chalk.yellow(` Suggestion: ${result.suggestion}\n`));
215
- }
216
-
217
- if (result.validPhases) {
218
- console.log(chalk.yellow('Valid phases:'));
219
- result.validPhases.forEach(p => {
220
- const def = PHASES[p];
221
- console.log(chalk.gray(` - ${p}: ${def.name}${def.optional ? ' (optional)' : ''}`));
222
- });
223
- }
224
- } else {
225
- console.log(chalk.red(' Missing required outputs:'));
226
- result.missingOutputs.forEach(output => {
227
- console.log(chalk.gray(` - ${output}`));
228
- });
229
-
230
- console.log(chalk.yellow(`\n Action required:`));
231
- console.log(chalk.yellow(` Complete the missing outputs before advancing to ${result.phase.name}`));
232
- }
233
- console.log('');
234
- process.exit(1);
235
- }
236
- }
237
-
238
- export { PHASES, validatePhase };