@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
@@ -0,0 +1,156 @@
1
+ /**
2
+ * validate-blazor command
3
+ *
4
+ * Validates Fluent UI Blazor patterns and icons in Razor files.
5
+ *
6
+ * Usage:
7
+ * morph-spec validate-blazor [path]
8
+ * morph-spec validate-blazor src/Components --verbose
9
+ */
10
+
11
+ import { glob } from 'glob';
12
+ import { readFileSync, existsSync, statSync } from 'fs';
13
+ import { join, resolve } from 'path';
14
+ import chalk from 'chalk';
15
+ import ora from 'ora';
16
+
17
+ import {
18
+ validateBlazorFile,
19
+ formatIssues,
20
+ countIssues,
21
+ } from '../lib/blazor-validator.js';
22
+
23
+ /**
24
+ * Main command handler for validate-blazor.
25
+ *
26
+ * @param {string} [targetPath] - Path to validate (file or directory)
27
+ * @param {Object} options - Command options
28
+ * @param {boolean} [options.verbose] - Show detailed output
29
+ * @param {boolean} [options.fix] - Auto-fix issues where possible
30
+ */
31
+ export async function validateBlazorCommand(targetPath, options = {}) {
32
+ const { verbose = false } = options;
33
+
34
+ console.log('');
35
+ console.log(
36
+ chalk.cyan('\uD83D\uDD0D Validating Fluent UI Blazor patterns...')
37
+ );
38
+ console.log('');
39
+
40
+ // Determine target path
41
+ const basePath = targetPath ? resolve(targetPath) : process.cwd();
42
+
43
+ if (!existsSync(basePath)) {
44
+ console.log(chalk.red(`\u274C Path not found: ${basePath}`));
45
+ process.exit(1);
46
+ }
47
+
48
+ const spinner = ora('Scanning for Razor files...').start();
49
+
50
+ let files = [];
51
+
52
+ try {
53
+ const stats = statSync(basePath);
54
+
55
+ if (stats.isFile()) {
56
+ // Single file
57
+ if (
58
+ basePath.endsWith('.razor') ||
59
+ basePath.endsWith('.razor.cs') ||
60
+ basePath.endsWith('.cs')
61
+ ) {
62
+ files = [basePath];
63
+ } else {
64
+ spinner.fail('File must be .razor or .cs');
65
+ process.exit(1);
66
+ }
67
+ } else {
68
+ // Directory - find all Razor files
69
+ const pattern = join(basePath, '**/*.{razor,razor.cs}');
70
+ files = await glob(pattern, {
71
+ ignore: ['**/node_modules/**', '**/bin/**', '**/obj/**'],
72
+ windowsPathsNoEscape: true,
73
+ });
74
+ }
75
+
76
+ spinner.succeed(`Found ${files.length} Razor file(s)`);
77
+ } catch (error) {
78
+ spinner.fail(`Error scanning files: ${error.message}`);
79
+ process.exit(1);
80
+ }
81
+
82
+ if (files.length === 0) {
83
+ console.log(chalk.yellow('\n\u26A0\uFE0F No Razor files found to validate'));
84
+ return;
85
+ }
86
+
87
+ // Validate each file
88
+ const allIssues = [];
89
+ const fileResults = [];
90
+
91
+ for (const file of files) {
92
+ try {
93
+ const content = readFileSync(file, 'utf-8');
94
+ const issues = validateBlazorFile(content, file);
95
+
96
+ if (issues.length > 0) {
97
+ allIssues.push(...issues);
98
+ fileResults.push({ file, issues });
99
+ }
100
+ } catch (error) {
101
+ console.log(chalk.red(`\u274C Error reading ${file}: ${error.message}`));
102
+ }
103
+ }
104
+
105
+ // Output results
106
+ console.log('');
107
+
108
+ if (allIssues.length === 0) {
109
+ console.log(
110
+ chalk.green('\u2705 No issues found! All patterns look correct.')
111
+ );
112
+ console.log('');
113
+ return;
114
+ }
115
+
116
+ // Group and display issues
117
+ if (verbose) {
118
+ // Verbose: show all issues with details
119
+ fileResults.forEach(({ file, issues }) => {
120
+ console.log(chalk.white.bold(`\n${file}`));
121
+ console.log(chalk.gray('-'.repeat(60)));
122
+ console.log(formatIssues(issues));
123
+ });
124
+ } else {
125
+ // Compact: just list issues
126
+ allIssues.forEach((issue) => {
127
+ const icon = issue.type === 'error' ? '\u274C' : '\u26A0\uFE0F';
128
+ const location = issue.line ? `${issue.file}:${issue.line}` : issue.file;
129
+
130
+ console.log(`${icon} ${issue.message}`);
131
+ if (issue.suggestion) {
132
+ console.log(chalk.gray(` \u2192 ${issue.suggestion}`));
133
+ }
134
+ console.log(chalk.dim(` ${location}`));
135
+ console.log('');
136
+ });
137
+ }
138
+
139
+ // Summary
140
+ const { errors, warnings } = countIssues(allIssues);
141
+ const summaryColor = errors > 0 ? chalk.red : chalk.yellow;
142
+
143
+ console.log(chalk.gray('-'.repeat(60)));
144
+ console.log(
145
+ summaryColor(
146
+ `\n${files.length} arquivo(s) validado(s) | ${errors} erro(s) | ${warnings} warning(s)\n`
147
+ )
148
+ );
149
+
150
+ // Exit with error code if there are errors
151
+ if (errors > 0) {
152
+ process.exit(1);
153
+ }
154
+ }
155
+
156
+ export default validateBlazorCommand;
@@ -0,0 +1,84 @@
1
+ /**
2
+ * MORPH-SPEC validate-css Command
3
+ *
4
+ * Validates that all CSS classes used in Razor files are defined in CSS files.
5
+ * Helps catch missing CSS definitions before runtime.
6
+ *
7
+ * Usage:
8
+ * morph-spec validate-css [path]
9
+ * morph-spec validate-css src/MyApp.Web
10
+ * morph-spec validate-css --verbose
11
+ * morph-spec validate-css --generate-stub
12
+ */
13
+
14
+ import chalk from 'chalk';
15
+ import { existsSync, writeFileSync } from 'fs';
16
+ import { resolve, join } from 'path';
17
+ import {
18
+ validateCssClasses,
19
+ formatValidationResults,
20
+ generateCssStub
21
+ } from '../lib/css-validator.js';
22
+
23
+ /**
24
+ * Execute the validate-css command
25
+ * @param {string} path - Project path to validate
26
+ * @param {Object} options - Command options
27
+ */
28
+ export async function validateCssCommand(path, options = {}) {
29
+ const projectPath = resolve(path || '.');
30
+ const { verbose, generateStub, includeUtilities } = options;
31
+
32
+ // Validate path exists
33
+ if (!existsSync(projectPath)) {
34
+ console.error(chalk.red(`\n Error: Path does not exist: ${projectPath}\n`));
35
+ process.exit(1);
36
+ }
37
+
38
+ console.log(chalk.cyan('\n Validating CSS classes...\n'));
39
+ console.log(chalk.gray(` Path: ${projectPath}`));
40
+ console.log('');
41
+
42
+ try {
43
+ // Run validation
44
+ const results = await validateCssClasses(projectPath, {
45
+ verbose,
46
+ includeUtilities
47
+ });
48
+
49
+ // Output results
50
+ const formatted = formatValidationResults(results, verbose);
51
+ console.log(formatted);
52
+
53
+ // Generate stub if requested
54
+ if (generateStub && !results.valid) {
55
+ const stubContent = generateCssStub(results);
56
+ const stubPath = join(projectPath, 'missing-classes.css');
57
+
58
+ writeFileSync(stubPath, stubContent, 'utf8');
59
+ console.log(chalk.green(`\n Generated stub file: ${stubPath}\n`));
60
+ }
61
+
62
+ // Summary with colors
63
+ if (results.valid) {
64
+ console.log(chalk.green('\n All CSS classes are properly defined!\n'));
65
+ process.exit(0);
66
+ } else {
67
+ console.log(chalk.yellow(`\n Found ${results.missingClasses.length} missing CSS class(es)\n`));
68
+
69
+ // Suggestions
70
+ console.log(chalk.cyan('Suggestions:'));
71
+ console.log(chalk.gray(' 1. Add the missing classes to your design-system.css'));
72
+ console.log(chalk.gray(' 2. Run with --generate-stub to create a template file'));
73
+ console.log(chalk.gray(' 3. If using utility frameworks (Tailwind), add --include-utilities\n'));
74
+
75
+ process.exit(1);
76
+ }
77
+ } catch (error) {
78
+ console.error(chalk.red(`\n Error: ${error.message}\n`));
79
+ if (verbose) {
80
+ console.error(error.stack);
81
+ }
82
+ process.exit(1);
83
+ }
84
+ }
@@ -0,0 +1,221 @@
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 '../lib/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
+ /**
75
+ * Check if output file exists
76
+ */
77
+ function checkOutput(featurePath, outputFile) {
78
+ const filePath = path.join(featurePath, outputFile);
79
+ return fs.existsSync(filePath);
80
+ }
81
+
82
+ /**
83
+ * Validate phase requirements
84
+ */
85
+ function validatePhase(featureName, targetPhase) {
86
+ const featurePath = path.join(process.cwd(), '.morph/project/outputs', featureName);
87
+
88
+ // Check if feature directory exists
89
+ if (!fs.existsSync(featurePath)) {
90
+ return {
91
+ valid: false,
92
+ error: `Feature directory not found: ${featurePath}`,
93
+ suggestion: `Run 'morph-spec state set ${featureName} phase proposal' to start`,
94
+ missingOutputs: [],
95
+ phase: null
96
+ };
97
+ }
98
+
99
+ // Get target phase definition
100
+ const phaseDefinition = PHASES[targetPhase];
101
+ if (!phaseDefinition) {
102
+ return {
103
+ valid: false,
104
+ error: `Unknown phase: ${targetPhase}`,
105
+ validPhases: Object.keys(PHASES),
106
+ missingOutputs: [],
107
+ phase: null
108
+ };
109
+ }
110
+
111
+ // Check required outputs
112
+ const missingOutputs = [];
113
+ for (const output of phaseDefinition.requiredOutputs) {
114
+ if (!checkOutput(featurePath, output)) {
115
+ missingOutputs.push(output);
116
+ }
117
+ }
118
+
119
+ // Check state.json for current phase
120
+ let stateWarning = null;
121
+ try {
122
+ const feature = getFeature(featureName);
123
+ if (feature) {
124
+ const currentPhaseOrder = PHASES[feature.phase]?.order ?? -1;
125
+ const targetPhaseOrder = phaseDefinition.order;
126
+
127
+ if (targetPhaseOrder > currentPhaseOrder + 1) {
128
+ stateWarning = `Skipping phases: current is '${feature.phase}' (order ${currentPhaseOrder}), target is '${targetPhase}' (order ${targetPhaseOrder})`;
129
+ }
130
+ }
131
+ } catch {
132
+ // State file may not exist, that's OK
133
+ }
134
+
135
+ // Special validation: if target is 'implement', check tasks exist in state
136
+ if (targetPhase === 'implement') {
137
+ try {
138
+ const feature = getFeature(featureName);
139
+ if (feature && (!feature.tasks || feature.tasks.total === 0)) {
140
+ missingOutputs.push('tasks in state.json (run morph-spec task to add tasks)');
141
+ }
142
+ } catch {
143
+ // State file may not exist
144
+ }
145
+ }
146
+
147
+ return {
148
+ valid: missingOutputs.length === 0,
149
+ error: null,
150
+ missingOutputs,
151
+ phase: phaseDefinition,
152
+ featurePath,
153
+ stateWarning
154
+ };
155
+ }
156
+
157
+ /**
158
+ * Main command handler
159
+ */
160
+ export async function validatePhaseCommand(feature, phase, options = {}) {
161
+ console.log(chalk.cyan('\n╔════════════════════════════════════════════════╗'));
162
+ console.log(chalk.cyan('║ MORPH-SPEC PHASE VALIDATOR ║'));
163
+ console.log(chalk.cyan('╚════════════════════════════════════════════════╝\n'));
164
+
165
+ const result = validatePhase(feature, phase);
166
+
167
+ console.log(chalk.gray('Feature:'), feature);
168
+ console.log(chalk.gray('Target Phase:'), result.phase ? result.phase.name : phase);
169
+
170
+ if (result.phase) {
171
+ console.log(chalk.gray('Description:'), result.phase.description);
172
+ }
173
+
174
+ if (result.stateWarning) {
175
+ console.log(chalk.yellow(`\n⚠️ Warning: ${result.stateWarning}`));
176
+ }
177
+
178
+ if (result.valid) {
179
+ console.log(chalk.green('\n✓ VALIDATION PASSED'));
180
+ console.log(chalk.green(' All required outputs are present.'));
181
+ console.log(chalk.green(` Safe to proceed to ${result.phase.name}\n`));
182
+
183
+ if (options.verbose) {
184
+ console.log(chalk.gray('Required outputs found:'));
185
+ result.phase.requiredOutputs.forEach(output => {
186
+ console.log(chalk.gray(` ✓ ${output}`));
187
+ });
188
+ console.log('');
189
+ }
190
+ } else {
191
+ console.log(chalk.red('\n✗ VALIDATION FAILED'));
192
+
193
+ if (result.error) {
194
+ console.log(chalk.red(` Error: ${result.error}\n`));
195
+
196
+ if (result.suggestion) {
197
+ console.log(chalk.yellow(` Suggestion: ${result.suggestion}\n`));
198
+ }
199
+
200
+ if (result.validPhases) {
201
+ console.log(chalk.yellow('Valid phases:'));
202
+ result.validPhases.forEach(p => {
203
+ const def = PHASES[p];
204
+ console.log(chalk.gray(` - ${p}: ${def.name}${def.optional ? ' (optional)' : ''}`));
205
+ });
206
+ }
207
+ } else {
208
+ console.log(chalk.red(' Missing required outputs:'));
209
+ result.missingOutputs.forEach(output => {
210
+ console.log(chalk.gray(` - ${output}`));
211
+ });
212
+
213
+ console.log(chalk.yellow(`\n Action required:`));
214
+ console.log(chalk.yellow(` Complete the missing outputs before advancing to ${result.phase.name}`));
215
+ }
216
+ console.log('');
217
+ process.exit(1);
218
+ }
219
+ }
220
+
221
+ export { PHASES, validatePhase };