@polymorphism-tech/morph-spec 2.3.0 → 3.0.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 (166) hide show
  1. package/CLAUDE.md +446 -1730
  2. package/README.md +515 -516
  3. package/bin/morph-spec.js +366 -294
  4. package/bin/task-manager.js +429 -368
  5. package/bin/validate.js +369 -268
  6. package/content/.claude/commands/morph-apply.md +221 -158
  7. package/content/.claude/commands/morph-deploy.md +529 -0
  8. package/content/.claude/commands/morph-preflight.md +227 -0
  9. package/content/.claude/commands/morph-proposal.md +122 -101
  10. package/content/.claude/commands/morph-status.md +86 -86
  11. package/content/.claude/commands/morph-troubleshoot.md +122 -0
  12. package/content/.claude/skills/infra/azure-deploy-specialist.md +699 -0
  13. package/content/.claude/skills/level-0-meta/README.md +7 -0
  14. package/content/.claude/skills/level-0-meta/code-review.md +226 -0
  15. package/content/.claude/skills/level-0-meta/morph-checklist.md +117 -0
  16. package/content/.claude/skills/level-0-meta/simulation-checklist.md +77 -0
  17. package/content/.claude/skills/level-1-workflows/README.md +7 -0
  18. package/content/.claude/skills/level-1-workflows/morph-replicate.md +213 -0
  19. package/content/.claude/{commands/morph-clarify.md → skills/level-1-workflows/phase-clarify.md} +131 -184
  20. package/content/.claude/{commands/morph-design.md → skills/level-1-workflows/phase-design.md} +213 -275
  21. package/content/.claude/skills/level-1-workflows/phase-setup.md +106 -0
  22. package/content/.claude/skills/level-1-workflows/phase-tasks.md +164 -0
  23. package/content/.claude/{commands/morph-uiux.md → skills/level-1-workflows/phase-uiux.md} +169 -211
  24. package/content/.claude/skills/level-2-domains/README.md +14 -0
  25. package/content/.claude/skills/level-2-domains/ai-agents/ai-system-architect.md +192 -0
  26. package/content/.claude/skills/{specialists → level-2-domains/architecture}/po-pm-advisor.md +197 -197
  27. package/content/.claude/skills/level-2-domains/architecture/standards-architect.md +156 -0
  28. package/content/.claude/skills/level-2-domains/backend/dotnet-senior.md +287 -0
  29. package/content/.claude/skills/level-2-domains/backend/ef-modeler.md +113 -0
  30. package/content/.claude/skills/level-2-domains/backend/hangfire-orchestrator.md +126 -0
  31. package/content/.claude/skills/level-2-domains/backend/ms-agent-expert.md +109 -0
  32. package/content/.claude/skills/level-2-domains/frontend/blazor-builder.md +210 -0
  33. package/content/.claude/skills/level-2-domains/frontend/nextjs-expert.md +154 -0
  34. package/content/.claude/skills/level-2-domains/frontend/ui-ux-designer.md +191 -0
  35. package/content/.claude/skills/{specialists → level-2-domains/infrastructure}/azure-architect.md +142 -142
  36. package/content/.claude/skills/level-2-domains/infrastructure/bicep-architect.md +126 -0
  37. package/content/.claude/skills/level-2-domains/infrastructure/container-specialist.md +131 -0
  38. package/content/.claude/skills/level-2-domains/infrastructure/devops-engineer.md +119 -0
  39. package/content/.claude/skills/level-2-domains/integrations/asaas-financial.md +130 -0
  40. package/content/.claude/skills/level-2-domains/integrations/azure-identity.md +142 -0
  41. package/content/.claude/skills/level-2-domains/integrations/clerk-auth.md +108 -0
  42. package/content/.claude/skills/level-2-domains/integrations/resend-email.md +119 -0
  43. package/content/.claude/skills/level-2-domains/quality/code-analyzer.md +235 -0
  44. package/content/.claude/skills/level-2-domains/quality/testing-specialist.md +126 -0
  45. package/content/.claude/skills/level-3-technologies/README.md +7 -0
  46. package/content/.claude/skills/level-4-patterns/README.md +7 -0
  47. package/content/.claude/skills/specialists/prompt-engineer.md +189 -0
  48. package/content/.claude/skills/specialists/seo-growth-hacker.md +320 -0
  49. package/content/.morph/config/agents.json +762 -242
  50. package/content/.morph/config/config.template.json +122 -108
  51. package/content/.morph/docs/workflows/design-impl.md +37 -0
  52. package/content/.morph/docs/workflows/enforcement-pipeline.md +668 -0
  53. package/content/.morph/docs/workflows/fast-track.md +29 -0
  54. package/content/.morph/docs/workflows/full-morph.md +76 -0
  55. package/content/.morph/docs/workflows/standard.md +44 -0
  56. package/content/.morph/docs/workflows/ui-refresh.md +39 -0
  57. package/content/.morph/examples/scheduled-reports/decisions.md +158 -0
  58. package/content/.morph/examples/scheduled-reports/proposal.md +95 -0
  59. package/content/.morph/examples/scheduled-reports/spec.md +267 -0
  60. package/content/.morph/hooks/README.md +348 -239
  61. package/content/.morph/hooks/pre-commit-agents.sh +24 -24
  62. package/content/.morph/hooks/task-completed.js +73 -0
  63. package/content/.morph/hooks/teammate-idle.js +68 -0
  64. package/content/.morph/schemas/tasks.schema.json +220 -0
  65. package/content/.morph/standards/agent-framework-blazor-ui.md +359 -0
  66. package/content/.morph/standards/agent-framework-production.md +410 -0
  67. package/content/.morph/standards/agent-framework-setup.md +413 -453
  68. package/content/.morph/standards/agent-framework-workflows.md +349 -0
  69. package/content/.morph/standards/agent-teams-workflow.md +474 -0
  70. package/content/.morph/standards/architecture.md +325 -325
  71. package/content/.morph/standards/azure.md +605 -379
  72. package/content/.morph/standards/dotnet10-migration.md +520 -494
  73. package/content/.morph/templates/CONTEXT-FEATURE.md +276 -0
  74. package/content/.morph/templates/CONTEXT.md +170 -0
  75. package/content/.morph/templates/agent.cs +163 -172
  76. package/content/.morph/templates/clarify-questions.md +159 -0
  77. package/content/.morph/templates/contracts/Commands.cs +74 -0
  78. package/content/.morph/templates/contracts/Entities.cs +25 -0
  79. package/content/.morph/templates/contracts/Queries.cs +74 -0
  80. package/content/.morph/templates/contracts/README.md +74 -0
  81. package/content/.morph/templates/decisions.md +123 -106
  82. package/content/.morph/templates/infra/azure-pipelines-deploy.yml +480 -0
  83. package/content/.morph/templates/infra/deploy-checklist.md +426 -0
  84. package/content/.morph/templates/proposal.md +141 -155
  85. package/content/.morph/templates/recap.md +94 -105
  86. package/content/.morph/templates/simulation.md +353 -0
  87. package/content/.morph/templates/spec.md +149 -148
  88. package/content/.morph/templates/state.template.json +222 -222
  89. package/content/.morph/templates/tasks.md +257 -235
  90. package/content/.morph/templates/ui-components.md +362 -276
  91. package/content/CLAUDE.md +150 -442
  92. package/detectors/structure-detector.js +245 -250
  93. package/docs/README.md +144 -149
  94. package/docs/getting-started.md +301 -302
  95. package/docs/installation.md +361 -361
  96. package/docs/validation-checklist.md +265 -266
  97. package/package.json +80 -80
  98. package/src/commands/advance-phase.js +266 -0
  99. package/src/commands/analyze-blazor-concurrency.js +193 -0
  100. package/src/commands/deploy.js +780 -0
  101. package/src/commands/detect-agents.js +167 -0
  102. package/src/commands/doctor.js +356 -280
  103. package/src/commands/generate-context.js +40 -0
  104. package/src/commands/init.js +258 -245
  105. package/src/commands/lint-fluent.js +352 -0
  106. package/src/commands/rollback-phase.js +185 -0
  107. package/src/commands/session-summary.js +291 -0
  108. package/src/commands/task.js +78 -75
  109. package/src/commands/troubleshoot.js +222 -0
  110. package/src/commands/update.js +192 -159
  111. package/src/commands/validate-blazor-state.js +210 -0
  112. package/src/commands/validate-blazor.js +156 -0
  113. package/src/commands/validate-css.js +84 -0
  114. package/src/commands/validate-phase.js +221 -0
  115. package/src/lib/blazor-concurrency-analyzer.js +288 -0
  116. package/src/lib/blazor-state-validator.js +291 -0
  117. package/src/lib/blazor-validator.js +374 -0
  118. package/src/lib/complexity-analyzer.js +441 -292
  119. package/src/lib/context-generator.js +513 -0
  120. package/src/lib/continuous-validator.js +421 -440
  121. package/src/lib/css-validator.js +352 -0
  122. package/src/lib/decision-constraint-loader.js +109 -0
  123. package/src/lib/design-system-detector.js +187 -0
  124. package/src/lib/design-system-scaffolder.js +299 -0
  125. package/src/lib/hook-executor.js +256 -0
  126. package/src/lib/recap-generator.js +205 -0
  127. package/src/lib/spec-validator.js +258 -0
  128. package/src/lib/standards-context-injector.js +287 -0
  129. package/src/lib/state-manager.js +397 -340
  130. package/src/lib/team-orchestrator.js +322 -0
  131. package/src/lib/troubleshoot-grep.js +194 -0
  132. package/src/lib/troubleshoot-index.js +144 -0
  133. package/src/lib/validation-runner.js +283 -0
  134. package/src/lib/validators/contract-compliance-validator.js +273 -0
  135. package/src/lib/validators/design-system-validator.js +231 -0
  136. package/src/utils/file-copier.js +187 -139
  137. package/content/.claude/commands/morph-costs.md +0 -206
  138. package/content/.claude/commands/morph-setup.md +0 -100
  139. package/content/.claude/commands/morph-tasks.md +0 -319
  140. package/content/.claude/skills/infra/bicep-architect.md +0 -419
  141. package/content/.claude/skills/infra/container-specialist.md +0 -437
  142. package/content/.claude/skills/infra/devops-engineer.md +0 -405
  143. package/content/.claude/skills/integrations/asaas-financial.md +0 -333
  144. package/content/.claude/skills/integrations/azure-identity.md +0 -309
  145. package/content/.claude/skills/integrations/clerk-auth.md +0 -290
  146. package/content/.claude/skills/specialists/ai-system-architect.md +0 -604
  147. package/content/.claude/skills/specialists/cost-guardian.md +0 -110
  148. package/content/.claude/skills/specialists/ef-modeler.md +0 -211
  149. package/content/.claude/skills/specialists/hangfire-orchestrator.md +0 -255
  150. package/content/.claude/skills/specialists/ms-agent-expert.md +0 -263
  151. package/content/.claude/skills/specialists/standards-architect.md +0 -78
  152. package/content/.claude/skills/specialists/ui-ux-designer.md +0 -1100
  153. package/content/.claude/skills/stacks/dotnet-blazor.md +0 -606
  154. package/content/.claude/skills/stacks/dotnet-nextjs.md +0 -402
  155. package/content/.claude/skills/stacks/shopify.md +0 -445
  156. package/content/.morph/config/azure-pricing.json +0 -70
  157. package/content/.morph/config/azure-pricing.schema.json +0 -50
  158. package/content/.morph/hooks/pre-commit-costs.sh +0 -91
  159. package/docs/api/cost-calculator.js.html +0 -513
  160. package/docs/api/design-system-generator.js.html +0 -382
  161. package/docs/api/global.html +0 -5263
  162. package/docs/api/index.html +0 -96
  163. package/docs/api/state-manager.js.html +0 -423
  164. package/src/commands/cost.js +0 -181
  165. package/src/commands/update-pricing.js +0 -206
  166. package/src/lib/cost-calculator.js +0 -429
package/bin/validate.js CHANGED
@@ -1,268 +1,369 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Validation CLI
5
- *
6
- * Runs all validators (package, architecture, contrast) on the project.
7
- * Part of Sprint 4: Continuous Validation + Learning System
8
- *
9
- * Usage:
10
- * morph-spec validate [options]
11
- * morph-spec validate packages
12
- * morph-spec validate architecture
13
- * morph-spec validate contrast
14
- * morph-spec validate all
15
- *
16
- * MORPH-SPEC 3.0
17
- */
18
-
19
- import chalk from 'chalk';
20
- import { validatePackages } from '../src/lib/validators/package-validator.js';
21
- import { validateArchitecture } from '../src/lib/validators/architecture-validator.js';
22
- import { validateContrast } from '../src/lib/validators/ui-contrast-validator.js';
23
- import { LearningSystem } from '../src/lib/learning-system.js';
24
-
25
- const VALIDATORS = {
26
- packages: {
27
- name: 'Package Compatibility',
28
- description: 'Validates NuGet package versions against .NET compatibility matrix',
29
- run: validatePackages
30
- },
31
- architecture: {
32
- name: 'Architecture Patterns',
33
- description: 'Detects DI anti-patterns and lifecycle issues in Blazor',
34
- run: validateArchitecture
35
- },
36
- contrast: {
37
- name: 'UI Contrast (WCAG)',
38
- description: 'Validates color contrast ratios for accessibility',
39
- run: validateContrast
40
- }
41
- };
42
-
43
- /**
44
- * Main validation command
45
- */
46
- export async function validateCommand(args = []) {
47
- const validatorName = args[0] || 'all';
48
- const options = parseOptions(args);
49
-
50
- console.log(chalk.bold.cyan('\n🔍 MORPH-SPEC Validator\n'));
51
-
52
- if (validatorName === 'all') {
53
- await runAllValidators(options);
54
- } else if (VALIDATORS[validatorName]) {
55
- await runValidator(validatorName, options);
56
- } else {
57
- console.error(chalk.red(`❌ Unknown validator: ${validatorName}`));
58
- console.log(chalk.gray('\nAvailable validators:'));
59
- for (const [name, validator] of Object.entries(VALIDATORS)) {
60
- console.log(chalk.gray(` - ${name}: ${validator.description}`));
61
- }
62
- console.log(chalk.gray(' - all: Run all validators'));
63
- process.exit(1);
64
- }
65
-
66
- // Show learning insights if --insights flag
67
- if (options.insights) {
68
- await showLearningInsights(options);
69
- }
70
- }
71
-
72
- /**
73
- * Run all validators
74
- */
75
- async function runAllValidators(options) {
76
- const results = {};
77
- let totalErrors = 0;
78
- let totalWarnings = 0;
79
-
80
- console.log(chalk.gray('Running all validators...\n'));
81
-
82
- for (const [name, validator] of Object.entries(VALIDATORS)) {
83
- console.log(chalk.cyan(`\n▸ ${validator.name}`));
84
- console.log(chalk.gray(` ${validator.description}\n`));
85
-
86
- try {
87
- const result = await validator.run('.', {
88
- verbose: options.verbose,
89
- autoFix: options.autoFix
90
- });
91
-
92
- results[name] = result;
93
-
94
- // Count errors/warnings
95
- if (result.errors !== undefined) {
96
- totalErrors += result.errors;
97
- totalWarnings += result.warnings || 0;
98
- } else if (result.results) {
99
- // Count issues in results array
100
- const issues = result.results.flatMap(r => r.issues || []);
101
- totalErrors += issues.filter(i => i.level === 'error').length;
102
- totalWarnings += issues.filter(i => i.level === 'warning').length;
103
- }
104
-
105
- } catch (error) {
106
- console.error(chalk.red(` ❌ Failed: ${error.message}`));
107
- results[name] = { status: 'error', error: error.message };
108
- }
109
- }
110
-
111
- // Summary
112
- console.log(chalk.bold.cyan('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
113
- console.log(chalk.bold('📊 Validation Summary\n'));
114
-
115
- if (totalErrors === 0 && totalWarnings === 0) {
116
- console.log(chalk.green('✅ All validations passed!'));
117
- } else {
118
- if (totalErrors > 0) {
119
- console.log(chalk.red(`❌ ${totalErrors} error(s) found`));
120
- }
121
- if (totalWarnings > 0) {
122
- console.log(chalk.yellow(`⚠️ ${totalWarnings} warning(s) found`));
123
- }
124
- }
125
-
126
- console.log('');
127
-
128
- // Exit with error code if errors found
129
- if (totalErrors > 0 && !options.noFail) {
130
- process.exit(1);
131
- }
132
- }
133
-
134
- /**
135
- * Run single validator
136
- */
137
- async function runValidator(name, options) {
138
- const validator = VALIDATORS[name];
139
-
140
- console.log(chalk.cyan(`▸ ${validator.name}`));
141
- console.log(chalk.gray(` ${validator.description}\n`));
142
-
143
- try {
144
- const result = await validator.run('.', {
145
- verbose: true, // Always verbose for single validator
146
- autoFix: options.autoFix,
147
- wcagLevel: options.wcagLevel
148
- });
149
-
150
- if (result.status === 'ok') {
151
- console.log(chalk.green('\n Validation passed!\n'));
152
- } else {
153
- console.log(chalk.yellow('\n⚠️ Validation completed with issues\n'));
154
-
155
- if (result.errors > 0 && !options.noFail) {
156
- process.exit(1);
157
- }
158
- }
159
-
160
- } catch (error) {
161
- console.error(chalk.red(`\n❌ Validation failed: ${error.message}\n`));
162
- if (!options.noFail) {
163
- process.exit(1);
164
- }
165
- }
166
- }
167
-
168
- /**
169
- * Show learning insights
170
- */
171
- async function showLearningInsights(options) {
172
- console.log(chalk.bold.cyan('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
173
-
174
- const learner = new LearningSystem('.');
175
- learner.formatInsights();
176
-
177
- if (options.verbose) {
178
- const suggestions = learner.getAllSuggestions();
179
- learner.formatSuggestions(suggestions);
180
- }
181
- }
182
-
183
- /**
184
- * Parse command-line options
185
- */
186
- function parseOptions(args) {
187
- const options = {
188
- verbose: false,
189
- autoFix: false,
190
- noFail: false,
191
- insights: false,
192
- wcagLevel: 'AA'
193
- };
194
-
195
- for (const arg of args) {
196
- if (arg === '--verbose' || arg === '-v') {
197
- options.verbose = true;
198
- } else if (arg === '--auto-fix' || arg === '--fix') {
199
- options.autoFix = true;
200
- } else if (arg === '--no-fail') {
201
- options.noFail = true;
202
- } else if (arg === '--insights' || arg === '-i') {
203
- options.insights = true;
204
- } else if (arg === '--wcag-aaa') {
205
- options.wcagLevel = 'AAA';
206
- }
207
- }
208
-
209
- return options;
210
- }
211
-
212
- /**
213
- * Show help
214
- */
215
- export function showValidateHelp() {
216
- console.log(`
217
- ${chalk.bold.cyan('morph-spec validate')} - Run project validations
218
-
219
- ${chalk.bold('USAGE')}
220
- morph-spec validate [validator] [options]
221
-
222
- ${chalk.bold('VALIDATORS')}
223
- all Run all validators (default)
224
- packages Validate NuGet package compatibility (.NET 10)
225
- architecture Validate architecture patterns (DI, lifecycle)
226
- contrast Validate UI contrast ratios (WCAG 2.1)
227
-
228
- ${chalk.bold('OPTIONS')}
229
- --verbose, -v Show detailed output
230
- --auto-fix, --fix Auto-fix issues where possible
231
- --no-fail Don't exit with error code
232
- --insights, -i Show learning insights
233
- --wcag-aaa Use WCAG AAA standard (stricter)
234
-
235
- ${chalk.bold('EXAMPLES')}
236
- morph-spec validate # Run all validators
237
- morph-spec validate packages --fix # Validate packages and auto-fix
238
- morph-spec validate architecture -v # Verbose architecture validation
239
- morph-spec validate contrast --wcag-aaa # Stricter contrast validation
240
- morph-spec validate all --insights # All validators + AI insights
241
-
242
- ${chalk.bold('EXIT CODES')}
243
- 0 All validations passed
244
- 1 Validation errors found (unless --no-fail)
245
-
246
- ${chalk.bold('INTEGRATION')}
247
- Add to pre-commit hook:
248
- morph-spec validate --no-fail
249
-
250
- CI/CD pipeline:
251
- morph-spec validate || exit 1
252
- `);
253
- }
254
-
255
- // Run if called directly
256
- if (import.meta.url === `file://${process.argv[1]}`) {
257
- const args = process.argv.slice(2);
258
-
259
- if (args.includes('--help') || args.includes('-h')) {
260
- showValidateHelp();
261
- process.exit(0);
262
- }
263
-
264
- validateCommand(args).catch(error => {
265
- console.error(chalk.red(`\n❌ Error: ${error.message}\n`));
266
- process.exit(1);
267
- });
268
- }
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Validation CLI
5
+ *
6
+ * Runs all validators (package, architecture, contrast) on the project.
7
+ * Part of Sprint 4: Continuous Validation + Learning System
8
+ *
9
+ * Usage:
10
+ * morph-spec validate [options]
11
+ * morph-spec validate packages
12
+ * morph-spec validate architecture
13
+ * morph-spec validate contrast
14
+ * morph-spec validate all
15
+ *
16
+ * MORPH-SPEC 3.0
17
+ */
18
+
19
+ import chalk from 'chalk';
20
+ import { validatePackages } from '../src/lib/validators/package-validator.js';
21
+ import { validateArchitecture } from '../src/lib/validators/architecture-validator.js';
22
+ import { validateContrast } from '../src/lib/validators/ui-contrast-validator.js';
23
+ import { LearningSystem } from '../src/lib/learning-system.js';
24
+
25
+ const VALIDATORS = {
26
+ packages: {
27
+ name: 'Package Compatibility',
28
+ description: 'Validates NuGet package versions against .NET compatibility matrix',
29
+ run: validatePackages
30
+ },
31
+ architecture: {
32
+ name: 'Architecture Patterns',
33
+ description: 'Detects DI anti-patterns and lifecycle issues in Blazor',
34
+ run: validateArchitecture
35
+ },
36
+ contrast: {
37
+ name: 'UI Contrast (WCAG)',
38
+ description: 'Validates color contrast ratios for accessibility',
39
+ run: validateContrast
40
+ },
41
+ 'spec-tasks': {
42
+ name: 'Spec vs Tasks Coverage',
43
+ description: 'Validates that tasks.json covers all requirements from spec.md',
44
+ run: validateSpecVsTasks
45
+ }
46
+ };
47
+
48
+ /**
49
+ * Validate spec.md requirements are covered by tasks
50
+ */
51
+ async function validateSpecVsTasks(projectPath, options = {}) {
52
+ const path = await import('path');
53
+ const fs = await import('fs');
54
+ const { loadState } = await import('../src/lib/state-manager.js');
55
+
56
+ const results = [];
57
+ let errors = 0;
58
+ let warnings = 0;
59
+
60
+ try {
61
+ const state = loadState(false);
62
+ if (!state || !state.features) {
63
+ return { status: 'ok', errors: 0, warnings: 0, message: 'No features to validate' };
64
+ }
65
+
66
+ for (const [featureName, feature] of Object.entries(state.features)) {
67
+ const outputsPath = path.join(projectPath, '.morph/project/outputs', featureName);
68
+ const specPath = path.join(outputsPath, 'spec.md');
69
+
70
+ if (!fs.existsSync(specPath)) {
71
+ continue; // No spec to validate
72
+ }
73
+
74
+ // Read spec.md and extract requirements
75
+ const specContent = fs.readFileSync(specPath, 'utf-8');
76
+
77
+ // Extract requirement patterns (## Requisitos, - [ ], numbered lists, etc.)
78
+ const requirementPatterns = [
79
+ /^#+\s*Requisitos?\s*$/gim,
80
+ /^-\s*\[.\]\s*(.+)$/gm,
81
+ /^\d+\.\s+(.+)$/gm
82
+ ];
83
+
84
+ const requirements = [];
85
+ for (const pattern of requirementPatterns) {
86
+ const matches = specContent.matchAll(pattern);
87
+ for (const match of matches) {
88
+ if (match[1]) {
89
+ requirements.push(match[1].trim());
90
+ }
91
+ }
92
+ }
93
+
94
+ // Check if feature has tasks
95
+ if (!feature.tasks || (Array.isArray(feature.tasks) && feature.tasks.length === 0)) {
96
+ if (requirements.length > 0) {
97
+ warnings++;
98
+ results.push({
99
+ feature: featureName,
100
+ level: 'warning',
101
+ message: `Spec has ${requirements.length} requirements but no tasks defined`
102
+ });
103
+ }
104
+ continue;
105
+ }
106
+
107
+ // Get task titles
108
+ const taskTitles = Array.isArray(feature.tasks)
109
+ ? feature.tasks.map(t => t.title?.toLowerCase() || '')
110
+ : [];
111
+
112
+ // Check each requirement has a matching task (fuzzy match)
113
+ for (const req of requirements.slice(0, 20)) { // Limit to first 20
114
+ const reqLower = req.toLowerCase();
115
+ const hasMatch = taskTitles.some(title =>
116
+ title.includes(reqLower.slice(0, 20)) ||
117
+ reqLower.includes(title.slice(0, 20))
118
+ );
119
+
120
+ if (!hasMatch && options.verbose) {
121
+ console.log(chalk.gray(` ? Requirement may not be covered: "${req.slice(0, 50)}..."`));
122
+ }
123
+ }
124
+
125
+ if (options.verbose) {
126
+ console.log(chalk.green(` ✓ ${featureName}: ${requirements.length} requirements, ${taskTitles.length} tasks`));
127
+ }
128
+ }
129
+
130
+ } catch (error) {
131
+ if (options.verbose) {
132
+ console.log(chalk.yellow(` ⚠ Could not validate: ${error.message}`));
133
+ }
134
+ }
135
+
136
+ return {
137
+ status: errors > 0 ? 'error' : warnings > 0 ? 'warning' : 'ok',
138
+ errors,
139
+ warnings,
140
+ results
141
+ };
142
+ }
143
+
144
+ /**
145
+ * Main validation command
146
+ */
147
+ export async function validateCommand(args = []) {
148
+ const validatorName = args[0] || 'all';
149
+ const options = parseOptions(args);
150
+
151
+ console.log(chalk.bold.cyan('\n🔍 MORPH-SPEC Validator\n'));
152
+
153
+ if (validatorName === 'all') {
154
+ await runAllValidators(options);
155
+ } else if (VALIDATORS[validatorName]) {
156
+ await runValidator(validatorName, options);
157
+ } else {
158
+ console.error(chalk.red(`❌ Unknown validator: ${validatorName}`));
159
+ console.log(chalk.gray('\nAvailable validators:'));
160
+ for (const [name, validator] of Object.entries(VALIDATORS)) {
161
+ console.log(chalk.gray(` - ${name}: ${validator.description}`));
162
+ }
163
+ console.log(chalk.gray(' - all: Run all validators'));
164
+ process.exit(1);
165
+ }
166
+
167
+ // Show learning insights if --insights flag
168
+ if (options.insights) {
169
+ await showLearningInsights(options);
170
+ }
171
+ }
172
+
173
+ /**
174
+ * Run all validators
175
+ */
176
+ async function runAllValidators(options) {
177
+ const results = {};
178
+ let totalErrors = 0;
179
+ let totalWarnings = 0;
180
+
181
+ console.log(chalk.gray('Running all validators...\n'));
182
+
183
+ for (const [name, validator] of Object.entries(VALIDATORS)) {
184
+ console.log(chalk.cyan(`\n▸ ${validator.name}`));
185
+ console.log(chalk.gray(` ${validator.description}\n`));
186
+
187
+ try {
188
+ const result = await validator.run('.', {
189
+ verbose: options.verbose,
190
+ autoFix: options.autoFix
191
+ });
192
+
193
+ results[name] = result;
194
+
195
+ // Count errors/warnings
196
+ if (result.errors !== undefined) {
197
+ totalErrors += result.errors;
198
+ totalWarnings += result.warnings || 0;
199
+ } else if (result.results) {
200
+ // Count issues in results array
201
+ const issues = result.results.flatMap(r => r.issues || []);
202
+ totalErrors += issues.filter(i => i.level === 'error').length;
203
+ totalWarnings += issues.filter(i => i.level === 'warning').length;
204
+ }
205
+
206
+ } catch (error) {
207
+ console.error(chalk.red(` ❌ Failed: ${error.message}`));
208
+ results[name] = { status: 'error', error: error.message };
209
+ }
210
+ }
211
+
212
+ // Summary
213
+ console.log(chalk.bold.cyan('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
214
+ console.log(chalk.bold('📊 Validation Summary\n'));
215
+
216
+ if (totalErrors === 0 && totalWarnings === 0) {
217
+ console.log(chalk.green(' All validations passed!'));
218
+ } else {
219
+ if (totalErrors > 0) {
220
+ console.log(chalk.red(`❌ ${totalErrors} error(s) found`));
221
+ }
222
+ if (totalWarnings > 0) {
223
+ console.log(chalk.yellow(`⚠️ ${totalWarnings} warning(s) found`));
224
+ }
225
+ }
226
+
227
+ console.log('');
228
+
229
+ // Exit with error code if errors found
230
+ if (totalErrors > 0 && !options.noFail) {
231
+ process.exit(1);
232
+ }
233
+ }
234
+
235
+ /**
236
+ * Run single validator
237
+ */
238
+ async function runValidator(name, options) {
239
+ const validator = VALIDATORS[name];
240
+
241
+ console.log(chalk.cyan(`▸ ${validator.name}`));
242
+ console.log(chalk.gray(` ${validator.description}\n`));
243
+
244
+ try {
245
+ const result = await validator.run('.', {
246
+ verbose: true, // Always verbose for single validator
247
+ autoFix: options.autoFix,
248
+ wcagLevel: options.wcagLevel
249
+ });
250
+
251
+ if (result.status === 'ok') {
252
+ console.log(chalk.green('\n✅ Validation passed!\n'));
253
+ } else {
254
+ console.log(chalk.yellow('\n⚠️ Validation completed with issues\n'));
255
+
256
+ if (result.errors > 0 && !options.noFail) {
257
+ process.exit(1);
258
+ }
259
+ }
260
+
261
+ } catch (error) {
262
+ console.error(chalk.red(`\n❌ Validation failed: ${error.message}\n`));
263
+ if (!options.noFail) {
264
+ process.exit(1);
265
+ }
266
+ }
267
+ }
268
+
269
+ /**
270
+ * Show learning insights
271
+ */
272
+ async function showLearningInsights(options) {
273
+ console.log(chalk.bold.cyan('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n'));
274
+
275
+ const learner = new LearningSystem('.');
276
+ learner.formatInsights();
277
+
278
+ if (options.verbose) {
279
+ const suggestions = learner.getAllSuggestions();
280
+ learner.formatSuggestions(suggestions);
281
+ }
282
+ }
283
+
284
+ /**
285
+ * Parse command-line options
286
+ */
287
+ function parseOptions(args) {
288
+ const options = {
289
+ verbose: false,
290
+ autoFix: false,
291
+ noFail: false,
292
+ insights: false,
293
+ wcagLevel: 'AA'
294
+ };
295
+
296
+ for (const arg of args) {
297
+ if (arg === '--verbose' || arg === '-v') {
298
+ options.verbose = true;
299
+ } else if (arg === '--auto-fix' || arg === '--fix') {
300
+ options.autoFix = true;
301
+ } else if (arg === '--no-fail') {
302
+ options.noFail = true;
303
+ } else if (arg === '--insights' || arg === '-i') {
304
+ options.insights = true;
305
+ } else if (arg === '--wcag-aaa') {
306
+ options.wcagLevel = 'AAA';
307
+ }
308
+ }
309
+
310
+ return options;
311
+ }
312
+
313
+ /**
314
+ * Show help
315
+ */
316
+ export function showValidateHelp() {
317
+ console.log(`
318
+ ${chalk.bold.cyan('morph-spec validate')} - Run project validations
319
+
320
+ ${chalk.bold('USAGE')}
321
+ morph-spec validate [validator] [options]
322
+
323
+ ${chalk.bold('VALIDATORS')}
324
+ all Run all validators (default)
325
+ packages Validate NuGet package compatibility (.NET 10)
326
+ architecture Validate architecture patterns (DI, lifecycle)
327
+ contrast Validate UI contrast ratios (WCAG 2.1)
328
+
329
+ ${chalk.bold('OPTIONS')}
330
+ --verbose, -v Show detailed output
331
+ --auto-fix, --fix Auto-fix issues where possible
332
+ --no-fail Don't exit with error code
333
+ --insights, -i Show learning insights
334
+ --wcag-aaa Use WCAG AAA standard (stricter)
335
+
336
+ ${chalk.bold('EXAMPLES')}
337
+ morph-spec validate # Run all validators
338
+ morph-spec validate packages --fix # Validate packages and auto-fix
339
+ morph-spec validate architecture -v # Verbose architecture validation
340
+ morph-spec validate contrast --wcag-aaa # Stricter contrast validation
341
+ morph-spec validate all --insights # All validators + AI insights
342
+
343
+ ${chalk.bold('EXIT CODES')}
344
+ 0 All validations passed
345
+ 1 Validation errors found (unless --no-fail)
346
+
347
+ ${chalk.bold('INTEGRATION')}
348
+ Add to pre-commit hook:
349
+ morph-spec validate --no-fail
350
+
351
+ CI/CD pipeline:
352
+ morph-spec validate || exit 1
353
+ `);
354
+ }
355
+
356
+ // Run if called directly
357
+ if (import.meta.url === `file://${process.argv[1]}`) {
358
+ const args = process.argv.slice(2);
359
+
360
+ if (args.includes('--help') || args.includes('-h')) {
361
+ showValidateHelp();
362
+ process.exit(0);
363
+ }
364
+
365
+ validateCommand(args).catch(error => {
366
+ console.error(chalk.red(`\n❌ Error: ${error.message}\n`));
367
+ process.exit(1);
368
+ });
369
+ }