@polymorphism-tech/morph-spec 4.7.1 → 4.8.1

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 (138) hide show
  1. package/.morph/analytics/threads-log.jsonl +54 -0
  2. package/.morph/state.json +198 -0
  3. package/LICENSE +1 -2
  4. package/README.md +379 -414
  5. package/bin/morph-spec.js +57 -403
  6. package/bin/validate.js +2 -26
  7. package/claude-plugin.json +2 -2
  8. package/docs/ARCHITECTURE.md +43 -46
  9. package/docs/CHEATSHEET.md +203 -221
  10. package/docs/COMMAND-FLOWS.md +319 -289
  11. package/docs/QUICKSTART.md +2 -8
  12. package/docs/plans/2026-02-22-claude-docs-morph-alignment-analysis.md +2 -0
  13. package/docs/plans/2026-02-22-claude-settings.md +2 -0
  14. package/docs/plans/2026-02-22-morph-cc-alignment-impl.md +2 -0
  15. package/docs/plans/2026-02-22-morph-spec-next.md +2 -0
  16. package/docs/plans/2026-02-22-native-alignment-design.md +2 -0
  17. package/docs/plans/2026-02-22-native-alignment-impl.md +2 -0
  18. package/docs/plans/2026-02-22-native-enrichment-design.md +2 -0
  19. package/docs/plans/2026-02-22-native-enrichment.md +2 -0
  20. package/docs/plans/2026-02-23-ddd-architecture-refactor.md +2 -0
  21. package/docs/plans/2026-02-23-ddd-nextsteps.md +2 -0
  22. package/docs/plans/2026-02-23-infra-architect-refactor.md +2 -0
  23. package/docs/plans/2026-02-23-nextjs-code-review-design.md +2 -1
  24. package/docs/plans/2026-02-23-nextjs-code-review-impl.md +2 -0
  25. package/docs/plans/2026-02-23-nextjs-standards-design.md +2 -1
  26. package/docs/plans/2026-02-23-nextjs-standards-impl.md +2 -0
  27. package/docs/plans/2026-02-24-cli-radical-simplification.md +592 -0
  28. package/docs/plans/2026-02-24-framework-failure-points.md +125 -0
  29. package/docs/plans/2026-02-24-morph-init-design.md +337 -0
  30. package/docs/plans/2026-02-24-morph-init-impl.md +1269 -0
  31. package/docs/plans/2026-02-24-tutorial-command-design.md +71 -0
  32. package/docs/plans/2026-02-24-tutorial-command.md +298 -0
  33. package/framework/CLAUDE.md +2 -2
  34. package/framework/commands/morph-proposal.md +3 -3
  35. package/framework/hooks/README.md +11 -10
  36. package/framework/hooks/claude-code/notification/approval-reminder.js +2 -0
  37. package/framework/hooks/claude-code/post-tool-use/dispatch.js +1 -1
  38. package/framework/hooks/claude-code/pre-tool-use/protect-readonly-files.js +4 -55
  39. package/framework/hooks/claude-code/session-start/inject-morph-context.js +20 -5
  40. package/framework/hooks/claude-code/statusline.py +6 -1
  41. package/framework/hooks/claude-code/stop/validate-completion.js +1 -1
  42. package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +1 -1
  43. package/framework/hooks/dev/check-sync-health.js +117 -0
  44. package/framework/hooks/dev/guard-version-numbers.js +57 -0
  45. package/framework/hooks/dev/sync-standards-registry.js +60 -0
  46. package/framework/hooks/dev/sync-template-registry.js +60 -0
  47. package/framework/hooks/dev/validate-skill-format.js +70 -0
  48. package/framework/hooks/dev/validate-standard-format.js +73 -0
  49. package/framework/hooks/shared/payload-utils.js +39 -0
  50. package/framework/hooks/shared/state-reader.js +25 -1
  51. package/framework/rules/morph-workflow.md +1 -1
  52. package/framework/skills/level-0-meta/morph-init/SKILL.md +216 -0
  53. package/framework/skills/level-0-meta/morph-replicate/SKILL.md +4 -4
  54. package/framework/skills/level-0-meta/tool-usage-guide/SKILL.md +4 -4
  55. package/framework/skills/level-0-meta/verification-before-completion/SKILL.md +1 -1
  56. package/framework/skills/level-1-workflows/phase-clarify/SKILL.md +192 -191
  57. package/framework/skills/level-1-workflows/phase-codebase-analysis/SKILL.md +181 -180
  58. package/framework/skills/level-1-workflows/phase-design/SKILL.md +339 -338
  59. package/framework/skills/level-1-workflows/phase-implement/SKILL.md +254 -253
  60. package/framework/skills/level-1-workflows/phase-setup/SKILL.md +168 -170
  61. package/framework/skills/level-1-workflows/phase-tasks/SKILL.md +284 -283
  62. package/framework/skills/level-1-workflows/phase-uiux/SKILL.md +246 -245
  63. package/framework/templates/examples/design-system-examples.md +1 -1
  64. package/framework/templates/ui/FluentDesignTheme.cs +1 -1
  65. package/framework/templates/ui/MudTheme.cs +1 -1
  66. package/framework/templates/ui/design-system.css +1 -1
  67. package/package.json +4 -2
  68. package/scripts/bump-version.js +248 -0
  69. package/scripts/install-dev-hooks.js +138 -0
  70. package/src/commands/agents/index.js +1 -2
  71. package/src/commands/index.js +13 -16
  72. package/src/commands/project/doctor.js +100 -14
  73. package/src/commands/project/index.js +7 -10
  74. package/src/commands/project/init.js +398 -555
  75. package/src/commands/project/install-plugin-cmd.js +28 -0
  76. package/src/commands/project/setup-infra-cmd.js +12 -0
  77. package/src/commands/project/tutorial.js +115 -0
  78. package/src/commands/project/update.js +22 -37
  79. package/src/commands/state/approve.js +213 -221
  80. package/src/commands/state/index.js +0 -1
  81. package/src/commands/state/state.js +337 -365
  82. package/src/commands/templates/index.js +0 -4
  83. package/src/commands/trust/trust.js +1 -93
  84. package/src/commands/utils/index.js +1 -5
  85. package/src/commands/validation/index.js +1 -5
  86. package/src/core/registry/command-registry.js +11 -285
  87. package/src/core/state/state-manager.js +5 -2
  88. package/src/lib/detectors/index.js +81 -87
  89. package/src/lib/detectors/structure-detector.js +275 -273
  90. package/src/lib/generators/recap-generator.js +232 -225
  91. package/src/lib/installers/mcp-installer.js +18 -3
  92. package/src/scripts/global-install.js +34 -0
  93. package/src/scripts/install-plugin.js +126 -0
  94. package/src/scripts/setup-infra.js +203 -0
  95. package/src/utils/agents-installer.js +10 -1
  96. package/src/utils/hooks-installer.js +70 -17
  97. package/CLAUDE.md +0 -77
  98. package/docs/claude-alignment-report.md +0 -137
  99. package/docs/examples/order-management/contracts.cs +0 -84
  100. package/docs/examples/order-management/proposal.md +0 -24
  101. package/docs/examples/order-management/spec.md +0 -162
  102. package/src/commands/feature/create-story.js +0 -362
  103. package/src/commands/feature/index.js +0 -6
  104. package/src/commands/feature/shard-spec.js +0 -225
  105. package/src/commands/feature/sprint-status.js +0 -250
  106. package/src/commands/generation/generate-onboarding.js +0 -169
  107. package/src/commands/generation/generate.js +0 -276
  108. package/src/commands/generation/index.js +0 -5
  109. package/src/commands/learning/capture-pattern.js +0 -121
  110. package/src/commands/learning/index.js +0 -5
  111. package/src/commands/learning/search-patterns.js +0 -126
  112. package/src/commands/mcp/mcp.js +0 -102
  113. package/src/commands/project/changes.js +0 -66
  114. package/src/commands/project/cost.js +0 -179
  115. package/src/commands/project/detect.js +0 -114
  116. package/src/commands/project/diff.js +0 -278
  117. package/src/commands/project/revert.js +0 -173
  118. package/src/commands/project/standards.js +0 -80
  119. package/src/commands/project/sync.js +0 -167
  120. package/src/commands/project/update-agents.js +0 -23
  121. package/src/commands/state/rollback-phase.js +0 -185
  122. package/src/commands/templates/template-customize.js +0 -87
  123. package/src/commands/templates/template-list.js +0 -114
  124. package/src/commands/templates/template-show.js +0 -129
  125. package/src/commands/templates/template-validate.js +0 -91
  126. package/src/commands/utils/troubleshoot.js +0 -222
  127. package/src/commands/validation/analyze-blazor-concurrency.js +0 -193
  128. package/src/commands/validation/lint-fluent.js +0 -352
  129. package/src/commands/validation/validate-blazor-state.js +0 -210
  130. package/src/commands/validation/validate-blazor.js +0 -156
  131. package/src/commands/validation/validate-css.js +0 -84
  132. package/src/lib/detectors/conversation-analyzer.js +0 -163
  133. package/src/lib/learning/index.js +0 -7
  134. package/src/lib/learning/learning-system.js +0 -520
  135. package/src/lib/troubleshooting/index.js +0 -8
  136. package/src/lib/troubleshooting/troubleshoot-grep.js +0 -198
  137. package/src/lib/troubleshooting/troubleshoot-index.js +0 -144
  138. package/src/llm/environment-detector.js +0 -43
@@ -1,129 +0,0 @@
1
- /**
2
- * Template Show Command - Display detailed information about a template
3
- */
4
-
5
- import chalk from 'chalk';
6
- import { logger } from '../../utils/logger.js';
7
- import { getTemplateById, resolveTemplatePathById } from '../../core/templates/template-registry.js';
8
- import { readFileSync, existsSync } from 'fs';
9
-
10
- /**
11
- * Show template details command
12
- */
13
- export async function templateShowCommand(templateId, options) {
14
- logger.header(`Template: ${templateId}`);
15
- logger.blank();
16
-
17
- try {
18
- const template = getTemplateById(templateId);
19
-
20
- if (!template) {
21
- logger.error(`Template not found: ${templateId}`);
22
- logger.dim('\n💡 Use `morph-spec template list` to see available templates');
23
- process.exit(1);
24
- }
25
-
26
- // Display template metadata
27
- logger.info(chalk.bold('📋 Metadata'));
28
- console.log(` ID: ${chalk.cyan(template.id)}`);
29
- console.log(` Name: ${chalk.green(template.name)}`);
30
- console.log(` Path: ${chalk.dim(template.path)}`);
31
- console.log(` Location: ${template.location === 'framework' ? chalk.cyan('framework') : chalk.yellow('stack')}`);
32
- console.log(` Category: ${template.category}`);
33
- console.log(` Phase: ${template.phase || 'N/A'}`);
34
- console.log(` Required: ${template.required ? chalk.green('Yes') : chalk.dim('No')}`);
35
- console.log(` Stack-Specific: ${template.stackSpecific ? chalk.yellow('Yes') : chalk.cyan('No (universal)')}`);
36
-
37
- if (template.stackSpecific && template.stacks) {
38
- console.log(` Stacks: ${chalk.yellow(template.stacks.join(', '))}`);
39
- }
40
-
41
- console.log(` Engine: ${template.engine === 'handlebars' ? chalk.blue('Handlebars') : chalk.dim('Custom')}`);
42
-
43
- if (template.deprecated) {
44
- console.log(` ${chalk.red.bold('⚠️ DEPRECATED')}`);
45
- }
46
-
47
- if (template.autoGenerated) {
48
- console.log(` ${chalk.dim('Auto-generated (not user-facing)')}`);
49
- }
50
-
51
- logger.blank();
52
-
53
- // Description
54
- if (template.description) {
55
- logger.info(chalk.bold('📝 Description'));
56
- console.log(` ${template.description}`);
57
- logger.blank();
58
- }
59
-
60
- // Placeholders
61
- if (template.placeholders && template.placeholders.length > 0) {
62
- logger.info(chalk.bold('🔑 Variables'));
63
- template.placeholders.forEach(p => {
64
- console.log(` ${chalk.cyan(`{{${p}}}`)}`);
65
- });
66
- logger.blank();
67
- }
68
-
69
- // Output name
70
- if (template.outputName) {
71
- logger.info(chalk.bold('📄 Output Name'));
72
- console.log(` ${chalk.dim(template.outputName)}`);
73
- logger.blank();
74
- }
75
-
76
- // Resolve actual path
77
- if (options.showPath) {
78
- const projectPath = options.projectPath || process.cwd();
79
- const resolvedPath = resolveTemplatePathById(templateId, projectPath);
80
-
81
- logger.info(chalk.bold('📂 Resolved Path'));
82
- if (resolvedPath) {
83
- console.log(` ${chalk.green(resolvedPath)}`);
84
- console.log(` ${chalk.dim(`(${existsSync(resolvedPath) ? 'exists' : 'not found'})`)}`);
85
- } else {
86
- console.log(` ${chalk.red('Not found in .morph/framework/templates/ or framework/templates/')}`);
87
- }
88
- logger.blank();
89
- }
90
-
91
- // Show template preview
92
- if (options.preview) {
93
- const projectPath = options.projectPath || process.cwd();
94
- const resolvedPath = resolveTemplatePathById(templateId, projectPath);
95
-
96
- if (resolvedPath && existsSync(resolvedPath)) {
97
- logger.info(chalk.bold('👁️ Preview (first 20 lines)'));
98
- logger.blank();
99
-
100
- const content = readFileSync(resolvedPath, 'utf-8');
101
- const lines = content.split('\n').slice(0, 20);
102
-
103
- lines.forEach((line, i) => {
104
- console.log(chalk.dim(`${String(i + 1).padStart(3)} ${line}`));
105
- });
106
-
107
- if (content.split('\n').length > 20) {
108
- logger.blank();
109
- logger.dim(` ... (${content.split('\n').length - 20} more lines)`);
110
- }
111
-
112
- logger.blank();
113
- } else {
114
- logger.warn('Template file not found - cannot preview');
115
- }
116
- }
117
-
118
- // Show usage hint
119
- if (template.engine === 'handlebars') {
120
- logger.info(chalk.bold('💡 Usage Hint'));
121
- console.log(chalk.dim(` morph-spec template render ${templateId} output.md '{"FEATURE_NAME":"my-feature"}'`));
122
- logger.blank();
123
- }
124
-
125
- } catch (error) {
126
- logger.error(`Failed to show template: ${error.message}`);
127
- process.exit(1);
128
- }
129
- }
@@ -1,91 +0,0 @@
1
- /**
2
- * Template Validate Command - Validate Handlebars templates
3
- */
4
-
5
- import chalk from 'chalk';
6
- import { logger } from '../../utils/logger.js';
7
- import { validateTemplate, validateAllTemplates, formatValidationResults, summarizeValidation } from '../../core/templates/template-validator.js';
8
-
9
- /**
10
- * Validate template(s) command
11
- */
12
- export async function templateValidateCommand(templateId, options) {
13
- const projectPath = options.projectPath || process.cwd();
14
-
15
- if (templateId) {
16
- // Validate single template
17
- logger.header(`Validating Template: ${templateId}`);
18
- logger.blank();
19
-
20
- const result = validateTemplate(templateId, projectPath);
21
-
22
- // Display results
23
- if (result.errors.length === 0 && result.warnings.length === 0) {
24
- logger.success(`✅ Template is valid`);
25
- logger.blank();
26
-
27
- if (result.info.length > 0 && options.verbose) {
28
- logger.info(chalk.bold('ℹ️ Information'));
29
- result.info.forEach(info => console.log(chalk.dim(` ${info}`)));
30
- logger.blank();
31
- }
32
- } else {
33
- if (result.errors.length > 0) {
34
- logger.error(chalk.bold('❌ Errors'));
35
- result.errors.forEach(error => console.log(chalk.red(` - ${error}`)));
36
- logger.blank();
37
- }
38
-
39
- if (result.warnings.length > 0) {
40
- logger.warn(chalk.bold('⚠️ Warnings'));
41
- result.warnings.forEach(warning => console.log(chalk.yellow(` - ${warning}`)));
42
- logger.blank();
43
- }
44
-
45
- if (result.info.length > 0 && options.verbose) {
46
- logger.info(chalk.bold('ℹ️ Information'));
47
- result.info.forEach(info => console.log(chalk.dim(` ${info}`)));
48
- logger.blank();
49
- }
50
-
51
- if (result.errors.length > 0) {
52
- process.exit(1);
53
- }
54
- }
55
- } else {
56
- // Validate all templates
57
- logger.header('Validating All Templates');
58
- logger.blank();
59
-
60
- const validationOptions = {
61
- skipDeprecated: !options.includeDeprecated,
62
- category: options.category,
63
- technology: options.technology,
64
- };
65
-
66
- const results = validateAllTemplates(projectPath, validationOptions);
67
- const summary = summarizeValidation(results);
68
-
69
- // Display results
70
- const formatted = formatValidationResults(results, {
71
- showInfo: options.verbose,
72
- showValid: options.showValid,
73
- });
74
-
75
- console.log(formatted);
76
- logger.blank();
77
-
78
- // Exit with error if any templates have errors
79
- if (summary.hasErrors > 0) {
80
- logger.error(`${summary.hasErrors} template(s) failed validation`);
81
- process.exit(1);
82
- } else if (summary.hasWarnings > 0) {
83
- logger.warn(`${summary.hasWarnings} template(s) have warnings`);
84
- if (options.strict) {
85
- process.exit(1);
86
- }
87
- } else {
88
- logger.success(`All templates are valid! ✅`);
89
- }
90
- }
91
- }
@@ -1,222 +0,0 @@
1
- /**
2
- * Troubleshoot Command
3
- * Search for solutions to common problems
4
- *
5
- * Usage: morph-spec troubleshoot <keywords...>
6
- */
7
-
8
- import { searchIndex, getCategories } from '../../lib/troubleshooting/troubleshoot-index.js';
9
- import { searchGrep } from '../../lib/troubleshooting/troubleshoot-grep.js';
10
- import chalk from 'chalk';
11
-
12
- // Severity colors and icons
13
- const SEVERITY_CONFIG = {
14
- critical: { color: chalk.red, icon: '🔴', label: 'CRITICAL' },
15
- high: { color: chalk.yellow, icon: '🟠', label: 'HIGH' },
16
- medium: { color: chalk.blue, icon: '🔵', label: 'MEDIUM' },
17
- low: { color: chalk.gray, icon: '⚪', label: 'LOW' }
18
- };
19
-
20
- /**
21
- * Format a single result for display
22
- * @param {Object} result - Result object
23
- * @param {boolean} verbose - Show full content
24
- * @returns {string} Formatted output
25
- */
26
- function formatResult(result, verbose = false) {
27
- const severity = SEVERITY_CONFIG[result.severity] || SEVERITY_CONFIG.medium;
28
- const lines = [];
29
-
30
- lines.push(chalk.gray('━'.repeat(50)));
31
- lines.push('');
32
- lines.push(`${severity.icon} ${severity.color.bold(severity.label)}: ${chalk.white.bold(result.title)}`);
33
- lines.push('');
34
-
35
- // File and section
36
- lines.push(`${chalk.gray('📁 Arquivo:')} ${chalk.cyan(result.file)}`);
37
- if (result.section) {
38
- lines.push(`${chalk.gray('📂 Seção:')} ${result.section}`);
39
- }
40
- lines.push('');
41
-
42
- // Cause
43
- if (result.cause) {
44
- lines.push(`${chalk.red('💡 Causa:')}`);
45
- lines.push(` ${result.cause}`);
46
- lines.push('');
47
- }
48
-
49
- // Solution
50
- if (result.solution) {
51
- lines.push(`${chalk.green('✅ Solução:')}`);
52
- lines.push(` ${chalk.white(result.solution)}`);
53
- lines.push('');
54
- }
55
-
56
- // Content preview (for grep results or verbose mode)
57
- if (verbose && result.content) {
58
- lines.push(`${chalk.gray('📝 Conteúdo:')}`);
59
- const contentLines = result.content.split('\n').slice(0, 15);
60
- contentLines.forEach(line => {
61
- lines.push(` ${chalk.gray(line)}`);
62
- });
63
- lines.push('');
64
- }
65
-
66
- // Keywords matched
67
- if (result.keywords && result.keywords.length > 0) {
68
- const keywords = Array.isArray(result.keywords)
69
- ? result.keywords.slice(0, 5).join(', ')
70
- : result.keywords;
71
- lines.push(`${chalk.gray('🏷️ Keywords:')} ${chalk.dim(keywords)}`);
72
- }
73
-
74
- // Source (index or grep)
75
- if (result.source === 'grep') {
76
- lines.push(`${chalk.gray('🔍 Fonte:')} ${chalk.dim('Busca em arquivos (grep)')}`);
77
- }
78
-
79
- lines.push('');
80
-
81
- return lines.join('\n');
82
- }
83
-
84
- /**
85
- * Format the summary footer
86
- * @param {Object} stats - Search statistics
87
- * @returns {string} Formatted summary
88
- */
89
- function formatSummary(stats) {
90
- const lines = [];
91
-
92
- lines.push(chalk.gray('━'.repeat(50)));
93
- lines.push('');
94
-
95
- if (stats.total === 0) {
96
- lines.push(chalk.yellow('⚠️ Nenhum resultado encontrado no índice ou arquivos.'));
97
- lines.push('');
98
- lines.push(chalk.dim('💡 Dicas:'));
99
- lines.push(chalk.dim(' • Tente termos mais específicos (ex: "NU1605" em vez de "error")'));
100
- lines.push(chalk.dim(' • Use parte da mensagem de erro exata'));
101
- lines.push(chalk.dim(' • Consulte a documentação: morph-spec read frontend/blazor/pitfalls.md'));
102
- } else {
103
- lines.push(`${chalk.green('✅')} Encontrado ${chalk.bold(stats.total)} resultado(s)`);
104
-
105
- if (stats.fromIndex > 0) {
106
- lines.push(` ${chalk.dim(`• ${stats.fromIndex} do índice de problemas conhecidos`)}`);
107
- }
108
- if (stats.fromGrep > 0) {
109
- lines.push(` ${chalk.dim(`• ${stats.fromGrep} da busca em arquivos`)}`);
110
- }
111
- }
112
-
113
- lines.push('');
114
-
115
- return lines.join('\n');
116
- }
117
-
118
- /**
119
- * List all categories
120
- */
121
- function listCategories() {
122
- const categories = getCategories();
123
-
124
- console.log('');
125
- console.log(chalk.bold('📂 Categorias disponíveis:'));
126
- console.log('');
127
-
128
- for (const [id, category] of Object.entries(categories)) {
129
- const name = typeof category === 'object' ? category.name : category;
130
- const desc = typeof category === 'object' ? category.description : '';
131
- console.log(` ${chalk.cyan(id.padEnd(12))} ${name}`);
132
- if (desc) {
133
- console.log(` ${' '.repeat(12)} ${chalk.dim(desc)}`);
134
- }
135
- }
136
-
137
- console.log('');
138
- console.log(chalk.dim('Uso: morph-spec troubleshoot --category efcore "sua busca"'));
139
- console.log('');
140
- }
141
-
142
- /**
143
- * Main troubleshoot command
144
- * @param {string[]} keywords - Search keywords
145
- * @param {Object} options - Command options
146
- */
147
- export async function troubleshootCommand(keywords, options = {}) {
148
- // Handle --list-categories flag
149
- if (options.listCategories) {
150
- listCategories();
151
- return;
152
- }
153
-
154
- // Validate keywords
155
- if (!keywords || keywords.length === 0) {
156
- console.log('');
157
- console.log(chalk.yellow('⚠️ Por favor, forneça termos de busca.'));
158
- console.log('');
159
- console.log(chalk.dim('Exemplos:'));
160
- console.log(chalk.dim(' morph-spec troubleshoot "blazor.web.js 404"'));
161
- console.log(chalk.dim(' morph-spec troubleshoot DbContext concurrent'));
162
- console.log(chalk.dim(' morph-spec troubleshoot NU1605 Azure.Identity'));
163
- console.log('');
164
- console.log(chalk.dim('Opções:'));
165
- console.log(chalk.dim(' --category <cat> Filtrar por categoria (blazor, efcore, azure)'));
166
- console.log(chalk.dim(' --verbose, -v Mostrar conteúdo completo'));
167
- console.log(chalk.dim(' --list-categories Listar categorias disponíveis'));
168
- console.log('');
169
- return;
170
- }
171
-
172
- const searchTerms = Array.isArray(keywords) ? keywords : [keywords];
173
-
174
- console.log('');
175
- console.log(`${chalk.cyan('🔍')} Buscando soluções para: ${chalk.bold(`"${searchTerms.join(' ')}"`)}`);
176
- console.log('');
177
-
178
- // Search options
179
- const searchOptions = {};
180
- if (options.category) {
181
- searchOptions.category = options.category;
182
- console.log(chalk.dim(` Filtrando por categoria: ${options.category}`));
183
- console.log('');
184
- }
185
-
186
- // Level 1: Search index
187
- let indexResults = searchIndex(searchTerms, searchOptions);
188
- indexResults = indexResults.map(r => ({ ...r, source: 'index' }));
189
-
190
- // Level 2: Grep fallback (if few results)
191
- let grepResults = [];
192
- if (indexResults.length < 3) {
193
- grepResults = searchGrep(searchTerms, searchOptions);
194
- // Filter out duplicates (same file + section)
195
- const indexKeys = new Set(indexResults.map(r => `${r.file}:${r.section}`));
196
- grepResults = grepResults.filter(r => !indexKeys.has(`${r.file}:${r.section}`));
197
- }
198
-
199
- // Combine and limit results
200
- const allResults = [...indexResults, ...grepResults].slice(0, 10);
201
-
202
- // Display results
203
- for (const result of allResults) {
204
- console.log(formatResult(result, options.verbose));
205
- }
206
-
207
- // Display summary
208
- console.log(formatSummary({
209
- total: allResults.length,
210
- fromIndex: indexResults.length,
211
- fromGrep: grepResults.slice(0, 10 - indexResults.length).length
212
- }));
213
-
214
- // Hint for web search (handled by Claude Code slash command)
215
- if (allResults.length === 0) {
216
- console.log(chalk.dim('💡 Use /morph-troubleshoot no Claude Code para busca web em'));
217
- console.log(chalk.dim(' GitHub Issues, Stack Overflow e Microsoft Learn.'));
218
- console.log('');
219
- }
220
- }
221
-
222
- export default troubleshootCommand;
@@ -1,193 +0,0 @@
1
- /**
2
- * analyze-blazor-concurrency command
3
- *
4
- * Analyzes Blazor Server code for DbContext concurrency issues.
5
- *
6
- * Usage:
7
- * morph-spec analyze-blazor-concurrency [path]
8
- * morph-spec analyze-blazor-concurrency src/Services --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
- analyzeConcurrency,
19
- } from '../../lib/validators/blazor/blazor-concurrency-analyzer.js';
20
- import { countIssues } from '../../lib/validators/shared/index.js';
21
-
22
- /**
23
- * Main command handler for analyze-blazor-concurrency.
24
- *
25
- * @param {string} [targetPath] - Path to analyze (file or directory)
26
- * @param {Object} options - Command options
27
- * @param {boolean} [options.verbose] - Show detailed output
28
- */
29
- export async function analyzeBlazorConcurrencyCommand(targetPath, options = {}) {
30
- const { verbose = false } = options;
31
-
32
- console.log('');
33
- console.log(
34
- chalk.cyan('\uD83D\uDD0D Analisando concorrencia DbContext em Blazor Server...')
35
- );
36
- console.log('');
37
-
38
- // Determine target path
39
- const basePath = targetPath ? resolve(targetPath) : process.cwd();
40
-
41
- if (!existsSync(basePath)) {
42
- console.log(chalk.red(`\u274C Path not found: ${basePath}`));
43
- process.exit(1);
44
- }
45
-
46
- const spinner = ora('Scanning for C# files...').start();
47
-
48
- let files = [];
49
-
50
- try {
51
- const stats = statSync(basePath);
52
-
53
- if (stats.isFile()) {
54
- if (basePath.endsWith('.cs')) {
55
- files = [basePath];
56
- } else {
57
- spinner.fail('File must be .cs');
58
- process.exit(1);
59
- }
60
- } else {
61
- // Find all C# files (services, repositories, handlers)
62
- const pattern = join(basePath, '**/*.cs');
63
- files = await glob(pattern, {
64
- ignore: [
65
- '**/node_modules/**',
66
- '**/bin/**',
67
- '**/obj/**',
68
- '**/Migrations/**',
69
- ],
70
- windowsPathsNoEscape: true,
71
- });
72
- }
73
-
74
- spinner.succeed(`Found ${files.length} C# file(s)`);
75
- } catch (error) {
76
- spinner.fail(`Error scanning files: ${error.message}`);
77
- process.exit(1);
78
- }
79
-
80
- if (files.length === 0) {
81
- console.log(chalk.yellow('\n\u26A0\uFE0F No C# files found to analyze'));
82
- return;
83
- }
84
-
85
- // Analyze each file
86
- const allIssues = [];
87
- const fileResults = [];
88
-
89
- for (const file of files) {
90
- try {
91
- const content = readFileSync(file, 'utf-8');
92
- const issues = analyzeConcurrency(content, file);
93
-
94
- if (issues.length > 0) {
95
- allIssues.push(...issues);
96
- fileResults.push({ file, issues });
97
- }
98
- } catch (error) {
99
- if (verbose) {
100
- console.log(chalk.red(`\u274C Error reading ${file}: ${error.message}`));
101
- }
102
- }
103
- }
104
-
105
- // Output results
106
- console.log('');
107
-
108
- if (allIssues.length === 0) {
109
- console.log(
110
- chalk.green(
111
- '\u2705 Nenhum problema de concorrencia detectado!'
112
- )
113
- );
114
- console.log(
115
- chalk.gray(
116
- ' Dica: Certifique-se de usar IDbContextFactory para operacoes background.'
117
- )
118
- );
119
- console.log('');
120
- return;
121
- }
122
-
123
- // Display issues
124
- if (verbose) {
125
- fileResults.forEach(({ file, issues }) => {
126
- console.log(chalk.white.bold(`\n${file}`));
127
- console.log(chalk.gray('-'.repeat(60)));
128
-
129
- issues.forEach((issue) => {
130
- const icon =
131
- issue.type === 'error'
132
- ? '\u274C'
133
- : issue.type === 'warning'
134
- ? '\u26A0\uFE0F'
135
- : '\u2139\uFE0F';
136
-
137
- console.log(`${icon} ${issue.message}`);
138
- if (issue.suggestion) {
139
- console.log(chalk.gray(` \u2192 ${issue.suggestion}`));
140
- }
141
- if (issue.line) {
142
- console.log(chalk.dim(` Linha: ${issue.line}`));
143
- }
144
- if (issue.code) {
145
- console.log(chalk.dim(` Codigo: ${issue.code}`));
146
- }
147
- console.log('');
148
- });
149
- });
150
- } else {
151
- allIssues.forEach((issue) => {
152
- const icon =
153
- issue.type === 'error'
154
- ? '\u274C'
155
- : issue.type === 'warning'
156
- ? '\u26A0\uFE0F'
157
- : '\u2139\uFE0F';
158
-
159
- const location = issue.line ? `${issue.file}:${issue.line}` : issue.file;
160
-
161
- console.log(`${icon} ${issue.message}`);
162
- if (issue.suggestion) {
163
- console.log(chalk.gray(` \u2192 ${issue.suggestion}`));
164
- }
165
- console.log(chalk.dim(` ${location}`));
166
- console.log('');
167
- });
168
- }
169
-
170
- // Summary
171
- const { errors, warnings, infos } = countIssues(allIssues);
172
- const summaryColor = errors > 0 ? chalk.red : chalk.yellow;
173
-
174
- console.log(chalk.gray('-'.repeat(60)));
175
- console.log(
176
- summaryColor(
177
- `\n${files.length} arquivo(s) analisado(s) | ${errors} erro(s) | ${warnings} warning(s) | ${infos} info(s)\n`
178
- )
179
- );
180
-
181
- // Recommendation
182
- if (errors > 0) {
183
- console.log(
184
- chalk.cyan(
185
- '\uD83D\uDCD6 Consulte: framework/standards/backend/database/ef-core.md para padroes corretos'
186
- )
187
- );
188
- console.log('');
189
- process.exit(1);
190
- }
191
- }
192
-
193
- export default analyzeBlazorConcurrencyCommand;