@velt-js/mcp-installer 0.1.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 +373 -0
- package/bin/mcp-server.js +22 -0
- package/package.json +42 -0
- package/src/index.js +754 -0
- package/src/tools/orchestrator.js +299 -0
- package/src/tools/unified-installer.js +886 -0
- package/src/utils/cli.js +380 -0
- package/src/utils/comment-detector.js +305 -0
- package/src/utils/config.js +149 -0
- package/src/utils/framework-detection.js +262 -0
- package/src/utils/header-positioning.js +146 -0
- package/src/utils/host-app-discovery.js +1000 -0
- package/src/utils/integration.js +803 -0
- package/src/utils/plan-formatter.js +1698 -0
- package/src/utils/screenshot.js +151 -0
- package/src/utils/use-client.js +366 -0
- package/src/utils/validation.js +556 -0
- package/src/utils/velt-docs-fetcher.js +288 -0
- package/src/utils/velt-docs-urls.js +140 -0
- package/src/utils/velt-mcp-client.js +202 -0
- package/src/utils/velt-mcp.js +718 -0
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Velt Installation Orchestrator
|
|
3
|
+
*
|
|
4
|
+
* @deprecated Use unified-installer.js instead. This module is kept for backward compatibility.
|
|
5
|
+
* The unified installer provides both guided and CLI-only modes with better UX.
|
|
6
|
+
*
|
|
7
|
+
* Single orchestrator tool that handles the complete Velt installation workflow
|
|
8
|
+
* with guaranteed sequential execution.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { collectConfiguration } from '../utils/config.js';
|
|
12
|
+
import { runVeltCli } from '../utils/cli.js';
|
|
13
|
+
import { queryVeltMCP, detectLibraries } from '../utils/velt-mcp.js';
|
|
14
|
+
import { analyzeAndIntegrate } from '../utils/integration.js';
|
|
15
|
+
import { validateInstallation } from '../utils/validation.js';
|
|
16
|
+
import path from 'path';
|
|
17
|
+
import { fileURLToPath } from 'url';
|
|
18
|
+
|
|
19
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
20
|
+
const __dirname = path.dirname(__filename);
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Main orchestrator function that executes all installation steps sequentially
|
|
24
|
+
*
|
|
25
|
+
* @param {Object} params - Tool parameters
|
|
26
|
+
* @param {string} params.projectPath - Path to Next.js project
|
|
27
|
+
* @param {string} [params.apiKey] - Velt API key (optional, will read from .env if not provided)
|
|
28
|
+
* @param {string} [params.authToken] - Velt auth token (optional)
|
|
29
|
+
* @returns {Promise<Object>} Installation report
|
|
30
|
+
*/
|
|
31
|
+
export async function installVeltFreestyle({ projectPath, apiKey, authToken }) {
|
|
32
|
+
const report = {
|
|
33
|
+
status: 'in_progress',
|
|
34
|
+
steps: [],
|
|
35
|
+
errors: [],
|
|
36
|
+
startTime: new Date().toISOString(),
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const resolvedPath = path.resolve(projectPath);
|
|
40
|
+
|
|
41
|
+
try {
|
|
42
|
+
console.error('\nš Starting Velt Installation');
|
|
43
|
+
console.error(`š Project: ${resolvedPath}\n`);
|
|
44
|
+
|
|
45
|
+
// === STEP 1: Collect Configuration ===
|
|
46
|
+
console.error('š Step 1/5: Collecting configuration...');
|
|
47
|
+
report.steps.push({
|
|
48
|
+
step: 1,
|
|
49
|
+
name: 'collect_configuration',
|
|
50
|
+
status: 'running',
|
|
51
|
+
description: 'Collecting installation configuration (directory, API key, auth token)',
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const config = await collectConfiguration({
|
|
55
|
+
projectPath: resolvedPath,
|
|
56
|
+
apiKey, // Pass provided API key (or null to read from .env)
|
|
57
|
+
authToken, // Pass provided auth token (or null to read from .env)
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
if (!config.success) {
|
|
61
|
+
// Stop installation if API key is missing
|
|
62
|
+
console.error('ā Step 1/5: Failed - API key not found\n');
|
|
63
|
+
report.status = 'failed';
|
|
64
|
+
report.endTime = new Date().toISOString();
|
|
65
|
+
report.steps[0].status = 'failed';
|
|
66
|
+
report.steps[0].error = config.error;
|
|
67
|
+
report.errors.push({
|
|
68
|
+
message: config.error,
|
|
69
|
+
failedAtStep: 'collect_configuration',
|
|
70
|
+
});
|
|
71
|
+
return report;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
report.steps[0].status = 'complete';
|
|
75
|
+
report.steps[0].result = {
|
|
76
|
+
installDir: config.data.installDir,
|
|
77
|
+
hasApiKey: !!config.data.apiKey,
|
|
78
|
+
hasAuthToken: !!config.data.authToken,
|
|
79
|
+
};
|
|
80
|
+
console.error('ā
Step 1/5: Configuration collected\n');
|
|
81
|
+
|
|
82
|
+
// === STEP 2: Run Velt CLI ===
|
|
83
|
+
console.error('āļø Step 2/5: Running Velt CLI...');
|
|
84
|
+
report.steps.push({
|
|
85
|
+
step: 2,
|
|
86
|
+
name: 'run_velt_cli',
|
|
87
|
+
status: 'running',
|
|
88
|
+
description: 'Running add-velt-cli to install base Velt components',
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
const cliResult = await runVeltCli({
|
|
92
|
+
installDir: config.data.installDir,
|
|
93
|
+
apiKey: config.data.apiKey,
|
|
94
|
+
authToken: config.data.authToken,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// CLI may fail on npm install (peer dependency conflicts), but files are still created
|
|
98
|
+
// Continue with installation even if CLI reports failure
|
|
99
|
+
if (!cliResult.success) {
|
|
100
|
+
console.error(` ā ļø CLI reported failure (exit code: ${cliResult.exitCode})`);
|
|
101
|
+
console.error(` ā¹ļø Continuing anyway - CLI may have still created required files`);
|
|
102
|
+
console.error(` ā¹ļø Common cause: npm install peer dependency conflicts (doesn't affect file generation)`);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
report.steps[1].status = cliResult.success ? 'complete' : 'complete_with_warnings';
|
|
106
|
+
report.steps[1].result = {
|
|
107
|
+
exitCode: cliResult.exitCode,
|
|
108
|
+
output: cliResult.output?.slice(0, 200), // Truncate for readability
|
|
109
|
+
warning: cliResult.success ? null : 'CLI reported failure but continuing - files may still have been created',
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
if (cliResult.success) {
|
|
113
|
+
console.error('ā
Step 2/5: Velt CLI completed\n');
|
|
114
|
+
} else {
|
|
115
|
+
console.error('ā ļø Step 2/5: Velt CLI completed with warnings (continuing...)\n');
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// === STEP 3: Query Velt MCP for Patterns and Detect Libraries ===
|
|
119
|
+
console.error('š Step 3/5: Fetching documentation patterns and detecting libraries...');
|
|
120
|
+
report.steps.push({
|
|
121
|
+
step: 3,
|
|
122
|
+
name: 'query_velt_mcp',
|
|
123
|
+
status: 'running',
|
|
124
|
+
description: 'Querying Velt MCP server for freestyle comments implementation patterns and detecting libraries',
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Query Velt Docs MCP for implementation patterns
|
|
128
|
+
const mcpPatterns = await queryVeltMCP({
|
|
129
|
+
question: 'How do I implement freestyle comments in Next.js app router? Show me the best practices and code patterns.',
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
if (!mcpPatterns.success) {
|
|
133
|
+
throw new Error(`Velt MCP query failed: ${mcpPatterns.error}`);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Detect libraries in the project
|
|
137
|
+
const libraryDetection = detectLibraries(resolvedPath);
|
|
138
|
+
|
|
139
|
+
// Merge MCP patterns with library detection
|
|
140
|
+
// This combines documentation patterns (code examples) with library flags (booleans)
|
|
141
|
+
const mergedPatterns = {
|
|
142
|
+
// MCP documentation patterns (code examples)
|
|
143
|
+
...mcpPatterns.data,
|
|
144
|
+
// Library detection flags (for integration.js)
|
|
145
|
+
...libraryDetection,
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
report.steps[2].status = 'complete';
|
|
149
|
+
report.steps[2].result = {
|
|
150
|
+
patternsFound: !!mcpPatterns.data,
|
|
151
|
+
patternSummary: mcpPatterns.data?.summary || 'Patterns retrieved',
|
|
152
|
+
source: mcpPatterns.source || 'unknown',
|
|
153
|
+
message: mcpPatterns.message || mcpPatterns.warning || 'Patterns retrieved',
|
|
154
|
+
queryUsed: mcpPatterns.query,
|
|
155
|
+
librariesDetected: {
|
|
156
|
+
reactflow: libraryDetection.hasReactFlow,
|
|
157
|
+
tiptap: libraryDetection.hasTiptap,
|
|
158
|
+
codemirror: libraryDetection.hasCodeMirror,
|
|
159
|
+
agGrid: libraryDetection.hasAgGrid,
|
|
160
|
+
tanStack: libraryDetection.hasTanStack,
|
|
161
|
+
},
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// Add clear message to report
|
|
165
|
+
if (mcpPatterns.source === 'velt-docs-url') {
|
|
166
|
+
report.steps[2].message = 'ā
Successfully fetched Velt documentation - using real documentation patterns';
|
|
167
|
+
} else if (mcpPatterns.source === 'fallback') {
|
|
168
|
+
report.steps[2].message = 'ā ļø Using fallback patterns (could not fetch documentation) - using known best practices';
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Add library detection summary
|
|
172
|
+
const libraryNames = {
|
|
173
|
+
hasReactFlow: 'ReactFlow',
|
|
174
|
+
hasTiptap: 'Tiptap',
|
|
175
|
+
hasCodeMirror: 'CodeMirror',
|
|
176
|
+
hasAgGrid: 'AG-Grid',
|
|
177
|
+
hasTanStack: 'TanStack Table',
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const detectedLibraries = Object.entries(libraryDetection)
|
|
181
|
+
.filter(([_, detected]) => detected)
|
|
182
|
+
.map(([key]) => libraryNames[key] || key);
|
|
183
|
+
|
|
184
|
+
if (detectedLibraries.length > 0) {
|
|
185
|
+
report.steps[2].message += ` | Detected libraries: ${detectedLibraries.join(', ')}`;
|
|
186
|
+
console.error(` š Detected libraries: ${detectedLibraries.join(', ')}`);
|
|
187
|
+
}
|
|
188
|
+
console.error('ā
Step 3/5: Patterns fetched and libraries detected\n');
|
|
189
|
+
|
|
190
|
+
// === STEP 4: Analyze and Integrate ===
|
|
191
|
+
console.error('š§ Step 4/5: Integrating Velt components...');
|
|
192
|
+
|
|
193
|
+
// Show what patterns will be used
|
|
194
|
+
const patternSource = mcpPatterns.source === 'velt-docs-url' ? 'Velt documentation' : 'fallback patterns';
|
|
195
|
+
console.error(` š Using patterns from: ${patternSource}`);
|
|
196
|
+
if (mcpPatterns.data?.providerPattern?.code) {
|
|
197
|
+
console.error(' ā Using VeltProvider pattern from docs');
|
|
198
|
+
}
|
|
199
|
+
if (mcpPatterns.data?.commentsPattern?.code) {
|
|
200
|
+
console.error(' ā Using VeltComments pattern from docs');
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
report.steps.push({
|
|
204
|
+
step: 4,
|
|
205
|
+
name: 'analyze_and_integrate',
|
|
206
|
+
status: 'running',
|
|
207
|
+
description: 'Analyzing customer code and integrating Velt components based on patterns',
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const integration = await analyzeAndIntegrate({
|
|
211
|
+
projectPath: resolvedPath,
|
|
212
|
+
config: {
|
|
213
|
+
apiKey: config.data.apiKey,
|
|
214
|
+
authToken: config.data.authToken,
|
|
215
|
+
},
|
|
216
|
+
patterns: mergedPatterns, // Now includes both MCP patterns AND library detection flags
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
if (!integration.success) {
|
|
220
|
+
throw new Error(`Integration failed: ${integration.error}`);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
report.steps[3].status = 'complete';
|
|
224
|
+
report.steps[3].result = {
|
|
225
|
+
filesModified: integration.data?.filesModified || [],
|
|
226
|
+
componentsAdded: integration.data?.componentsAdded || [],
|
|
227
|
+
integrationPoints: integration.data?.integrationPoints || [],
|
|
228
|
+
};
|
|
229
|
+
const filesCount = integration.data?.filesModified?.length || 0;
|
|
230
|
+
const componentsCount = integration.data?.componentsAdded?.length || 0;
|
|
231
|
+
console.error(` āļø Modified ${filesCount} file(s)`);
|
|
232
|
+
console.error(` ā Added ${componentsCount} component(s)`);
|
|
233
|
+
console.error('ā
Step 4/5: Integration completed\n');
|
|
234
|
+
|
|
235
|
+
// === STEP 5: Validate Installation ===
|
|
236
|
+
console.error('āļø Step 5/5: Validating installation...');
|
|
237
|
+
report.steps.push({
|
|
238
|
+
step: 5,
|
|
239
|
+
name: 'validate_installation',
|
|
240
|
+
status: 'running',
|
|
241
|
+
description: 'Validating installation with basic checks',
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
const validation = await validateInstallation({
|
|
245
|
+
projectPath: resolvedPath,
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
report.steps[4].status = 'complete';
|
|
249
|
+
report.steps[4].result = {
|
|
250
|
+
checks: validation.checks || [],
|
|
251
|
+
passed: validation.passed || 0,
|
|
252
|
+
total: validation.total || 0,
|
|
253
|
+
score: validation.score || '0/0',
|
|
254
|
+
};
|
|
255
|
+
console.error(` ${validation.passed}/${validation.total} validation checks passed`);
|
|
256
|
+
console.error('ā
Step 5/5: Validation completed\n');
|
|
257
|
+
|
|
258
|
+
// All steps completed successfully
|
|
259
|
+
report.status = 'success';
|
|
260
|
+
report.endTime = new Date().toISOString();
|
|
261
|
+
console.error('š Installation completed successfully!\n');
|
|
262
|
+
|
|
263
|
+
// Build summary with source information
|
|
264
|
+
const mcpStep = report.steps.find(s => s.name === 'query_velt_mcp');
|
|
265
|
+
const mcpSource = mcpStep?.result?.source || 'unknown';
|
|
266
|
+
const mcpMessage = mcpStep?.message || '';
|
|
267
|
+
|
|
268
|
+
report.summary = `Velt freestyle comments successfully installed in ${resolvedPath}`;
|
|
269
|
+
report.details = {
|
|
270
|
+
installationPath: resolvedPath,
|
|
271
|
+
veltDocsSource: mcpSource === 'velt-docs-url' ? 'ā
Used real documentation' : 'ā ļø Used fallback patterns',
|
|
272
|
+
mcpMessage: mcpMessage,
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
return report;
|
|
276
|
+
} catch (error) {
|
|
277
|
+
const currentStep = report.steps[report.steps.length - 1];
|
|
278
|
+
const stepNumber = currentStep?.step || '?';
|
|
279
|
+
console.error(`\nā Step ${stepNumber}/5: Failed`);
|
|
280
|
+
console.error(` Error: ${error.message}\n`);
|
|
281
|
+
|
|
282
|
+
report.status = 'failed';
|
|
283
|
+
report.endTime = new Date().toISOString();
|
|
284
|
+
report.errors.push({
|
|
285
|
+
message: error.message,
|
|
286
|
+
stack: error.stack,
|
|
287
|
+
failedAtStep: currentStep?.name || 'unknown',
|
|
288
|
+
});
|
|
289
|
+
|
|
290
|
+
// Mark current step as failed
|
|
291
|
+
if (currentStep && currentStep.status === 'running') {
|
|
292
|
+
currentStep.status = 'failed';
|
|
293
|
+
currentStep.error = error.message;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
return report;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|