@polymorphism-tech/morph-spec 4.9.0 → 4.10.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.
- package/README.md +2 -2
- package/bin/morph-spec.js +30 -0
- package/bin/task-manager.js +34 -22
- package/claude-plugin.json +1 -1
- package/docs/CHEATSHEET.md +1 -1
- package/docs/QUICKSTART.md +1 -1
- package/framework/CLAUDE.md +35 -98
- package/framework/agents/backend/api-designer.md +3 -0
- package/framework/agents/backend/dotnet-senior.md +3 -0
- package/framework/agents/backend/ef-modeler.md +2 -0
- package/framework/agents/backend/hangfire-orchestrator.md +2 -0
- package/framework/agents/backend/ms-agent-expert.md +2 -0
- package/framework/agents/frontend/blazor-builder.md +2 -0
- package/framework/agents/frontend/nextjs-expert.md +2 -0
- package/framework/agents/infrastructure/azure-architect.md +2 -0
- package/framework/agents/infrastructure/azure-deploy-specialist.md +2 -0
- package/framework/agents/infrastructure/bicep-architect.md +2 -0
- package/framework/agents/infrastructure/container-specialist.md +2 -0
- package/framework/agents/infrastructure/devops-engineer.md +3 -0
- package/framework/agents/infrastructure/infra-architect.md +3 -0
- package/framework/agents/integrations/asaas-financial.md +2 -0
- package/framework/agents/integrations/azure-identity.md +2 -0
- package/framework/agents/integrations/clerk-auth.md +3 -0
- package/framework/agents/integrations/hangfire-integration.md +2 -0
- package/framework/agents/integrations/resend-email.md +2 -0
- package/framework/agents.json +37 -7
- package/framework/commands/commit.md +166 -0
- package/framework/commands/morph-apply.md +156 -155
- package/framework/commands/morph-archive.md +33 -27
- package/framework/commands/morph-infra.md +83 -77
- package/framework/commands/morph-preflight.md +97 -55
- package/framework/commands/morph-proposal.md +131 -58
- package/framework/commands/morph-status.md +36 -30
- package/framework/commands/morph-troubleshoot.md +68 -59
- package/framework/hooks/claude-code/notification/approval-reminder.js +3 -2
- package/framework/hooks/claude-code/post-tool-use/dispatch.js +154 -31
- package/framework/hooks/claude-code/post-tool-use/skill-reminder.js +7 -84
- package/framework/hooks/claude-code/post-tool-use/validator-feedback.js +8 -17
- package/framework/hooks/claude-code/pre-compact/save-morph-context.js +16 -3
- package/framework/hooks/claude-code/pre-tool-use/enforce-phase-writes.js +4 -3
- package/framework/hooks/claude-code/pre-tool-use/protect-spec-files.js +3 -2
- package/framework/hooks/claude-code/pre-tool-use/task-tracking-guard.js +60 -0
- package/framework/hooks/claude-code/session-start/inject-morph-context.js +55 -2
- package/framework/hooks/claude-code/session-start/post-compact-restore.js +41 -0
- package/framework/hooks/claude-code/stop/validate-completion.js +2 -15
- package/framework/hooks/claude-code/user-prompt/enrich-prompt.js +23 -5
- package/framework/hooks/shared/compact-restore.js +100 -0
- package/framework/hooks/shared/dispatch-helpers.js +116 -0
- package/framework/hooks/shared/phase-utils.js +9 -5
- package/framework/hooks/shared/state-reader.js +27 -3
- package/framework/phases.json +30 -7
- package/framework/rules/csharp-standards.md +3 -0
- package/framework/rules/frontend-standards.md +2 -0
- package/framework/rules/infrastructure-standards.md +3 -0
- package/framework/rules/morph-workflow.md +143 -86
- package/framework/rules/nextjs-standards.md +2 -0
- package/framework/rules/testing-standards.md +3 -0
- package/framework/skills/level-0-meta/mcp-registry.json +86 -51
- package/framework/skills/level-0-meta/morph-brainstorming/SKILL.md +139 -0
- package/framework/skills/level-0-meta/morph-checklist/SKILL.md +42 -19
- package/framework/skills/level-0-meta/{code-review → morph-code-review}/SKILL.md +8 -5
- package/framework/skills/level-0-meta/{code-review-nextjs → morph-code-review-nextjs}/SKILL.md +8 -6
- package/framework/skills/level-0-meta/morph-frontend-review/SKILL.md +362 -0
- package/framework/skills/level-0-meta/morph-init/SKILL.md +114 -20
- package/framework/skills/level-0-meta/morph-post-implementation/SKILL.md +362 -0
- package/framework/skills/level-0-meta/morph-replicate/SKILL.md +95 -87
- package/framework/skills/level-0-meta/{simulation-checklist → morph-simulation-checklist}/SKILL.md +24 -0
- package/framework/skills/level-0-meta/{tool-usage-guide → morph-tool-usage-guide}/SKILL.md +43 -43
- package/framework/skills/level-0-meta/{tool-usage-guide → morph-tool-usage-guide}/references/tools-per-phase.md +1 -2
- package/framework/skills/level-0-meta/{verification-before-completion → morph-verification-before-completion}/SKILL.md +23 -12
- package/framework/skills/level-0-meta/{verification-before-completion → morph-verification-before-completion}/scripts/check-phase-outputs.mjs +2 -2
- package/framework/skills/level-1-workflows/morph-phase-clarify/SKILL.md +247 -0
- package/framework/skills/level-1-workflows/morph-phase-codebase-analysis/SKILL.md +270 -0
- package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +499 -0
- package/framework/skills/level-1-workflows/morph-phase-implement/.morph/logs/activity.json +38 -0
- package/framework/skills/level-1-workflows/morph-phase-implement/SKILL.md +472 -0
- package/framework/skills/level-1-workflows/morph-phase-implement/prompts/code-quality-reviewer-prompt.md +50 -0
- package/framework/skills/level-1-workflows/morph-phase-implement/prompts/implementer-prompt.md +45 -0
- package/framework/skills/level-1-workflows/morph-phase-implement/prompts/spec-reviewer-prompt.md +47 -0
- package/framework/skills/level-1-workflows/morph-phase-plan/SKILL.md +246 -0
- package/framework/skills/level-1-workflows/morph-phase-setup/SKILL.md +238 -0
- package/framework/skills/level-1-workflows/morph-phase-tasks/.morph/logs/activity.json +14 -0
- package/framework/skills/level-1-workflows/morph-phase-tasks/SKILL.md +312 -0
- package/framework/skills/level-1-workflows/{phase-tasks → morph-phase-tasks}/scripts/validate-tasks.mjs +3 -3
- package/framework/skills/level-1-workflows/morph-phase-uiux/SKILL.md +324 -0
- package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +146 -0
- package/framework/standards/integration/mcp/mcp-tools.md +25 -7
- package/framework/templates/docs/onboarding.md +2 -2
- package/package.json +3 -4
- package/src/commands/agents/dispatch-agents.js +50 -3
- package/src/commands/mcp/mcp-setup.js +39 -2
- package/src/commands/phase/phase-reset.js +74 -0
- package/src/commands/project/doctor.js +26 -7
- package/src/commands/project/update.js +4 -4
- package/src/commands/scope/escalate.js +215 -0
- package/src/commands/state/advance-phase.js +27 -53
- package/src/commands/state/state.js +1 -1
- package/src/commands/task/expand.js +100 -0
- package/src/core/paths/output-schema.js +4 -3
- package/src/core/state/phase-state-machine.js +7 -4
- package/src/core/state/state-manager.js +4 -3
- package/src/lib/detectors/claude-config-detector.js +93 -347
- package/src/lib/detectors/design-system-detector.js +189 -189
- package/src/lib/detectors/index.js +155 -57
- package/src/lib/generators/context-generator.js +2 -2
- package/src/lib/installers/mcp-installer.js +37 -5
- package/src/lib/phase-chain/phase-validator.js +22 -16
- package/src/lib/scope/impact-analyzer.js +106 -0
- package/src/lib/stack-filter.js +58 -0
- package/src/lib/tasks/task-parser.js +1 -1
- package/src/lib/validators/shared/emit-validator-dispatch.js +64 -0
- package/src/scripts/setup-infra.js +68 -18
- package/src/utils/agents-installer.js +51 -17
- package/src/utils/claude-md-injector.js +90 -0
- package/src/utils/file-copier.js +0 -1
- package/src/utils/hooks-installer.js +16 -5
- package/src/utils/skills-installer.js +67 -7
- package/CLAUDE.md +0 -98
- package/framework/memory/patterns-learned.md +0 -766
- package/framework/skills/level-0-meta/brainstorming/SKILL.md +0 -137
- package/framework/skills/level-0-meta/frontend-review/SKILL.md +0 -359
- package/framework/skills/level-0-meta/post-implementation/SKILL.md +0 -362
- package/framework/skills/level-0-meta/terminal-title/SKILL.md +0 -61
- package/framework/skills/level-0-meta/terminal-title/scripts/set_title.sh +0 -65
- package/framework/skills/level-1-workflows/phase-clarify/SKILL.md +0 -216
- package/framework/skills/level-1-workflows/phase-codebase-analysis/SKILL.md +0 -252
- package/framework/skills/level-1-workflows/phase-design/SKILL.md +0 -383
- package/framework/skills/level-1-workflows/phase-implement/SKILL.md +0 -492
- package/framework/skills/level-1-workflows/phase-setup/SKILL.md +0 -195
- package/framework/skills/level-1-workflows/phase-tasks/SKILL.md +0 -271
- package/framework/skills/level-1-workflows/phase-uiux/SKILL.md +0 -286
- package/src/commands/project/index.js +0 -8
- package/src/core/index.js +0 -10
- package/src/core/state/index.js +0 -8
- package/src/core/templates/index.js +0 -9
- package/src/core/templates/template-data-sources.js +0 -325
- package/src/core/workflows/index.js +0 -7
- package/src/lib/detectors/config-detector.js +0 -223
- package/src/lib/detectors/standards-generator.js +0 -335
- package/src/lib/detectors/structure-detector.js +0 -275
- package/src/lib/monitor/agent-resolver.js +0 -144
- package/src/lib/monitor/renderer.js +0 -230
- package/src/lib/orchestration/index.js +0 -7
- package/src/lib/orchestration/team-orchestrator.js +0 -404
- package/src/sanitizer/context-sanitizer.js +0 -221
- package/src/sanitizer/patterns.js +0 -163
- package/src/writer/file-writer.js +0 -86
- /package/framework/skills/level-0-meta/{brainstorming → morph-brainstorming}/references/proposal-example.md +0 -0
- /package/framework/skills/level-0-meta/{code-review → morph-code-review}/references/review-example.md +0 -0
- /package/framework/skills/level-0-meta/{code-review → morph-code-review}/references/review-guidelines.md +0 -0
- /package/framework/skills/level-0-meta/{code-review → morph-code-review}/scripts/scan-csharp.mjs +0 -0
- /package/framework/skills/level-0-meta/{code-review-nextjs → morph-code-review-nextjs}/references/review-example-nextjs.md +0 -0
- /package/framework/skills/level-0-meta/{code-review-nextjs → morph-code-review-nextjs}/scripts/scan-nextjs.mjs +0 -0
- /package/framework/skills/level-0-meta/{frontend-review → morph-frontend-review}/scripts/scan-accessibility.mjs +0 -0
- /package/framework/skills/level-0-meta/{post-implementation → morph-post-implementation}/scripts/detect-dev-server.mjs +0 -0
- /package/framework/skills/level-0-meta/{post-implementation → morph-post-implementation}/scripts/detect-stack.mjs +0 -0
- /package/framework/skills/level-1-workflows/{phase-clarify → morph-phase-clarify}/references/clarifications-example.md +0 -0
- /package/framework/skills/level-1-workflows/{phase-design → morph-phase-design}/references/architecture-analysis-guide.md +0 -0
- /package/framework/skills/level-1-workflows/{phase-design → morph-phase-design}/references/spec-authoring-guide.md +0 -0
- /package/framework/skills/level-1-workflows/{phase-design → morph-phase-design}/references/spec-example.md +0 -0
- /package/framework/skills/level-1-workflows/{phase-implement → morph-phase-implement}/references/recap-example.md +0 -0
- /package/framework/skills/level-1-workflows/{phase-implement → morph-phase-implement}/references/vsa-implementation-guide.md +0 -0
- /package/framework/skills/level-1-workflows/{phase-tasks → morph-phase-tasks}/references/task-planning-patterns.md +0 -0
- /package/framework/skills/level-1-workflows/{phase-tasks → morph-phase-tasks}/references/tasks-example.md +0 -0
|
@@ -1,335 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Standards Generator - Generates inferred-standards.md from detection results
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Generate inferred standards
|
|
7
|
-
* @param {Object} detectionResults - Results from all detectors
|
|
8
|
-
* @returns {Promise<Object>} Generated standards
|
|
9
|
-
*/
|
|
10
|
-
export async function generateStandards(detectionResults) {
|
|
11
|
-
const { structure, config, conversation } = detectionResults;
|
|
12
|
-
|
|
13
|
-
const standards = {
|
|
14
|
-
markdown: generateMarkdown(structure, config, conversation),
|
|
15
|
-
recommendations: generateRecommendations(structure, config, conversation),
|
|
16
|
-
gaps: identifyGaps(structure, config)
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
return standards;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Generate markdown content for inferred-standards.md
|
|
24
|
-
*/
|
|
25
|
-
function generateMarkdown(structure, config, conversation) {
|
|
26
|
-
const sections = [];
|
|
27
|
-
|
|
28
|
-
// Header
|
|
29
|
-
sections.push(`# Inferred Standards (Auto-generated)`);
|
|
30
|
-
sections.push(``);
|
|
31
|
-
sections.push(`> ⚠️ This file is auto-generated by MORPH-SPEC detection system.`);
|
|
32
|
-
sections.push(`> Manual edits will be overwritten. Create custom standards in \`overrides.md\`.`);
|
|
33
|
-
sections.push(``);
|
|
34
|
-
sections.push(`**Generated:** ${new Date().toISOString()}`);
|
|
35
|
-
sections.push(``);
|
|
36
|
-
sections.push(`---`);
|
|
37
|
-
sections.push(``);
|
|
38
|
-
|
|
39
|
-
// Stack Summary
|
|
40
|
-
sections.push(`## 🎯 Project Stack`);
|
|
41
|
-
sections.push(``);
|
|
42
|
-
sections.push(`- **Type**: ${structure?.stack || 'unknown'}`);
|
|
43
|
-
sections.push(`- **Language**: ${config?.language || 'unknown'}`);
|
|
44
|
-
sections.push(`- **Version**: ${config?.version || 'unknown'}`);
|
|
45
|
-
sections.push(`- **Architecture**: ${structure?.architecture || 'unknown'}`);
|
|
46
|
-
if (structure?.uiLibrary) {
|
|
47
|
-
sections.push(`- **UI Library**: ${structure.uiLibrary}`);
|
|
48
|
-
}
|
|
49
|
-
sections.push(``);
|
|
50
|
-
|
|
51
|
-
// Technologies
|
|
52
|
-
if (config?.technologies?.length > 0) {
|
|
53
|
-
sections.push(`## 🛠️ Technologies Detected`);
|
|
54
|
-
sections.push(``);
|
|
55
|
-
config.technologies.forEach(tech => {
|
|
56
|
-
sections.push(`- ${tech}`);
|
|
57
|
-
});
|
|
58
|
-
sections.push(``);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// Patterns
|
|
62
|
-
if (structure?.patterns?.length > 0) {
|
|
63
|
-
sections.push(`## 📐 Patterns in Use`);
|
|
64
|
-
sections.push(``);
|
|
65
|
-
structure.patterns.forEach(pattern => {
|
|
66
|
-
sections.push(`- ${pattern}`);
|
|
67
|
-
});
|
|
68
|
-
sections.push(``);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Coding Standards (inferred)
|
|
72
|
-
sections.push(`## 💻 Inferred Coding Standards`);
|
|
73
|
-
sections.push(``);
|
|
74
|
-
sections.push(generateCodingStandards(structure, config));
|
|
75
|
-
sections.push(``);
|
|
76
|
-
|
|
77
|
-
// Architecture Patterns
|
|
78
|
-
if (structure?.architecture !== 'unknown') {
|
|
79
|
-
sections.push(`## 🏗️ Architecture Pattern`);
|
|
80
|
-
sections.push(``);
|
|
81
|
-
sections.push(generateArchitectureSection(structure));
|
|
82
|
-
sections.push(``);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Dependencies
|
|
86
|
-
if (config?.dependencies?.length > 0) {
|
|
87
|
-
sections.push(`## 📦 Key Dependencies`);
|
|
88
|
-
sections.push(``);
|
|
89
|
-
const importantDeps = filterImportantDependencies(config.dependencies);
|
|
90
|
-
importantDeps.slice(0, 10).forEach(dep => {
|
|
91
|
-
sections.push(`- ${dep}`);
|
|
92
|
-
});
|
|
93
|
-
if (config.dependencies.length > 10) {
|
|
94
|
-
sections.push(`- ... and ${config.dependencies.length - 10} more`);
|
|
95
|
-
}
|
|
96
|
-
sections.push(``);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// User Preferences (from conversation)
|
|
100
|
-
if (conversation?.preferences && Object.keys(conversation.preferences).some(k => conversation.preferences[k])) {
|
|
101
|
-
sections.push(`## 🎨 User Preferences (from past decisions)`);
|
|
102
|
-
sections.push(``);
|
|
103
|
-
Object.entries(conversation.preferences).forEach(([key, value]) => {
|
|
104
|
-
if (value) {
|
|
105
|
-
sections.push(`- **${formatKey(key)}**: ${value}`);
|
|
106
|
-
}
|
|
107
|
-
});
|
|
108
|
-
sections.push(``);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return sections.join('\n');
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
/**
|
|
115
|
-
* Generate coding standards section
|
|
116
|
-
*/
|
|
117
|
-
function generateCodingStandards(structure, config) {
|
|
118
|
-
if (config?.language === 'csharp') {
|
|
119
|
-
return `### C# / .NET Conventions
|
|
120
|
-
|
|
121
|
-
Based on detected patterns in your codebase:
|
|
122
|
-
|
|
123
|
-
- **Naming**: PascalCase for classes, camelCase for variables
|
|
124
|
-
- **Async**: Methods with \`Async\` suffix
|
|
125
|
-
- **DI**: Constructor injection (${structure.patterns.includes('Dependency Injection') ? '✅ detected' : '⚠️ not detected'})
|
|
126
|
-
- **Tests**: ${structure.patterns.includes('Unit Tests') ? '✅ Present' : '⚠️ Not detected'}
|
|
127
|
-
|
|
128
|
-
**Recommendation**: Refer to \`.morph/framework/standards/coding.md\` for complete .NET standards.`;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
if (config?.language === 'javascript') {
|
|
132
|
-
const techLine = config.technologies?.length > 0
|
|
133
|
-
? `\n- **Framework**: ${config.technologies.join(', ')}`
|
|
134
|
-
: '';
|
|
135
|
-
|
|
136
|
-
return `### JavaScript / TypeScript Conventions
|
|
137
|
-
|
|
138
|
-
Based on detected patterns in your codebase:
|
|
139
|
-
|
|
140
|
-
- **Package Manager**: ${config.packageManager}${techLine}
|
|
141
|
-
|
|
142
|
-
**Recommendation**: Refer to framework standards for JavaScript best practices.`;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return 'No specific coding standards inferred. Check framework standards for guidance.';
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Generate architecture section
|
|
150
|
-
*/
|
|
151
|
-
function generateArchitectureSection(structure) {
|
|
152
|
-
const { architecture } = structure;
|
|
153
|
-
|
|
154
|
-
const descriptions = {
|
|
155
|
-
'cli-library': `### CLI / Library Architecture
|
|
156
|
-
|
|
157
|
-
Your project follows a CLI/Library pattern:
|
|
158
|
-
|
|
159
|
-
- ✅ **bin/** entry points detected
|
|
160
|
-
- ✅ **src/** source directory detected
|
|
161
|
-
- ✅ **package.json** present
|
|
162
|
-
|
|
163
|
-
**Key principles**:
|
|
164
|
-
- Commands exposed via bin/
|
|
165
|
-
- Core logic in src/commands/ and src/lib/
|
|
166
|
-
- Public API exported from src/index.js`,
|
|
167
|
-
|
|
168
|
-
'nextjs-app-router': `### Next.js App Router Architecture
|
|
169
|
-
|
|
170
|
-
Your project uses the Next.js App Router pattern:
|
|
171
|
-
|
|
172
|
-
- ✅ **app/** directory detected (React Server Components)
|
|
173
|
-
|
|
174
|
-
**Key principles**:
|
|
175
|
-
- Server Components by default
|
|
176
|
-
- Client Components with 'use client' directive
|
|
177
|
-
- Route handlers in app/api/`,
|
|
178
|
-
|
|
179
|
-
'express-mvc': `### Express MVC Architecture
|
|
180
|
-
|
|
181
|
-
Your project uses Express with MVC pattern:
|
|
182
|
-
|
|
183
|
-
- ✅ **routes/** detected
|
|
184
|
-
- ✅ **controllers/** detected`,
|
|
185
|
-
|
|
186
|
-
'clean-architecture': `### Clean Architecture
|
|
187
|
-
|
|
188
|
-
Your project follows Clean Architecture pattern:
|
|
189
|
-
|
|
190
|
-
- ✅ **Domain** layer detected (core business logic)
|
|
191
|
-
- ✅ **Application** layer detected (use cases)
|
|
192
|
-
- ✅ **Infrastructure** layer detected (implementations)
|
|
193
|
-
|
|
194
|
-
**Key principles**:
|
|
195
|
-
- Domain has no dependencies
|
|
196
|
-
- Application depends on Domain
|
|
197
|
-
- Infrastructure implements Application interfaces`,
|
|
198
|
-
|
|
199
|
-
'cqrs': `### CQRS Pattern
|
|
200
|
-
|
|
201
|
-
Your project uses Command Query Responsibility Segregation:
|
|
202
|
-
|
|
203
|
-
- ✅ **Commands** detected (write operations)
|
|
204
|
-
- ✅ **Queries** detected (read operations)
|
|
205
|
-
|
|
206
|
-
**Key principles**:
|
|
207
|
-
- Separate read and write models
|
|
208
|
-
- Commands return void or Task
|
|
209
|
-
- Queries return data`,
|
|
210
|
-
|
|
211
|
-
'mvc': `### MVC Pattern
|
|
212
|
-
|
|
213
|
-
Your project uses Model-View-Controller pattern:
|
|
214
|
-
|
|
215
|
-
- ✅ **Controllers** detected
|
|
216
|
-
- ✅ **Models** detected
|
|
217
|
-
- ✅ **Views** detected`
|
|
218
|
-
};
|
|
219
|
-
|
|
220
|
-
return descriptions[architecture] || `Architecture: ${architecture}`;
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
/**
|
|
224
|
-
* Generate recommendations
|
|
225
|
-
*/
|
|
226
|
-
function generateRecommendations(structure, config, conversation) {
|
|
227
|
-
const recommendations = [];
|
|
228
|
-
|
|
229
|
-
// Recommend based on stack
|
|
230
|
-
if (structure?.stack === 'blazor') {
|
|
231
|
-
if (!structure.uiLibrary) {
|
|
232
|
-
recommendations.push('Consider adding Fluent UI Blazor or MudBlazor for consistent UI components');
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
if (!structure.patterns.includes('AI Agents') && config?.technologies?.includes('Microsoft Agent Framework')) {
|
|
236
|
-
recommendations.push('Setup detected Agent Framework but no agents found - check .morph/framework/standards/agent-framework-setup.md');
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
if (structure?.stack === 'nodejs' || config?.language === 'javascript') {
|
|
241
|
-
if (!structure?.patterns?.includes('Unit Tests')) {
|
|
242
|
-
recommendations.push('No unit tests detected - consider adding test coverage with Jest or Vitest');
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
if (structure?.architecture === 'unknown') {
|
|
246
|
-
recommendations.push('No clear architecture detected - consider organizing code into src/commands/, src/lib/, src/core/');
|
|
247
|
-
}
|
|
248
|
-
} else {
|
|
249
|
-
// Recommend tests (generic / .NET)
|
|
250
|
-
if (!structure?.patterns?.includes('Unit Tests')) {
|
|
251
|
-
recommendations.push('No unit tests detected - consider adding test project');
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
// Recommend DI (only meaningful for C# / .NET)
|
|
255
|
-
if (config?.language === 'csharp' && !structure?.patterns?.includes('Dependency Injection')) {
|
|
256
|
-
recommendations.push('Consider implementing Dependency Injection pattern');
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
// Architecture recommendations (.NET)
|
|
260
|
-
if (structure?.architecture === 'unknown' && structure?.folders?.hasServices) {
|
|
261
|
-
recommendations.push('Service layer detected but no clear architecture - consider Clean Architecture or CQRS');
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return recommendations;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* Identify gaps between framework and project
|
|
270
|
-
*/
|
|
271
|
-
function identifyGaps(structure, config) {
|
|
272
|
-
const gaps = [];
|
|
273
|
-
|
|
274
|
-
// Check for missing patterns
|
|
275
|
-
const expectedPatterns = {
|
|
276
|
-
blazor: ['Service Layer', 'Repository Pattern', 'Dependency Injection'],
|
|
277
|
-
nextjs: ['API Routes', 'Components'],
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
const expected = expectedPatterns[structure?.stack];
|
|
281
|
-
if (expected) {
|
|
282
|
-
expected.forEach(pattern => {
|
|
283
|
-
if (!structure?.patterns?.includes(pattern)) {
|
|
284
|
-
gaps.push(`Missing: ${pattern}`);
|
|
285
|
-
}
|
|
286
|
-
});
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
return gaps;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Filter important dependencies
|
|
294
|
-
*/
|
|
295
|
-
function filterImportantDependencies(deps) {
|
|
296
|
-
const important = deps.filter(dep => {
|
|
297
|
-
// .NET Framework packages
|
|
298
|
-
if (dep.includes('Microsoft.') || dep.includes('System.')) return true;
|
|
299
|
-
// Blazor UI libraries
|
|
300
|
-
if (dep.includes('Blazor') || dep.includes('FluentUI') || dep.includes('Mud')) return true;
|
|
301
|
-
// .NET common tools
|
|
302
|
-
if (dep.includes('Hangfire') || dep.includes('Serilog') || dep.includes('AutoMapper')) return true;
|
|
303
|
-
// AI/ML (.NET)
|
|
304
|
-
if (dep.includes('Agents') || dep.includes('AI') || dep.includes('OpenAI')) return true;
|
|
305
|
-
// JS: frontend frameworks
|
|
306
|
-
if (['next', 'react', 'react-dom', 'vue', 'nuxt', 'svelte', 'astro'].includes(dep)) return true;
|
|
307
|
-
// JS: backend frameworks
|
|
308
|
-
if (['express', 'fastify', 'hono', 'koa', 'nestjs', '@nestjs/core'].includes(dep)) return true;
|
|
309
|
-
// JS: databases / ORMs
|
|
310
|
-
if (['prisma', '@prisma/client', 'supabase', '@supabase/supabase-js', 'drizzle-orm', 'mongoose', 'typeorm'].includes(dep)) return true;
|
|
311
|
-
// JS: auth
|
|
312
|
-
if (['next-auth', 'clerk', '@clerk/nextjs', 'lucia', 'better-auth'].includes(dep)) return true;
|
|
313
|
-
// JS: validation / schema
|
|
314
|
-
if (['zod', 'yup', 'joi', 'valibot'].includes(dep)) return true;
|
|
315
|
-
// JS: testing
|
|
316
|
-
if (['vitest', 'jest', '@jest/core', 'mocha', 'cypress', 'playwright'].includes(dep)) return true;
|
|
317
|
-
// JS: UI / styling
|
|
318
|
-
if (['tailwindcss', '@mui/material', 'shadcn-ui', 'radix-ui', 'chakra-ui'].includes(dep)) return true;
|
|
319
|
-
// JS: AI
|
|
320
|
-
if (dep.includes('openai') || dep.includes('anthropic') || dep.includes('langchain') || dep.includes('ai')) return true;
|
|
321
|
-
return false;
|
|
322
|
-
});
|
|
323
|
-
|
|
324
|
-
return important.length > 0 ? important : deps;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
/**
|
|
328
|
-
* Format key for display
|
|
329
|
-
*/
|
|
330
|
-
function formatKey(key) {
|
|
331
|
-
return key
|
|
332
|
-
.replace(/([A-Z])/g, ' $1')
|
|
333
|
-
.replace(/^./, str => str.toUpperCase())
|
|
334
|
-
.trim();
|
|
335
|
-
}
|
|
@@ -1,275 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Structure Detector - Analyzes folder structure to infer stack and architecture
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { glob } from 'glob';
|
|
6
|
-
import { join } from 'path';
|
|
7
|
-
import { existsSync } from 'fs';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Detect project structure
|
|
11
|
-
* @param {string} projectPath - Project root path
|
|
12
|
-
* @returns {Promise<Object>} Structure detection results
|
|
13
|
-
*/
|
|
14
|
-
export async function detectStructure(projectPath) {
|
|
15
|
-
const result = {
|
|
16
|
-
stack: 'unknown',
|
|
17
|
-
architecture: 'unknown',
|
|
18
|
-
uiLibrary: null,
|
|
19
|
-
patterns: [],
|
|
20
|
-
folders: {
|
|
21
|
-
hasPages: false,
|
|
22
|
-
hasComponents: false,
|
|
23
|
-
hasServices: false,
|
|
24
|
-
hasRepositories: false,
|
|
25
|
-
hasAgents: false
|
|
26
|
-
}
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
// Detect stack
|
|
30
|
-
result.stack = await detectStack(projectPath);
|
|
31
|
-
|
|
32
|
-
// Detect architecture pattern
|
|
33
|
-
result.architecture = await detectArchitecture(projectPath);
|
|
34
|
-
|
|
35
|
-
// Detect UI library
|
|
36
|
-
if (result.stack === 'blazor') {
|
|
37
|
-
result.uiLibrary = await detectUILibrary(projectPath);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Detect patterns
|
|
41
|
-
result.patterns = await detectPatterns(projectPath);
|
|
42
|
-
|
|
43
|
-
// Analyze folders
|
|
44
|
-
result.folders = await analyzeFolders(projectPath);
|
|
45
|
-
|
|
46
|
-
return result;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Detect stack type
|
|
51
|
-
*/
|
|
52
|
-
async function detectStack(projectPath) {
|
|
53
|
-
// Order matters: more specific patterns first
|
|
54
|
-
const patterns = {
|
|
55
|
-
blazor: [
|
|
56
|
-
'**/*.razor',
|
|
57
|
-
'**/Pages/**/*.razor',
|
|
58
|
-
'**/Components/**/*.razor'
|
|
59
|
-
],
|
|
60
|
-
nextjs: [
|
|
61
|
-
'**/next.config.js',
|
|
62
|
-
'**/next.config.mjs',
|
|
63
|
-
'**/next.config.ts',
|
|
64
|
-
'pages/**/*.tsx',
|
|
65
|
-
'app/**/*.tsx',
|
|
66
|
-
'**/pages/**/*.tsx',
|
|
67
|
-
'**/app/**/*.tsx'
|
|
68
|
-
],
|
|
69
|
-
react: [
|
|
70
|
-
'src/App.jsx',
|
|
71
|
-
'src/App.tsx',
|
|
72
|
-
'vite.config.js',
|
|
73
|
-
'craco.config.js'
|
|
74
|
-
],
|
|
75
|
-
vue: [
|
|
76
|
-
'vite.config.js', // Vue 3 + Vite
|
|
77
|
-
'vue.config.js', // Vue 2
|
|
78
|
-
'src/App.vue'
|
|
79
|
-
],
|
|
80
|
-
dotnet: [
|
|
81
|
-
'**/*.csproj',
|
|
82
|
-
'**/Program.cs'
|
|
83
|
-
],
|
|
84
|
-
typescript: [
|
|
85
|
-
'tsconfig.json',
|
|
86
|
-
'src/**/*.ts'
|
|
87
|
-
],
|
|
88
|
-
nodejs: [
|
|
89
|
-
'package.json' // Fallback: generic Node.js
|
|
90
|
-
],
|
|
91
|
-
python: [
|
|
92
|
-
'requirements.txt',
|
|
93
|
-
'pyproject.toml',
|
|
94
|
-
'setup.py'
|
|
95
|
-
],
|
|
96
|
-
go: [
|
|
97
|
-
'go.mod',
|
|
98
|
-
'main.go'
|
|
99
|
-
]
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
const globIgnore = ['framework/**', 'test/**', 'node_modules/**', '.morph/**'];
|
|
103
|
-
|
|
104
|
-
for (const [stack, globs] of Object.entries(patterns)) {
|
|
105
|
-
for (const pattern of globs) {
|
|
106
|
-
const files = await glob(pattern, { cwd: projectPath, nodir: true, ignore: globIgnore });
|
|
107
|
-
if (files.length > 0) {
|
|
108
|
-
return stack;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
return 'unknown';
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Detect architecture pattern
|
|
118
|
-
*/
|
|
119
|
-
async function detectArchitecture(projectPath) {
|
|
120
|
-
const globIgnore = ['framework/**', 'test/**', 'node_modules/**', '.morph/**'];
|
|
121
|
-
|
|
122
|
-
const checks = [
|
|
123
|
-
// .NET: Clean Architecture
|
|
124
|
-
{
|
|
125
|
-
pattern: 'clean-architecture',
|
|
126
|
-
indicators: [
|
|
127
|
-
existsSync(join(projectPath, 'src', 'Application')),
|
|
128
|
-
existsSync(join(projectPath, 'src', 'Domain')),
|
|
129
|
-
existsSync(join(projectPath, 'src', 'Infrastructure'))
|
|
130
|
-
]
|
|
131
|
-
},
|
|
132
|
-
// .NET: CQRS
|
|
133
|
-
{
|
|
134
|
-
pattern: 'cqrs',
|
|
135
|
-
indicators: [
|
|
136
|
-
await glob('**/Commands/**/*.cs', { cwd: projectPath, ignore: globIgnore }).then(f => f.length > 0),
|
|
137
|
-
await glob('**/Queries/**/*.cs', { cwd: projectPath, ignore: globIgnore }).then(f => f.length > 0)
|
|
138
|
-
]
|
|
139
|
-
},
|
|
140
|
-
// .NET: MVC
|
|
141
|
-
{
|
|
142
|
-
pattern: 'mvc',
|
|
143
|
-
indicators: [
|
|
144
|
-
existsSync(join(projectPath, 'Controllers')),
|
|
145
|
-
existsSync(join(projectPath, 'Models')),
|
|
146
|
-
existsSync(join(projectPath, 'Views'))
|
|
147
|
-
]
|
|
148
|
-
},
|
|
149
|
-
// JS: CLI / Library (bin + src + lib)
|
|
150
|
-
{
|
|
151
|
-
pattern: 'cli-library',
|
|
152
|
-
indicators: [
|
|
153
|
-
existsSync(join(projectPath, 'bin')),
|
|
154
|
-
existsSync(join(projectPath, 'src')),
|
|
155
|
-
existsSync(join(projectPath, 'package.json'))
|
|
156
|
-
]
|
|
157
|
-
},
|
|
158
|
-
// JS: Next.js App Router
|
|
159
|
-
{
|
|
160
|
-
pattern: 'nextjs-app-router',
|
|
161
|
-
indicators: [
|
|
162
|
-
existsSync(join(projectPath, 'app')),
|
|
163
|
-
await glob('app/**/*.{js,ts,jsx,tsx}', { cwd: projectPath, ignore: globIgnore }).then(f => f.length > 0)
|
|
164
|
-
]
|
|
165
|
-
},
|
|
166
|
-
// JS: Express MVC
|
|
167
|
-
{
|
|
168
|
-
pattern: 'express-mvc',
|
|
169
|
-
indicators: [
|
|
170
|
-
existsSync(join(projectPath, 'src', 'routes')) || existsSync(join(projectPath, 'routes')),
|
|
171
|
-
existsSync(join(projectPath, 'src', 'controllers')) || existsSync(join(projectPath, 'controllers'))
|
|
172
|
-
]
|
|
173
|
-
}
|
|
174
|
-
];
|
|
175
|
-
|
|
176
|
-
for (const { pattern, indicators } of checks) {
|
|
177
|
-
if (indicators.every(Boolean)) {
|
|
178
|
-
return pattern;
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
return 'unknown';
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Detect UI library (Blazor projects)
|
|
187
|
-
*/
|
|
188
|
-
async function detectUILibrary(projectPath) {
|
|
189
|
-
const csprojFiles = await glob('**/*.csproj', { cwd: projectPath });
|
|
190
|
-
|
|
191
|
-
for (const csprojFile of csprojFiles) {
|
|
192
|
-
const content = await import('fs').then(fs =>
|
|
193
|
-
fs.promises.readFile(join(projectPath, csprojFile), 'utf8')
|
|
194
|
-
);
|
|
195
|
-
|
|
196
|
-
if (content.includes('FluentUI.Blazor') || content.includes('Microsoft.FluentUI.AspNetCore.Components')) {
|
|
197
|
-
return 'fluent-ui';
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (content.includes('MudBlazor')) {
|
|
201
|
-
return 'mudblazor';
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
return null;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Detect common patterns
|
|
210
|
-
*/
|
|
211
|
-
async function detectPatterns(projectPath) {
|
|
212
|
-
const patterns = [];
|
|
213
|
-
// Ignore template/vendor directories; keep test/ accessible for JS test detection
|
|
214
|
-
const globIgnore = ['framework/**', 'test/fixtures/**', 'node_modules/**', '.morph/**'];
|
|
215
|
-
|
|
216
|
-
// C# / .NET patterns
|
|
217
|
-
const dotnetChecks = [
|
|
218
|
-
{ name: 'Repository Pattern', glob: '**/*Repository.cs' },
|
|
219
|
-
{ name: 'Service Layer', glob: '**/*Service.cs' },
|
|
220
|
-
{ name: 'DTOs', glob: '**/*Dto.cs' },
|
|
221
|
-
{ name: 'Entity Framework', glob: '**/Migrations/**/*.cs' },
|
|
222
|
-
{ name: 'Dependency Injection', glob: '**/DependencyInjection.cs' },
|
|
223
|
-
{ name: 'Hangfire Jobs', glob: '**/*Job.cs' },
|
|
224
|
-
{ name: 'AI Agents', glob: '**/*Agent.cs' },
|
|
225
|
-
{ name: 'Unit Tests', glob: '**/*.Tests/**/*.cs' }
|
|
226
|
-
];
|
|
227
|
-
|
|
228
|
-
// JavaScript / TypeScript patterns
|
|
229
|
-
const jsChecks = [
|
|
230
|
-
{ name: 'Service Layer', glob: 'src/**/*Service.js' },
|
|
231
|
-
{ name: 'Service Layer', glob: 'src/**/*Service.ts' },
|
|
232
|
-
{ name: 'Repository Pattern', glob: 'src/**/*Repository.js' },
|
|
233
|
-
{ name: 'Repository Pattern', glob: 'src/**/*Repository.ts' },
|
|
234
|
-
{ name: 'API Routes', glob: 'src/**/routes/**/*.{js,ts}' },
|
|
235
|
-
{ name: 'API Routes', glob: 'src/commands/**/*.{js,ts}' },
|
|
236
|
-
{ name: 'Unit Tests', glob: 'test/**/*.test.{js,ts}' },
|
|
237
|
-
{ name: 'Unit Tests', glob: 'src/**/*.test.{js,ts}' },
|
|
238
|
-
{ name: 'Unit Tests', glob: 'src/**/*.spec.{js,ts}' }
|
|
239
|
-
];
|
|
240
|
-
|
|
241
|
-
const allChecks = [...dotnetChecks, ...jsChecks];
|
|
242
|
-
const seen = new Set();
|
|
243
|
-
|
|
244
|
-
for (const { name, glob: pattern } of allChecks) {
|
|
245
|
-
if (seen.has(name)) continue;
|
|
246
|
-
const files = await glob(pattern, { cwd: projectPath, nodir: true, ignore: globIgnore });
|
|
247
|
-
if (files.length > 0) {
|
|
248
|
-
patterns.push(name);
|
|
249
|
-
seen.add(name);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
return patterns;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
/**
|
|
257
|
-
* Analyze folder structure
|
|
258
|
-
*/
|
|
259
|
-
async function analyzeFolders(projectPath) {
|
|
260
|
-
const folders = {
|
|
261
|
-
hasPages: false,
|
|
262
|
-
hasComponents: false,
|
|
263
|
-
hasServices: false,
|
|
264
|
-
hasRepositories: false,
|
|
265
|
-
hasAgents: false
|
|
266
|
-
};
|
|
267
|
-
|
|
268
|
-
folders.hasPages = await glob('**/Pages/**/*', { cwd: projectPath }).then(f => f.length > 0);
|
|
269
|
-
folders.hasComponents = await glob('**/Components/**/*', { cwd: projectPath }).then(f => f.length > 0);
|
|
270
|
-
folders.hasServices = await glob('**/Services/**/*', { cwd: projectPath }).then(f => f.length > 0);
|
|
271
|
-
folders.hasRepositories = await glob('**/Repositories/**/*', { cwd: projectPath }).then(f => f.length > 0);
|
|
272
|
-
folders.hasAgents = await glob('**/Agents/**/*', { cwd: projectPath }).then(f => f.length > 0);
|
|
273
|
-
|
|
274
|
-
return folders;
|
|
275
|
-
}
|