@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,188 +0,0 @@
1
- /**
2
- * @fileoverview Wizard Questions - Defines interactive wizard questions
3
- * @module morph-spec/ui/wizard-questions
4
- */
5
-
6
- /**
7
- * Get wizard questions for interactive mode
8
- * @returns {Array} Inquirer questions
9
- */
10
- export function getWizardQuestions() {
11
- return [
12
- {
13
- type: 'input',
14
- name: 'name',
15
- message: '1/7 Project name:',
16
- default: process.cwd().split(/[/\\]/).pop(),
17
- validate: (input) => {
18
- if (!input || input.trim().length === 0) {
19
- return 'Project name is required';
20
- }
21
- return true;
22
- }
23
- },
24
- {
25
- type: 'input',
26
- name: 'description',
27
- message: '2/7 Project description (1-2 sentences):',
28
- validate: (input) => {
29
- if (!input || input.trim().length < 10) {
30
- return 'Description must be at least 10 characters';
31
- }
32
- return true;
33
- }
34
- },
35
- {
36
- type: 'list',
37
- name: 'type',
38
- message: '3/7 Project type:',
39
- choices: [
40
- { name: 'Blazor Server (.NET)', value: 'blazor-server' },
41
- { name: 'Next.js (React)', value: 'nextjs' },
42
- { name: '.NET Web API', value: 'dotnet-api' },
43
- { name: 'CLI Tool', value: 'cli-tool' },
44
- { name: 'Monorepo (multiple projects)', value: 'monorepo' },
45
- { name: 'Other', value: 'other' }
46
- ]
47
- },
48
- {
49
- type: 'list',
50
- name: 'frontend',
51
- message: '4/7 Frontend technology:',
52
- choices: [
53
- { name: 'Blazor Server', value: 'blazor' },
54
- { name: 'Next.js', value: 'nextjs' },
55
- { name: 'React', value: 'react' },
56
- { name: 'Vue.js', value: 'vue' },
57
- { name: 'Angular', value: 'angular' },
58
- { name: 'None (backend-only)', value: null }
59
- ],
60
- when: (answers) => answers.type !== 'cli-tool' && answers.type !== 'dotnet-api'
61
- },
62
- {
63
- type: 'list',
64
- name: 'backend',
65
- message: '5/7 Backend technology:',
66
- choices: [
67
- { name: '.NET 10', value: 'dotnet-10' },
68
- { name: '.NET 9', value: 'dotnet-9' },
69
- { name: '.NET 8', value: 'dotnet-8' },
70
- { name: 'Node.js', value: 'nodejs' },
71
- { name: 'Other', value: 'other' }
72
- ],
73
- default: 'dotnet-10'
74
- },
75
- {
76
- type: 'list',
77
- name: 'database',
78
- message: '6/7 Database:',
79
- choices: [
80
- { name: 'Azure SQL Database', value: 'azure-sql' },
81
- { name: 'PostgreSQL', value: 'postgresql' },
82
- { name: 'Cosmos DB', value: 'cosmosdb' },
83
- { name: 'MongoDB', value: 'mongodb' },
84
- { name: 'SQLite', value: 'sqlite' },
85
- { name: 'Supabase (PostgreSQL)', value: 'supabase' },
86
- { name: 'None (no database)', value: null }
87
- ]
88
- },
89
- {
90
- type: 'confirm',
91
- name: 'hasAzure',
92
- message: '7a/7 Uses Azure infrastructure?',
93
- default: false
94
- },
95
- {
96
- type: 'confirm',
97
- name: 'hasDocker',
98
- message: '7b/7 Uses Docker containerization?',
99
- default: true
100
- }
101
- ];
102
- }
103
-
104
- /**
105
- * Map wizard answers to ProjectConfig
106
- * @param {Object} answers - Wizard answers from inquirer
107
- * @returns {ProjectConfig} Mapped project config
108
- */
109
- export function mapAnswersToConfig(answers) {
110
- // Parse backend tech and version
111
- const backendParts = answers.backend.split('-');
112
- const backendTech = backendParts[0] === 'dotnet' ? '.NET' :
113
- backendParts[0] === 'nodejs' ? 'Node.js' :
114
- answers.backend;
115
- const backendVersion = backendParts[1] || 'latest';
116
-
117
- // Map frontend
118
- let frontend = null;
119
- if (answers.frontend) {
120
- const frontendMap = {
121
- 'blazor': { tech: 'Blazor', version: backendVersion, details: 'Blazor Server' },
122
- 'nextjs': { tech: 'Next.js', version: '15', details: 'App Router' },
123
- 'react': { tech: 'React', version: '18', details: null },
124
- 'vue': { tech: 'Vue.js', version: '3', details: null },
125
- 'angular': { tech: 'Angular', version: '17', details: null }
126
- };
127
- frontend = frontendMap[answers.frontend] || null;
128
- }
129
-
130
- // Map database
131
- let database = null;
132
- if (answers.database) {
133
- const databaseMap = {
134
- 'azure-sql': { tech: 'Azure SQL', version: 'latest', details: 'Managed SQL Database' },
135
- 'postgresql': { tech: 'PostgreSQL', version: '16', details: null },
136
- 'cosmosdb': { tech: 'Cosmos DB', version: 'latest', details: 'NoSQL' },
137
- 'mongodb': { tech: 'MongoDB', version: '7', details: null },
138
- 'sqlite': { tech: 'SQLite', version: '3', details: null },
139
- 'supabase': { tech: 'PostgreSQL', version: '16', details: 'Managed by Supabase' }
140
- };
141
- database = databaseMap[answers.database] || null;
142
- }
143
-
144
- // Infer architecture from project type
145
- const architectureMap = {
146
- 'blazor-server': 'clean-architecture',
147
- 'nextjs': 'layered',
148
- 'dotnet-api': 'clean-architecture',
149
- 'cli-tool': 'monolith',
150
- 'monorepo': 'microservices',
151
- 'other': 'layered'
152
- };
153
-
154
- const architecture = architectureMap[answers.type] || 'layered';
155
-
156
- // Infer hosting
157
- let hosting = null;
158
- if (answers.hasAzure) {
159
- hosting = 'Azure';
160
- } else if (answers.hasDocker) {
161
- hosting = 'Docker';
162
- }
163
-
164
- return {
165
- name: answers.name,
166
- description: answers.description,
167
- type: answers.type,
168
- stack: {
169
- frontend,
170
- backend: {
171
- tech: backendTech,
172
- version: backendVersion,
173
- details: null
174
- },
175
- database,
176
- hosting
177
- },
178
- architecture,
179
- projectStructure: 'User-specified configuration via interactive wizard',
180
- conventions: 'Standard conventions for ' + backendTech,
181
- repository: null,
182
- hasAzure: answers.hasAzure,
183
- hasDocker: answers.hasDocker,
184
- hasDevOps: false,
185
- confidence: 100, // User input is 100% confident
186
- warnings: ['Configuration was manually entered, not auto-detected']
187
- };
188
- }
@@ -1,70 +0,0 @@
1
- /**
2
- * Unified color utilities for CLI output
3
- *
4
- * Replaces manual ANSI codes with consistent chalk usage.
5
- * Standardizes color handling across the codebase.
6
- */
7
-
8
- import chalk from 'chalk';
9
-
10
- // Re-export chalk for direct usage
11
- export { chalk };
12
-
13
- /**
14
- * Predefined color functions for common use cases
15
- */
16
- export const colors = {
17
- error: chalk.red,
18
- success: chalk.green,
19
- warning: chalk.yellow,
20
- info: chalk.blue,
21
- dim: chalk.gray,
22
- bold: chalk.bold,
23
- highlight: chalk.cyan,
24
- };
25
-
26
- /**
27
- * Status indicators with colors
28
- */
29
- export const status = {
30
- success: chalk.green('✓'),
31
- error: chalk.red('✗'),
32
- warning: chalk.yellow('⚠'),
33
- info: chalk.blue('ℹ'),
34
- };
35
-
36
- /**
37
- * Format a success message
38
- * @param {string} message - Message to format
39
- * @returns {string} Formatted message
40
- */
41
- export function formatSuccess(message) {
42
- return `${status.success} ${chalk.green(message)}`;
43
- }
44
-
45
- /**
46
- * Format an error message
47
- * @param {string} message - Message to format
48
- * @returns {string} Formatted message
49
- */
50
- export function formatError(message) {
51
- return `${status.error} ${chalk.red(message)}`;
52
- }
53
-
54
- /**
55
- * Format a warning message
56
- * @param {string} message - Message to format
57
- * @returns {string} Formatted message
58
- */
59
- export function formatWarning(message) {
60
- return `${status.warning} ${chalk.yellow(message)}`;
61
- }
62
-
63
- /**
64
- * Format an info message
65
- * @param {string} message - Message to format
66
- * @returns {string} Formatted message
67
- */
68
- export function formatInfo(message) {
69
- return `${status.info} ${chalk.blue(message)}`;
70
- }
@@ -1,97 +0,0 @@
1
- /**
2
- * Process Handler - Testable Exit Strategy
3
- *
4
- * Replaces direct process.exit() calls with a mockable handler.
5
- * Makes the codebase testable by allowing exit behavior to be intercepted.
6
- *
7
- * @module process-handler
8
- */
9
-
10
- import chalk from 'chalk';
11
-
12
- /**
13
- * Process Handler Class
14
- *
15
- * Provides testable process exit functionality.
16
- */
17
- export class ProcessHandler {
18
- /**
19
- * @param {Function} exitFn - Exit function (defaults to process.exit)
20
- */
21
- constructor(exitFn = process.exit.bind(process)) {
22
- this.exitFn = exitFn;
23
- }
24
-
25
- /**
26
- * Exit the process with optional message
27
- *
28
- * @param {number} code - Exit code (0 = success, non-zero = error)
29
- * @param {string} [message] - Optional message to display
30
- */
31
- exit(code = 0, message = null) {
32
- if (message) {
33
- if (code === 0) {
34
- console.log(message);
35
- } else {
36
- console.error(message);
37
- }
38
- }
39
- this.exitFn(code);
40
- }
41
-
42
- /**
43
- * Exit with error message (code 1)
44
- *
45
- * @param {string} message - Error message
46
- * @param {number} [code=1] - Error code
47
- */
48
- exitWithError(message, code = 1) {
49
- this.exit(code, chalk.red(message));
50
- }
51
-
52
- /**
53
- * Exit with success message (code 0)
54
- *
55
- * @param {string} message - Success message
56
- */
57
- exitWithSuccess(message) {
58
- this.exit(0, chalk.green(message));
59
- }
60
-
61
- /**
62
- * Exit with warning message (code 0, but highlighted)
63
- *
64
- * @param {string} message - Warning message
65
- */
66
- exitWithWarning(message) {
67
- this.exit(0, chalk.yellow(message));
68
- }
69
- }
70
-
71
- // Default instance for general use
72
- export const processHandler = new ProcessHandler();
73
-
74
- /**
75
- * Create a test handler for unit tests
76
- *
77
- * @returns {{handler: ProcessHandler, getExitCode: Function, getExited: Function}}
78
- */
79
- export function createTestHandler() {
80
- let exitCode = null;
81
- let exited = false;
82
-
83
- const handler = new ProcessHandler((code) => {
84
- exitCode = code;
85
- exited = true;
86
- });
87
-
88
- return {
89
- handler,
90
- getExitCode: () => exitCode,
91
- getExited: () => exited,
92
- reset: () => {
93
- exitCode = null;
94
- exited = false;
95
- },
96
- };
97
- }
@@ -1,86 +0,0 @@
1
- /**
2
- * @fileoverview FileWriter - Saves generated configs to filesystem
3
- * @module morph-spec/writer/file-writer
4
- */
5
-
6
- import { writeFile, mkdir, access } from 'fs/promises';
7
- import { join, dirname } from 'path';
8
- import chalk from 'chalk';
9
-
10
- /**
11
- * @typedef {import('../types/index.js').GeneratedConfigs} GeneratedConfigs
12
- */
13
-
14
- /**
15
- * FileWriter - Saves configuration files to .morph/ directory
16
- * @class
17
- */
18
- export class FileWriter {
19
- /**
20
- * Save generated configs to filesystem
21
- * @param {string} cwd - Current working directory
22
- * @param {GeneratedConfigs} configs - Configs to save
23
- * @returns {Promise<void>}
24
- */
25
- async save(cwd, configs) {
26
- const morphDir = join(cwd, '.morph');
27
- const configDir = join(morphDir, 'config');
28
-
29
- // Ensure directories exist
30
- await this.ensureDirectoryExists(morphDir);
31
- await this.ensureDirectoryExists(configDir);
32
-
33
- // Write files
34
- const projectMdPath = join(morphDir, 'project.md');
35
- const configJsonPath = join(configDir, 'config.json');
36
-
37
- await Promise.all([
38
- this.writeProjectMd(projectMdPath, configs.projectMd),
39
- this.writeConfigJson(configJsonPath, configs.configJson)
40
- ]);
41
-
42
- // Display success message
43
- console.log(chalk.bold.green('\n✅ Configuration files saved:\n'));
44
- console.log(chalk.cyan(` 📄 ${projectMdPath}`));
45
- console.log(chalk.cyan(` ⚙️ ${configJsonPath}`));
46
- console.log();
47
- }
48
-
49
- /**
50
- * Write project.md file
51
- * @param {string} filepath - File path
52
- * @param {string} content - File content
53
- * @returns {Promise<void>}
54
- */
55
- async writeProjectMd(filepath, content) {
56
- await writeFile(filepath, content, 'utf-8');
57
- }
58
-
59
- /**
60
- * Write config.json file (with pretty formatting)
61
- * @param {string} filepath - File path
62
- * @param {string} content - File content (JSON string)
63
- * @returns {Promise<void>}
64
- */
65
- async writeConfigJson(filepath, content) {
66
- // Parse and re-stringify with pretty formatting
67
- const parsed = JSON.parse(content);
68
- const formatted = JSON.stringify(parsed, null, 2);
69
-
70
- await writeFile(filepath, formatted, 'utf-8');
71
- }
72
-
73
- /**
74
- * Ensure directory exists (create if not)
75
- * @param {string} dirPath - Directory path
76
- * @returns {Promise<void>}
77
- */
78
- async ensureDirectoryExists(dirPath) {
79
- try {
80
- await access(dirPath);
81
- } catch (error) {
82
- // Directory doesn't exist, create it
83
- await mkdir(dirPath, { recursive: true });
84
- }
85
- }
86
- }