@polymorphism-tech/morph-spec 4.9.0 → 4.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +99 -98
- package/framework/agents.json +37 -7
- package/framework/commands/commit.md +166 -0
- package/framework/commands/morph-apply.md +13 -2
- package/framework/commands/morph-archive.md +8 -2
- package/framework/commands/morph-infra.md +6 -0
- package/framework/commands/morph-preflight.md +6 -0
- package/framework/commands/morph-proposal.md +56 -7
- package/framework/commands/morph-status.md +6 -0
- package/framework/commands/morph-troubleshoot.md +6 -0
- 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/morph-workflow.md +88 -86
- package/framework/skills/level-0-meta/mcp-registry.json +86 -51
- package/framework/skills/level-0-meta/{brainstorming → morph-brainstorming}/SKILL.md +13 -16
- package/framework/skills/level-0-meta/{code-review → morph-code-review}/SKILL.md +1 -1
- package/framework/skills/level-0-meta/{code-review-nextjs → morph-code-review-nextjs}/SKILL.md +2 -2
- package/framework/skills/level-0-meta/{frontend-review → morph-frontend-review}/SKILL.md +5 -5
- package/framework/skills/level-0-meta/morph-init/SKILL.md +72 -7
- package/framework/skills/level-0-meta/{post-implementation → morph-post-implementation}/SKILL.md +9 -9
- package/framework/skills/level-0-meta/morph-replicate/SKILL.md +1 -1
- package/framework/skills/level-0-meta/{terminal-title → morph-terminal-title}/SKILL.md +1 -1
- package/framework/skills/level-0-meta/{tool-usage-guide → morph-tool-usage-guide}/SKILL.md +2 -3
- 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 +1 -1
- 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 +238 -0
- package/framework/skills/level-1-workflows/{phase-codebase-analysis → morph-phase-codebase-analysis}/SKILL.md +251 -251
- package/framework/skills/level-1-workflows/morph-phase-design/SKILL.md +507 -0
- package/framework/skills/level-1-workflows/{phase-implement → morph-phase-implement}/SKILL.md +590 -491
- 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 +254 -0
- package/framework/skills/level-1-workflows/{phase-setup → morph-phase-setup}/SKILL.md +237 -194
- package/framework/skills/level-1-workflows/{phase-tasks → morph-phase-tasks}/SKILL.md +307 -270
- package/framework/skills/level-1-workflows/{phase-tasks → morph-phase-tasks}/scripts/validate-tasks.mjs +3 -3
- package/framework/skills/level-1-workflows/{phase-uiux → morph-phase-uiux}/SKILL.md +320 -285
- package/framework/skills/level-1-workflows/morph-scope-escalation/SKILL.md +97 -0
- package/framework/standards/integration/mcp/mcp-tools.md +25 -7
- package/framework/templates/docs/onboarding.md +2 -2
- package/package.json +1 -2
- 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 +19 -5
- 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/tasks/task-parser.js +1 -1
- package/src/lib/validators/shared/emit-validator-dispatch.js +64 -0
- package/src/scripts/setup-infra.js +15 -0
- package/src/utils/agents-installer.js +32 -12
- package/src/utils/file-copier.js +0 -1
- package/src/utils/hooks-installer.js +15 -1
- package/framework/skills/level-1-workflows/phase-clarify/SKILL.md +0 -216
- package/framework/skills/level-1-workflows/phase-design/SKILL.md +0 -383
- 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-0-meta/{simulation-checklist → morph-simulation-checklist}/SKILL.md +0 -0
- /package/framework/skills/level-0-meta/{terminal-title → morph-terminal-title}/scripts/set_title.sh +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,325 +0,0 @@
|
|
|
1
|
-
import { glob } from 'glob';
|
|
2
|
-
import { readFileSync, existsSync } from 'fs';
|
|
3
|
-
import { join } from 'path';
|
|
4
|
-
import { execSync } from 'child_process';
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Template Data Sources - Inject dynamic MCP data into templates
|
|
8
|
-
*
|
|
9
|
-
* Provides project context, compliance status, and recent activity
|
|
10
|
-
* for enriching template placeholders.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Get project structure statistics
|
|
15
|
-
* @param {string} projectPath - Project root path
|
|
16
|
-
* @returns {Promise<Object>} Project structure data
|
|
17
|
-
*/
|
|
18
|
-
export async function getProjectStructure(projectPath = process.cwd()) {
|
|
19
|
-
try {
|
|
20
|
-
// Find all files (excluding common ignore patterns)
|
|
21
|
-
const files = await glob('**/*', {
|
|
22
|
-
cwd: projectPath,
|
|
23
|
-
ignore: [
|
|
24
|
-
'node_modules/**',
|
|
25
|
-
'bin/**',
|
|
26
|
-
'obj/**',
|
|
27
|
-
'.git/**',
|
|
28
|
-
'.morph/**',
|
|
29
|
-
'dist/**',
|
|
30
|
-
'build/**',
|
|
31
|
-
'*.log'
|
|
32
|
-
],
|
|
33
|
-
nodir: true
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// Calculate language stats
|
|
37
|
-
const languageStats = {};
|
|
38
|
-
files.forEach(file => {
|
|
39
|
-
const ext = file.split('.').pop();
|
|
40
|
-
languageStats[ext] = (languageStats[ext] || 0) + 1;
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
// Get test coverage if available
|
|
44
|
-
let testCoverage = null;
|
|
45
|
-
const coveragePath = join(projectPath, 'coverage/coverage-summary.json');
|
|
46
|
-
if (existsSync(coveragePath)) {
|
|
47
|
-
const coverageData = JSON.parse(readFileSync(coveragePath, 'utf8'));
|
|
48
|
-
testCoverage = coverageData.total?.lines?.pct || null;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Get last commit info
|
|
52
|
-
let lastCommit = null;
|
|
53
|
-
try {
|
|
54
|
-
const gitLog = execSync('git log -1 --format="%H|%an|%ar|%s"', {
|
|
55
|
-
cwd: projectPath,
|
|
56
|
-
encoding: 'utf8',
|
|
57
|
-
stdio: 'pipe'
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
const [hash, author, time, message] = gitLog.trim().split('|');
|
|
61
|
-
lastCommit = { hash: hash.substring(0, 7), author, time, message };
|
|
62
|
-
} catch {
|
|
63
|
-
// Git not available or not a repo
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
return {
|
|
67
|
-
totalFiles: files.length,
|
|
68
|
-
languageStats,
|
|
69
|
-
testCoverage: testCoverage ? Math.round(testCoverage) : null,
|
|
70
|
-
lastCommit,
|
|
71
|
-
filesByExtension: {
|
|
72
|
-
cs: languageStats.cs || 0,
|
|
73
|
-
js: languageStats.js || 0,
|
|
74
|
-
ts: languageStats.ts || 0,
|
|
75
|
-
tsx: languageStats.tsx || 0,
|
|
76
|
-
razor: languageStats.razor || 0,
|
|
77
|
-
css: languageStats.css || 0,
|
|
78
|
-
md: languageStats.md || 0
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
} catch (error) {
|
|
82
|
-
return {
|
|
83
|
-
error: error.message,
|
|
84
|
-
totalFiles: 0,
|
|
85
|
-
testCoverage: null
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Get dependency information
|
|
92
|
-
* @param {string} projectPath - Project root path
|
|
93
|
-
* @returns {Promise<Object>} Dependency data
|
|
94
|
-
*/
|
|
95
|
-
export async function getDependencyInfo(projectPath = process.cwd()) {
|
|
96
|
-
const dependencies = {
|
|
97
|
-
nuget: [],
|
|
98
|
-
npm: [],
|
|
99
|
-
outdated: []
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
try {
|
|
103
|
-
// Check for NuGet packages (C# projects)
|
|
104
|
-
const csprojFiles = await glob('**/*.csproj', {
|
|
105
|
-
cwd: projectPath,
|
|
106
|
-
ignore: ['**/bin/**', '**/obj/**']
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
if (csprojFiles.length > 0) {
|
|
110
|
-
const csprojPath = join(projectPath, csprojFiles[0]);
|
|
111
|
-
const csprojContent = readFileSync(csprojPath, 'utf8');
|
|
112
|
-
|
|
113
|
-
// Extract PackageReference elements
|
|
114
|
-
const packageRegex = /<PackageReference\s+Include="([^"]+)"\s+Version="([^"]+)"/g;
|
|
115
|
-
let match;
|
|
116
|
-
|
|
117
|
-
while ((match = packageRegex.exec(csprojContent)) !== null) {
|
|
118
|
-
dependencies.nuget.push({
|
|
119
|
-
name: match[1],
|
|
120
|
-
version: match[2]
|
|
121
|
-
});
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Check for npm packages
|
|
126
|
-
const packageJsonPath = join(projectPath, 'package.json');
|
|
127
|
-
if (existsSync(packageJsonPath)) {
|
|
128
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
129
|
-
|
|
130
|
-
const allDeps = {
|
|
131
|
-
...packageJson.dependencies,
|
|
132
|
-
...packageJson.devDependencies
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
Object.entries(allDeps).forEach(([name, version]) => {
|
|
136
|
-
dependencies.npm.push({ name, version });
|
|
137
|
-
});
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
} catch (error) {
|
|
141
|
-
dependencies.error = error.message;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
return dependencies;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Get compliance status from validators
|
|
149
|
-
* @param {string} projectPath - Project root path
|
|
150
|
-
* @returns {Promise<Object>} Compliance data
|
|
151
|
-
*/
|
|
152
|
-
export async function getComplianceStatus(projectPath = process.cwd()) {
|
|
153
|
-
const compliance = {
|
|
154
|
-
architectureViolations: 0,
|
|
155
|
-
packageConflicts: 0,
|
|
156
|
-
designSystemCompliance: 100,
|
|
157
|
-
securityIssues: 0,
|
|
158
|
-
overall: 100
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
try {
|
|
162
|
-
// Run validators if available
|
|
163
|
-
const validators = ['architecture', 'packages', 'design-system', 'security'];
|
|
164
|
-
|
|
165
|
-
for (const validator of validators) {
|
|
166
|
-
try {
|
|
167
|
-
const result = execSync(
|
|
168
|
-
`node bin/validate.js ${validator} --json`,
|
|
169
|
-
{
|
|
170
|
-
cwd: projectPath,
|
|
171
|
-
encoding: 'utf8',
|
|
172
|
-
stdio: 'pipe'
|
|
173
|
-
}
|
|
174
|
-
);
|
|
175
|
-
|
|
176
|
-
const parsed = JSON.parse(result);
|
|
177
|
-
|
|
178
|
-
if (validator === 'architecture') {
|
|
179
|
-
compliance.architectureViolations = parsed.errors || 0;
|
|
180
|
-
} else if (validator === 'packages') {
|
|
181
|
-
compliance.packageConflicts = parsed.errors || 0;
|
|
182
|
-
} else if (validator === 'design-system') {
|
|
183
|
-
const total = parsed.total || 100;
|
|
184
|
-
const errors = parsed.errors || 0;
|
|
185
|
-
compliance.designSystemCompliance = Math.round(((total - errors) / total) * 100);
|
|
186
|
-
} else if (validator === 'security') {
|
|
187
|
-
compliance.securityIssues = parsed.errors || 0;
|
|
188
|
-
}
|
|
189
|
-
} catch {
|
|
190
|
-
// Validator not available or failed - skip
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// Calculate overall compliance score
|
|
195
|
-
const violations = compliance.architectureViolations +
|
|
196
|
-
compliance.packageConflicts +
|
|
197
|
-
compliance.securityIssues;
|
|
198
|
-
|
|
199
|
-
compliance.overall = Math.max(0, 100 - (violations * 5));
|
|
200
|
-
|
|
201
|
-
} catch (error) {
|
|
202
|
-
compliance.error = error.message;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
return compliance;
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/**
|
|
209
|
-
* Get recent activity and history
|
|
210
|
-
* @param {string} projectPath - Project root path
|
|
211
|
-
* @returns {Promise<Object>} Activity data
|
|
212
|
-
*/
|
|
213
|
-
export async function getRecentActivity(projectPath = process.cwd()) {
|
|
214
|
-
const activity = {
|
|
215
|
-
lastFeature: null,
|
|
216
|
-
recentCommits: [],
|
|
217
|
-
activeBranches: [],
|
|
218
|
-
lastDeployment: null
|
|
219
|
-
};
|
|
220
|
-
|
|
221
|
-
try {
|
|
222
|
-
// Check state.json for last feature
|
|
223
|
-
const statePath = join(projectPath, '.morph/state.json');
|
|
224
|
-
if (existsSync(statePath)) {
|
|
225
|
-
const state = JSON.parse(readFileSync(statePath, 'utf8'));
|
|
226
|
-
|
|
227
|
-
// Find most recently updated feature
|
|
228
|
-
let lastFeature = null;
|
|
229
|
-
let lastTimestamp = null;
|
|
230
|
-
|
|
231
|
-
Object.entries(state.features || {}).forEach(([name, feature]) => {
|
|
232
|
-
const updatedAt = feature.updatedAt || feature.createdAt;
|
|
233
|
-
if (updatedAt && (!lastTimestamp || updatedAt > lastTimestamp)) {
|
|
234
|
-
lastTimestamp = updatedAt;
|
|
235
|
-
lastFeature = name;
|
|
236
|
-
}
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
activity.lastFeature = lastFeature;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
// Get recent commits
|
|
243
|
-
try {
|
|
244
|
-
const gitLog = execSync('git log -5 --format="%h|%an|%ar|%s"', {
|
|
245
|
-
cwd: projectPath,
|
|
246
|
-
encoding: 'utf8',
|
|
247
|
-
stdio: 'pipe'
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
activity.recentCommits = gitLog.trim().split('\n').map(line => {
|
|
251
|
-
const [hash, author, time, message] = line.split('|');
|
|
252
|
-
return { hash, author, time, message };
|
|
253
|
-
});
|
|
254
|
-
} catch {
|
|
255
|
-
// Git not available
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// Get active branches
|
|
259
|
-
try {
|
|
260
|
-
const branches = execSync('git branch -a', {
|
|
261
|
-
cwd: projectPath,
|
|
262
|
-
encoding: 'utf8',
|
|
263
|
-
stdio: 'pipe'
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
activity.activeBranches = branches
|
|
267
|
-
.split('\n')
|
|
268
|
-
.map(b => b.trim().replace(/^\*\s+/, ''))
|
|
269
|
-
.filter(b => b && !b.includes('->'));
|
|
270
|
-
} catch {
|
|
271
|
-
// Git not available
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
} catch (error) {
|
|
275
|
-
activity.error = error.message;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
return activity;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Get all template data sources combined
|
|
283
|
-
* @param {string} projectPath - Project root path
|
|
284
|
-
* @returns {Promise<Object>} All data sources
|
|
285
|
-
*/
|
|
286
|
-
export async function getAllTemplatePlaceholders(projectPath = process.cwd()) {
|
|
287
|
-
const [structure, dependencies, compliance, activity] = await Promise.all([
|
|
288
|
-
getProjectStructure(projectPath),
|
|
289
|
-
getDependencyInfo(projectPath),
|
|
290
|
-
getComplianceStatus(projectPath),
|
|
291
|
-
getRecentActivity(projectPath)
|
|
292
|
-
]);
|
|
293
|
-
|
|
294
|
-
return {
|
|
295
|
-
MCP_PROJECT_FILES: structure.totalFiles,
|
|
296
|
-
MCP_TEST_COVERAGE: structure.testCoverage || 'N/A',
|
|
297
|
-
MCP_COMPLIANCE_SCORE: compliance.overall,
|
|
298
|
-
MCP_LAST_FEATURE: activity.lastFeature || 'None',
|
|
299
|
-
MCP_LAST_COMMIT: structure.lastCommit?.message || 'Unknown',
|
|
300
|
-
MCP_LAST_COMMIT_AUTHOR: structure.lastCommit?.author || 'Unknown',
|
|
301
|
-
MCP_LAST_COMMIT_TIME: structure.lastCommit?.time || 'Unknown',
|
|
302
|
-
|
|
303
|
-
MCP_CS_FILES: structure.filesByExtension?.cs || 0,
|
|
304
|
-
MCP_RAZOR_FILES: structure.filesByExtension?.razor || 0,
|
|
305
|
-
MCP_TS_FILES: structure.filesByExtension?.ts || 0,
|
|
306
|
-
MCP_JS_FILES: structure.filesByExtension?.js || 0,
|
|
307
|
-
|
|
308
|
-
MCP_NUGET_PACKAGES: dependencies.nuget.length,
|
|
309
|
-
MCP_NPM_PACKAGES: dependencies.npm.length,
|
|
310
|
-
|
|
311
|
-
MCP_ARCHITECTURE_VIOLATIONS: compliance.architectureViolations,
|
|
312
|
-
MCP_PACKAGE_CONFLICTS: compliance.packageConflicts,
|
|
313
|
-
MCP_SECURITY_ISSUES: compliance.securityIssues,
|
|
314
|
-
|
|
315
|
-
MCP_RECENT_BRANCHES: activity.activeBranches.slice(0, 3).join(', '),
|
|
316
|
-
|
|
317
|
-
// Full objects for advanced usage
|
|
318
|
-
_raw: {
|
|
319
|
-
structure,
|
|
320
|
-
dependencies,
|
|
321
|
-
compliance,
|
|
322
|
-
activity
|
|
323
|
-
}
|
|
324
|
-
};
|
|
325
|
-
}
|
|
@@ -1,223 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Config Detector - Reads configuration files to extract technologies, versions, and dependencies
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { readFileSync, existsSync } from 'fs';
|
|
6
|
-
import { join } from 'path';
|
|
7
|
-
import { glob } from 'glob';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Detect project configuration
|
|
11
|
-
* @param {string} projectPath - Project root path
|
|
12
|
-
* @returns {Promise<Object>} Configuration detection results
|
|
13
|
-
*/
|
|
14
|
-
export async function detectConfig(projectPath) {
|
|
15
|
-
const result = {
|
|
16
|
-
language: 'unknown',
|
|
17
|
-
version: null,
|
|
18
|
-
packageManager: 'unknown',
|
|
19
|
-
dependencies: [],
|
|
20
|
-
technologies: [],
|
|
21
|
-
auth: null,
|
|
22
|
-
database: null,
|
|
23
|
-
hosting: null
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
// Detect .NET projects
|
|
27
|
-
const dotnetConfig = await detectDotNet(projectPath);
|
|
28
|
-
if (dotnetConfig) {
|
|
29
|
-
Object.assign(result, dotnetConfig);
|
|
30
|
-
return result;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
// Detect Node.js projects
|
|
34
|
-
const nodeConfig = await detectNode(projectPath);
|
|
35
|
-
if (nodeConfig) {
|
|
36
|
-
Object.assign(result, nodeConfig);
|
|
37
|
-
return result;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return result;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Detect .NET configuration
|
|
45
|
-
*/
|
|
46
|
-
async function detectDotNet(projectPath) {
|
|
47
|
-
const programCs = join(projectPath, 'Program.cs');
|
|
48
|
-
const csprojFiles = await glob('**/*.csproj', { cwd: projectPath });
|
|
49
|
-
|
|
50
|
-
if (!existsSync(programCs) && csprojFiles.length === 0) {
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
const config = {
|
|
55
|
-
language: 'csharp',
|
|
56
|
-
version: null,
|
|
57
|
-
packageManager: 'dotnet',
|
|
58
|
-
dependencies: [],
|
|
59
|
-
technologies: [],
|
|
60
|
-
auth: null,
|
|
61
|
-
database: null,
|
|
62
|
-
hosting: null
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
// Read Program.cs
|
|
66
|
-
if (existsSync(programCs)) {
|
|
67
|
-
const content = readFileSync(programCs, 'utf8');
|
|
68
|
-
|
|
69
|
-
// Detect .NET version
|
|
70
|
-
if (content.includes('WebApplication.CreateBuilder') || content.includes('.NET')) {
|
|
71
|
-
config.version = detectDotNetVersion(content);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// Detect technologies from Program.cs
|
|
75
|
-
config.technologies = detectTechnologiesFromProgramCs(content);
|
|
76
|
-
config.auth = detectAuthMethod(content);
|
|
77
|
-
config.database = detectDatabase(content);
|
|
78
|
-
config.hosting = detectHosting(content);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
// Read .csproj files
|
|
82
|
-
for (const csprojFile of csprojFiles.slice(0, 3)) { // Read first 3 csproj files
|
|
83
|
-
const csprojPath = join(projectPath, csprojFile);
|
|
84
|
-
const content = readFileSync(csprojPath, 'utf8');
|
|
85
|
-
|
|
86
|
-
config.dependencies.push(...extractNuGetPackages(content));
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
// Remove duplicates
|
|
90
|
-
config.dependencies = [...new Set(config.dependencies)];
|
|
91
|
-
config.technologies = [...new Set(config.technologies)];
|
|
92
|
-
|
|
93
|
-
return config;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Detect Node.js configuration
|
|
98
|
-
*/
|
|
99
|
-
async function detectNode(projectPath) {
|
|
100
|
-
const packageJsonPath = join(projectPath, 'package.json');
|
|
101
|
-
|
|
102
|
-
if (!existsSync(packageJsonPath)) {
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'));
|
|
107
|
-
|
|
108
|
-
const config = {
|
|
109
|
-
language: 'javascript',
|
|
110
|
-
version: packageJson.engines?.node || null,
|
|
111
|
-
packageManager: existsSync(join(projectPath, 'yarn.lock')) ? 'yarn' :
|
|
112
|
-
existsSync(join(projectPath, 'pnpm-lock.yaml')) ? 'pnpm' : 'npm',
|
|
113
|
-
dependencies: [],
|
|
114
|
-
technologies: [],
|
|
115
|
-
auth: null,
|
|
116
|
-
database: null,
|
|
117
|
-
hosting: null
|
|
118
|
-
};
|
|
119
|
-
|
|
120
|
-
// Extract dependencies
|
|
121
|
-
const allDeps = {
|
|
122
|
-
...packageJson.dependencies,
|
|
123
|
-
...packageJson.devDependencies
|
|
124
|
-
};
|
|
125
|
-
|
|
126
|
-
config.dependencies = Object.keys(allDeps);
|
|
127
|
-
|
|
128
|
-
// Detect technologies
|
|
129
|
-
if (allDeps['next']) config.technologies.push('Next.js');
|
|
130
|
-
if (allDeps['react']) config.technologies.push('React');
|
|
131
|
-
if (allDeps['@clerk/nextjs']) config.auth = 'Clerk';
|
|
132
|
-
if (allDeps['prisma']) config.database = 'Prisma';
|
|
133
|
-
|
|
134
|
-
return config;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/**
|
|
138
|
-
* Detect .NET version from Program.cs
|
|
139
|
-
*/
|
|
140
|
-
function detectDotNetVersion(content) {
|
|
141
|
-
if (content.includes('.NET 10') || content.includes('net10.0')) return '.NET 10';
|
|
142
|
-
if (content.includes('.NET 9') || content.includes('net9.0')) return '.NET 9';
|
|
143
|
-
if (content.includes('.NET 8') || content.includes('net8.0')) return '.NET 8';
|
|
144
|
-
return 'unknown';
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Detect technologies from Program.cs
|
|
149
|
-
*/
|
|
150
|
-
function detectTechnologiesFromProgramCs(content) {
|
|
151
|
-
const techs = [];
|
|
152
|
-
|
|
153
|
-
if (content.includes('AddBlazor') || content.includes('MapBlazorHub')) {
|
|
154
|
-
techs.push('Blazor Server');
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
if (content.includes('AddHangfire')) {
|
|
158
|
-
techs.push('Hangfire');
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
if (content.includes('IChatClient') || content.includes('Microsoft.Agents')) {
|
|
162
|
-
techs.push('Microsoft Agent Framework');
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
if (content.includes('AddDbContext') || content.includes('UseSqlServer')) {
|
|
166
|
-
techs.push('Entity Framework Core');
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
if (content.includes('AddFluentUIComponents') || content.includes('FluentUI')) {
|
|
170
|
-
techs.push('Fluent UI Blazor');
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
if (content.includes('AddMudServices') || content.includes('MudBlazor')) {
|
|
174
|
-
techs.push('MudBlazor');
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
return techs;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
/**
|
|
181
|
-
* Detect authentication method
|
|
182
|
-
*/
|
|
183
|
-
function detectAuthMethod(content) {
|
|
184
|
-
if (content.includes('AddClerk') || content.includes('Clerk')) return 'Clerk';
|
|
185
|
-
if (content.includes('AddMicrosoftIdentity') || content.includes('Entra')) return 'Microsoft Entra';
|
|
186
|
-
if (content.includes('AddAuthentication')) return 'ASP.NET Identity';
|
|
187
|
-
return null;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Detect database
|
|
192
|
-
*/
|
|
193
|
-
function detectDatabase(content) {
|
|
194
|
-
if (content.includes('UseSqlServer')) return 'SQL Server';
|
|
195
|
-
if (content.includes('UsePostgres')) return 'PostgreSQL';
|
|
196
|
-
if (content.includes('UseSqlite')) return 'SQLite';
|
|
197
|
-
if (content.includes('UseCosmos')) return 'Cosmos DB';
|
|
198
|
-
return null;
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
/**
|
|
202
|
-
* Detect hosting platform
|
|
203
|
-
*/
|
|
204
|
-
function detectHosting(content) {
|
|
205
|
-
if (content.includes('Azure') || content.includes('AddAzure')) return 'Azure';
|
|
206
|
-
if (content.includes('AWS')) return 'AWS';
|
|
207
|
-
return null;
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
/**
|
|
211
|
-
* Extract NuGet packages from .csproj
|
|
212
|
-
*/
|
|
213
|
-
function extractNuGetPackages(csprojContent) {
|
|
214
|
-
const packages = [];
|
|
215
|
-
const regex = /<PackageReference\s+Include="([^"]+)"/g;
|
|
216
|
-
let match;
|
|
217
|
-
|
|
218
|
-
while ((match = regex.exec(csprojContent)) !== null) {
|
|
219
|
-
packages.push(match[1]);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
return packages;
|
|
223
|
-
}
|