mcp-new 1.2.2 → 1.6.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 +33 -1
- package/dist/{chunk-3JG4FVS2.js → chunk-LJNMSDBU.js} +1157 -212
- package/dist/cli.js +1287 -18
- package/dist/index.d.ts +43 -10
- package/dist/index.js +22 -35
- package/package.json +4 -2
- package/templates/ci/circleci/config.yml.ejs +219 -0
- package/templates/ci/github/ci.yml.ejs +184 -0
- package/templates/ci/gitlab/.gitlab-ci.yml.ejs +233 -0
- package/templates/csharp/.env.example +6 -0
- package/templates/csharp/.gitignore.ejs +53 -0
- package/templates/csharp/McpServer.csproj.ejs +19 -0
- package/templates/csharp/README.md.ejs +136 -0
- package/templates/csharp/src/Program.cs.ejs +117 -0
- package/templates/elixir/.env.example +6 -0
- package/templates/elixir/.gitignore.ejs +33 -0
- package/templates/elixir/README.md.ejs +154 -0
- package/templates/elixir/config/config.exs.ejs +9 -0
- package/templates/elixir/config/dev.exs.ejs +3 -0
- package/templates/elixir/config/prod.exs.ejs +3 -0
- package/templates/elixir/lib/application.ex.ejs +19 -0
- package/templates/elixir/lib/cli.ex.ejs +17 -0
- package/templates/elixir/lib/server.ex.ejs +112 -0
- package/templates/elixir/mix.exs.ejs +32 -0
- package/templates/java/gradle/.env.example +6 -0
- package/templates/java/gradle/.gitignore.ejs +48 -0
- package/templates/java/gradle/README.md.ejs +132 -0
- package/templates/java/gradle/build.gradle.ejs +46 -0
- package/templates/java/gradle/settings.gradle.ejs +1 -0
- package/templates/java/gradle/src/main/java/com/example/mcp/McpServer.java.ejs +149 -0
- package/templates/java/gradle/src/main/resources/logback.xml +13 -0
- package/templates/java/maven/.env.example +6 -0
- package/templates/java/maven/.gitignore.ejs +53 -0
- package/templates/java/maven/README.md.ejs +131 -0
- package/templates/java/maven/pom.xml.ejs +86 -0
- package/templates/java/maven/src/main/java/com/example/mcp/McpServer.java.ejs +149 -0
- package/templates/java/maven/src/main/resources/logback.xml +13 -0
- package/templates/kotlin/gradle/.env.example +6 -0
- package/templates/kotlin/gradle/.gitignore.ejs +45 -0
- package/templates/kotlin/gradle/README.md.ejs +138 -0
- package/templates/kotlin/gradle/build.gradle.kts.ejs +48 -0
- package/templates/kotlin/gradle/settings.gradle.kts.ejs +1 -0
- package/templates/kotlin/gradle/src/main/kotlin/com/example/mcp/McpServer.kt.ejs +141 -0
- package/templates/kotlin/gradle/src/main/resources/logback.xml +13 -0
- package/templates/kotlin/maven/.env.example +6 -0
- package/templates/kotlin/maven/.gitignore.ejs +50 -0
- package/templates/kotlin/maven/README.md.ejs +96 -0
- package/templates/kotlin/maven/pom.xml.ejs +105 -0
- package/templates/kotlin/maven/src/main/kotlin/com/example/mcp/McpServer.kt.ejs +141 -0
- package/templates/kotlin/maven/src/main/resources/logback.xml +13 -0
|
@@ -40,12 +40,12 @@ function validateUrl(url) {
|
|
|
40
40
|
return { valid: false, error: "Invalid URL format" };
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
-
function validateFilePath(
|
|
44
|
-
if (!
|
|
43
|
+
function validateFilePath(path11) {
|
|
44
|
+
if (!path11 || path11.trim().length === 0) {
|
|
45
45
|
return { valid: false, error: "File path cannot be empty" };
|
|
46
46
|
}
|
|
47
47
|
const invalidChars = /[<>:"|?*]/;
|
|
48
|
-
if (invalidChars.test(
|
|
48
|
+
if (invalidChars.test(path11)) {
|
|
49
49
|
return { valid: false, error: "File path contains invalid characters" };
|
|
50
50
|
}
|
|
51
51
|
return { valid: true };
|
|
@@ -90,20 +90,270 @@ async function promptProjectDescription() {
|
|
|
90
90
|
return description;
|
|
91
91
|
}
|
|
92
92
|
|
|
93
|
+
// src/utils/file-system.ts
|
|
94
|
+
import fs from "fs-extra";
|
|
95
|
+
import path from "path";
|
|
96
|
+
import ejs from "ejs";
|
|
97
|
+
async function ensureDir(dirPath) {
|
|
98
|
+
await fs.ensureDir(dirPath);
|
|
99
|
+
}
|
|
100
|
+
async function writeFile(filePath, content) {
|
|
101
|
+
await fs.ensureDir(path.dirname(filePath));
|
|
102
|
+
await fs.writeFile(filePath, content, "utf-8");
|
|
103
|
+
}
|
|
104
|
+
async function readFile(filePath) {
|
|
105
|
+
return fs.readFile(filePath, "utf-8");
|
|
106
|
+
}
|
|
107
|
+
async function copyFile(src, dest) {
|
|
108
|
+
await fs.ensureDir(path.dirname(dest));
|
|
109
|
+
await fs.copyFile(src, dest);
|
|
110
|
+
}
|
|
111
|
+
async function copyDir(src, dest) {
|
|
112
|
+
await fs.copy(src, dest);
|
|
113
|
+
}
|
|
114
|
+
async function exists(filePath) {
|
|
115
|
+
return fs.pathExists(filePath);
|
|
116
|
+
}
|
|
117
|
+
async function remove(filePath) {
|
|
118
|
+
await fs.remove(filePath);
|
|
119
|
+
}
|
|
120
|
+
async function readDir(dirPath) {
|
|
121
|
+
return fs.readdir(dirPath);
|
|
122
|
+
}
|
|
123
|
+
async function isDirectory(filePath) {
|
|
124
|
+
try {
|
|
125
|
+
const stat = await fs.stat(filePath);
|
|
126
|
+
return stat.isDirectory();
|
|
127
|
+
} catch {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
async function renderTemplate(templatePath, data) {
|
|
132
|
+
const template = await readFile(templatePath);
|
|
133
|
+
return ejs.render(template, data, { async: false });
|
|
134
|
+
}
|
|
135
|
+
async function renderTemplateToFile(templatePath, outputPath, data) {
|
|
136
|
+
const content = await renderTemplate(templatePath, data);
|
|
137
|
+
const finalPath = outputPath.replace(/\.ejs$/, "");
|
|
138
|
+
await writeFile(finalPath, content);
|
|
139
|
+
}
|
|
140
|
+
async function walkDir(dirPath, callback) {
|
|
141
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
142
|
+
for (const entry of entries) {
|
|
143
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
144
|
+
const isDir = entry.isDirectory();
|
|
145
|
+
await callback(fullPath, isDir);
|
|
146
|
+
if (isDir) {
|
|
147
|
+
await walkDir(fullPath, callback);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function getTemplateDir() {
|
|
152
|
+
const devPath = path.join(import.meta.dirname, "..", "templates");
|
|
153
|
+
const prodPath = path.join(import.meta.dirname, "..", "..", "templates");
|
|
154
|
+
if (fs.existsSync(devPath)) {
|
|
155
|
+
return devPath;
|
|
156
|
+
}
|
|
157
|
+
return prodPath;
|
|
158
|
+
}
|
|
159
|
+
function getTemplateDirForLanguage(language, pluginTemplateDir) {
|
|
160
|
+
if (pluginTemplateDir) {
|
|
161
|
+
return pluginTemplateDir;
|
|
162
|
+
}
|
|
163
|
+
return path.join(getTemplateDir(), language);
|
|
164
|
+
}
|
|
165
|
+
function resolveOutputPath(basePath, ...segments) {
|
|
166
|
+
return path.resolve(basePath, ...segments);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/plugins/discovery.ts
|
|
170
|
+
import path2 from "path";
|
|
171
|
+
|
|
172
|
+
// src/types/plugin.ts
|
|
173
|
+
import { z } from "zod";
|
|
174
|
+
var LanguagePluginManifestSchema = z.object({
|
|
175
|
+
languageId: z.string(),
|
|
176
|
+
languageDisplayName: z.string(),
|
|
177
|
+
templateDir: z.string().default("templates"),
|
|
178
|
+
installCommand: z.string().optional(),
|
|
179
|
+
runCommand: z.string().optional(),
|
|
180
|
+
buildCommand: z.string().optional(),
|
|
181
|
+
fileExtension: z.string().optional()
|
|
182
|
+
});
|
|
183
|
+
var PLUGIN_MANIFEST_FILE = "mcp-plugin.json";
|
|
184
|
+
|
|
185
|
+
// src/plugins/discovery.ts
|
|
186
|
+
async function discoverPlugins() {
|
|
187
|
+
const plugins = [];
|
|
188
|
+
const searchPaths = [
|
|
189
|
+
// Global npm modules
|
|
190
|
+
getGlobalNodeModulesPath(),
|
|
191
|
+
// Local node_modules
|
|
192
|
+
path2.join(process.cwd(), "node_modules"),
|
|
193
|
+
// Relative to this package
|
|
194
|
+
path2.join(import.meta.dirname, "..", "..", "node_modules")
|
|
195
|
+
];
|
|
196
|
+
for (const searchPath of searchPaths) {
|
|
197
|
+
const scopedPath = path2.join(searchPath, "@mcp-new");
|
|
198
|
+
if (!await exists(scopedPath)) {
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
try {
|
|
202
|
+
const { readdir } = await import("fs/promises");
|
|
203
|
+
const entries = await readdir(scopedPath, { withFileTypes: true });
|
|
204
|
+
for (const entry of entries) {
|
|
205
|
+
if (!entry.isDirectory()) continue;
|
|
206
|
+
if (!entry.name.startsWith("template-")) continue;
|
|
207
|
+
const pluginPath = path2.join(scopedPath, entry.name);
|
|
208
|
+
const plugin = await loadPlugin(pluginPath, `@mcp-new/${entry.name}`);
|
|
209
|
+
if (plugin) {
|
|
210
|
+
if (!plugins.some((p) => p.manifest.languageId === plugin.manifest.languageId)) {
|
|
211
|
+
plugins.push(plugin);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
} catch {
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return plugins;
|
|
219
|
+
}
|
|
220
|
+
async function loadPlugin(packagePath, packageName) {
|
|
221
|
+
const manifestPath = path2.join(packagePath, PLUGIN_MANIFEST_FILE);
|
|
222
|
+
if (!await exists(manifestPath)) {
|
|
223
|
+
return null;
|
|
224
|
+
}
|
|
225
|
+
try {
|
|
226
|
+
const content = await readFile(manifestPath);
|
|
227
|
+
const rawManifest = JSON.parse(content);
|
|
228
|
+
const manifest = LanguagePluginManifestSchema.parse(rawManifest);
|
|
229
|
+
const templatePath = path2.join(packagePath, manifest.templateDir);
|
|
230
|
+
if (!await exists(templatePath)) {
|
|
231
|
+
console.warn(`Plugin ${packageName}: templates directory not found at ${templatePath}`);
|
|
232
|
+
return null;
|
|
233
|
+
}
|
|
234
|
+
return {
|
|
235
|
+
manifest,
|
|
236
|
+
packageName,
|
|
237
|
+
packagePath,
|
|
238
|
+
templatePath
|
|
239
|
+
};
|
|
240
|
+
} catch (error) {
|
|
241
|
+
console.warn(`Failed to load plugin ${packageName}:`, error);
|
|
242
|
+
return null;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
function getGlobalNodeModulesPath() {
|
|
246
|
+
if (process.platform === "win32") {
|
|
247
|
+
return path2.join(process.env.APPDATA || "", "npm", "node_modules");
|
|
248
|
+
}
|
|
249
|
+
return "/usr/local/lib/node_modules";
|
|
250
|
+
}
|
|
251
|
+
function isPluginLanguage(languageId, plugins) {
|
|
252
|
+
return plugins.some((p) => p.manifest.languageId === languageId);
|
|
253
|
+
}
|
|
254
|
+
function getPluginForLanguage(languageId, plugins) {
|
|
255
|
+
return plugins.find((p) => p.manifest.languageId === languageId);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// src/plugins/registry.ts
|
|
259
|
+
var PluginRegistry = class {
|
|
260
|
+
plugins = [];
|
|
261
|
+
initialized = false;
|
|
262
|
+
/**
|
|
263
|
+
* Initialize the registry by discovering installed plugins.
|
|
264
|
+
*/
|
|
265
|
+
async initialize() {
|
|
266
|
+
if (this.initialized) {
|
|
267
|
+
return;
|
|
268
|
+
}
|
|
269
|
+
this.plugins = await discoverPlugins();
|
|
270
|
+
this.initialized = true;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Get all registered plugins.
|
|
274
|
+
*/
|
|
275
|
+
getPlugins() {
|
|
276
|
+
return [...this.plugins];
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Get a plugin by language ID.
|
|
280
|
+
*/
|
|
281
|
+
getPlugin(languageId) {
|
|
282
|
+
return getPluginForLanguage(languageId, this.plugins);
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Check if a language is provided by a plugin.
|
|
286
|
+
*/
|
|
287
|
+
isPluginLanguage(languageId) {
|
|
288
|
+
return isPluginLanguage(languageId, this.plugins);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Get all available languages from plugins.
|
|
292
|
+
*/
|
|
293
|
+
getPluginLanguages() {
|
|
294
|
+
return this.plugins.map((p) => ({
|
|
295
|
+
id: p.manifest.languageId,
|
|
296
|
+
name: p.manifest.languageDisplayName
|
|
297
|
+
}));
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Get the template directory for a plugin language.
|
|
301
|
+
*/
|
|
302
|
+
getPluginTemplateDir(languageId) {
|
|
303
|
+
const plugin = this.getPlugin(languageId);
|
|
304
|
+
return plugin?.templatePath;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Get the install command for a plugin language.
|
|
308
|
+
*/
|
|
309
|
+
getPluginInstallCommand(languageId) {
|
|
310
|
+
const plugin = this.getPlugin(languageId);
|
|
311
|
+
return plugin?.manifest.installCommand;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Get the run command for a plugin language.
|
|
315
|
+
*/
|
|
316
|
+
getPluginRunCommand(languageId) {
|
|
317
|
+
const plugin = this.getPlugin(languageId);
|
|
318
|
+
return plugin?.manifest.runCommand;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Reset the registry (for testing).
|
|
322
|
+
*/
|
|
323
|
+
reset() {
|
|
324
|
+
this.plugins = [];
|
|
325
|
+
this.initialized = false;
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
var pluginRegistry = new PluginRegistry();
|
|
329
|
+
|
|
93
330
|
// src/prompts/language.ts
|
|
94
331
|
import inquirer2 from "inquirer";
|
|
332
|
+
var BUILTIN_CHOICES = [
|
|
333
|
+
{ name: "TypeScript", value: "typescript" },
|
|
334
|
+
{ name: "Python", value: "python" },
|
|
335
|
+
{ name: "Go", value: "go" },
|
|
336
|
+
{ name: "Rust", value: "rust" },
|
|
337
|
+
{ name: "Java", value: "java" },
|
|
338
|
+
{ name: "Kotlin", value: "kotlin" },
|
|
339
|
+
{ name: "C# (.NET)", value: "csharp" },
|
|
340
|
+
{ name: "Elixir", value: "elixir" }
|
|
341
|
+
];
|
|
95
342
|
async function promptLanguage() {
|
|
343
|
+
const pluginLanguages = pluginRegistry.getPluginLanguages();
|
|
344
|
+
const choices = [...BUILTIN_CHOICES];
|
|
345
|
+
if (pluginLanguages.length > 0) {
|
|
346
|
+
choices.push(new inquirer2.Separator("\u2500\u2500 Plugins \u2500\u2500"));
|
|
347
|
+
for (const lang of pluginLanguages) {
|
|
348
|
+
choices.push({ name: `${lang.name} (plugin)`, value: lang.id });
|
|
349
|
+
}
|
|
350
|
+
}
|
|
96
351
|
const { language } = await inquirer2.prompt([
|
|
97
352
|
{
|
|
98
353
|
type: "list",
|
|
99
354
|
name: "language",
|
|
100
355
|
message: "Select language:",
|
|
101
|
-
choices
|
|
102
|
-
{ name: "TypeScript", value: "typescript" },
|
|
103
|
-
{ name: "Python", value: "python" },
|
|
104
|
-
{ name: "Go", value: "go" },
|
|
105
|
-
{ name: "Rust", value: "rust" }
|
|
106
|
-
],
|
|
356
|
+
choices,
|
|
107
357
|
default: "typescript"
|
|
108
358
|
}
|
|
109
359
|
]);
|
|
@@ -314,10 +564,28 @@ async function promptMultipleResources() {
|
|
|
314
564
|
return resources;
|
|
315
565
|
}
|
|
316
566
|
|
|
317
|
-
// src/prompts/
|
|
567
|
+
// src/prompts/java-build-tool.ts
|
|
318
568
|
import inquirer6 from "inquirer";
|
|
569
|
+
async function promptJavaBuildTool() {
|
|
570
|
+
const { buildTool } = await inquirer6.prompt([
|
|
571
|
+
{
|
|
572
|
+
type: "list",
|
|
573
|
+
name: "buildTool",
|
|
574
|
+
message: "Select Java build tool:",
|
|
575
|
+
choices: [
|
|
576
|
+
{ name: "Maven (pom.xml)", value: "maven" },
|
|
577
|
+
{ name: "Gradle (build.gradle)", value: "gradle" }
|
|
578
|
+
],
|
|
579
|
+
default: "maven"
|
|
580
|
+
}
|
|
581
|
+
]);
|
|
582
|
+
return buildTool;
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// src/prompts/generation-method.ts
|
|
586
|
+
import inquirer7 from "inquirer";
|
|
319
587
|
async function promptGenerationMethod() {
|
|
320
|
-
const { method } = await
|
|
588
|
+
const { method } = await inquirer7.prompt([
|
|
321
589
|
{
|
|
322
590
|
type: "list",
|
|
323
591
|
name: "method",
|
|
@@ -346,8 +614,67 @@ async function promptGenerationMethod() {
|
|
|
346
614
|
return method;
|
|
347
615
|
}
|
|
348
616
|
|
|
617
|
+
// src/types/config.ts
|
|
618
|
+
import { z as z2 } from "zod";
|
|
619
|
+
var BuiltinLanguageSchema = z2.enum([
|
|
620
|
+
"typescript",
|
|
621
|
+
"python",
|
|
622
|
+
"go",
|
|
623
|
+
"rust",
|
|
624
|
+
"java",
|
|
625
|
+
"kotlin",
|
|
626
|
+
"csharp",
|
|
627
|
+
"elixir"
|
|
628
|
+
]);
|
|
629
|
+
var LanguageSchema = z2.string();
|
|
630
|
+
var BUILTIN_LANGUAGES = [
|
|
631
|
+
"typescript",
|
|
632
|
+
"python",
|
|
633
|
+
"go",
|
|
634
|
+
"rust",
|
|
635
|
+
"java",
|
|
636
|
+
"kotlin",
|
|
637
|
+
"csharp",
|
|
638
|
+
"elixir"
|
|
639
|
+
];
|
|
640
|
+
function isBuiltinLanguage(lang) {
|
|
641
|
+
return BUILTIN_LANGUAGES.includes(lang);
|
|
642
|
+
}
|
|
643
|
+
var JavaBuildToolSchema = z2.enum(["maven", "gradle"]);
|
|
644
|
+
var TransportSchema = z2.enum(["stdio", "sse"]);
|
|
645
|
+
var ToolParameterSchema = z2.object({
|
|
646
|
+
name: z2.string(),
|
|
647
|
+
type: z2.enum(["string", "number", "boolean", "object", "array"]),
|
|
648
|
+
description: z2.string(),
|
|
649
|
+
required: z2.boolean().default(true)
|
|
650
|
+
});
|
|
651
|
+
var ToolConfigSchema = z2.object({
|
|
652
|
+
name: z2.string(),
|
|
653
|
+
description: z2.string(),
|
|
654
|
+
parameters: z2.array(ToolParameterSchema).default([])
|
|
655
|
+
});
|
|
656
|
+
var ResourceConfigSchema = z2.object({
|
|
657
|
+
name: z2.string(),
|
|
658
|
+
uri: z2.string(),
|
|
659
|
+
description: z2.string(),
|
|
660
|
+
mimeType: z2.string().optional()
|
|
661
|
+
});
|
|
662
|
+
var ProjectConfigSchema = z2.object({
|
|
663
|
+
name: z2.string().min(1, "Project name is required"),
|
|
664
|
+
description: z2.string().default(""),
|
|
665
|
+
language: LanguageSchema,
|
|
666
|
+
transport: TransportSchema,
|
|
667
|
+
tools: z2.array(ToolConfigSchema).default([]),
|
|
668
|
+
resources: z2.array(ResourceConfigSchema).default([]),
|
|
669
|
+
includeExampleTool: z2.boolean().default(true),
|
|
670
|
+
skipInstall: z2.boolean().default(false),
|
|
671
|
+
initGit: z2.boolean().default(true),
|
|
672
|
+
javaBuildTool: JavaBuildToolSchema.optional()
|
|
673
|
+
});
|
|
674
|
+
var PresetIdSchema = z2.enum(["database", "rest-api", "filesystem"]);
|
|
675
|
+
|
|
349
676
|
// src/prompts/preset.ts
|
|
350
|
-
import
|
|
677
|
+
import inquirer8 from "inquirer";
|
|
351
678
|
|
|
352
679
|
// src/presets/database.ts
|
|
353
680
|
var DATABASE_PRESET = {
|
|
@@ -657,6 +984,230 @@ var FILESYSTEM_PRESET = {
|
|
|
657
984
|
]
|
|
658
985
|
};
|
|
659
986
|
|
|
987
|
+
// src/types/marketplace.ts
|
|
988
|
+
import { z as z3 } from "zod";
|
|
989
|
+
var ExternalPresetManifestSchema = z3.object({
|
|
990
|
+
id: z3.string(),
|
|
991
|
+
name: z3.string(),
|
|
992
|
+
description: z3.string(),
|
|
993
|
+
version: z3.string(),
|
|
994
|
+
tools: z3.array(ToolConfigSchema),
|
|
995
|
+
author: z3.string().optional(),
|
|
996
|
+
repository: z3.string().optional()
|
|
997
|
+
});
|
|
998
|
+
var CACHE_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
999
|
+
function parsePresetIdentifier(identifier) {
|
|
1000
|
+
if (identifier.startsWith("github:")) {
|
|
1001
|
+
return {
|
|
1002
|
+
type: "github",
|
|
1003
|
+
identifier: identifier.replace("github:", "")
|
|
1004
|
+
};
|
|
1005
|
+
}
|
|
1006
|
+
if (identifier.startsWith("@")) {
|
|
1007
|
+
return {
|
|
1008
|
+
type: "npm",
|
|
1009
|
+
identifier
|
|
1010
|
+
};
|
|
1011
|
+
}
|
|
1012
|
+
return {
|
|
1013
|
+
type: "local",
|
|
1014
|
+
identifier
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
function isExternalPreset(identifier) {
|
|
1018
|
+
return identifier.startsWith("@") || identifier.startsWith("github:");
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
// src/marketplace/preset-resolver.ts
|
|
1022
|
+
import path4 from "path";
|
|
1023
|
+
import os2 from "os";
|
|
1024
|
+
import { execa } from "execa";
|
|
1025
|
+
import * as tar from "tar";
|
|
1026
|
+
|
|
1027
|
+
// src/marketplace/cache.ts
|
|
1028
|
+
import path3 from "path";
|
|
1029
|
+
import os from "os";
|
|
1030
|
+
var CACHE_DIR = path3.join(os.homedir(), ".mcp-new", "preset-cache");
|
|
1031
|
+
function getCacheFilePath(source) {
|
|
1032
|
+
const safeId = source.identifier.replace(/[^a-zA-Z0-9]/g, "_");
|
|
1033
|
+
return path3.join(CACHE_DIR, `${source.type}_${safeId}.json`);
|
|
1034
|
+
}
|
|
1035
|
+
async function getCachedPreset(source) {
|
|
1036
|
+
const cacheFile = getCacheFilePath(source);
|
|
1037
|
+
if (!await exists(cacheFile)) {
|
|
1038
|
+
return null;
|
|
1039
|
+
}
|
|
1040
|
+
try {
|
|
1041
|
+
const content = await readFile(cacheFile);
|
|
1042
|
+
const cached = JSON.parse(content);
|
|
1043
|
+
const now = Date.now();
|
|
1044
|
+
if (now - cached.cachedAt > CACHE_TTL_MS) {
|
|
1045
|
+
return null;
|
|
1046
|
+
}
|
|
1047
|
+
return cached;
|
|
1048
|
+
} catch {
|
|
1049
|
+
return null;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
async function setCachedPreset(source, manifest) {
|
|
1053
|
+
await ensureDir(CACHE_DIR);
|
|
1054
|
+
const cached = {
|
|
1055
|
+
manifest,
|
|
1056
|
+
cachedAt: Date.now(),
|
|
1057
|
+
source
|
|
1058
|
+
};
|
|
1059
|
+
const cacheFile = getCacheFilePath(source);
|
|
1060
|
+
await writeFile(cacheFile, JSON.stringify(cached, null, 2));
|
|
1061
|
+
}
|
|
1062
|
+
async function clearPresetCache() {
|
|
1063
|
+
if (!await exists(CACHE_DIR)) {
|
|
1064
|
+
return 0;
|
|
1065
|
+
}
|
|
1066
|
+
try {
|
|
1067
|
+
const { readdir, stat, unlink } = await import("fs/promises");
|
|
1068
|
+
const files = await readdir(CACHE_DIR);
|
|
1069
|
+
let count = 0;
|
|
1070
|
+
for (const file of files) {
|
|
1071
|
+
if (file.endsWith(".json")) {
|
|
1072
|
+
await unlink(path3.join(CACHE_DIR, file));
|
|
1073
|
+
count++;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
return count;
|
|
1077
|
+
} catch {
|
|
1078
|
+
return 0;
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
async function listCachedPresets() {
|
|
1082
|
+
if (!await exists(CACHE_DIR)) {
|
|
1083
|
+
return [];
|
|
1084
|
+
}
|
|
1085
|
+
try {
|
|
1086
|
+
const { readdir } = await import("fs/promises");
|
|
1087
|
+
const files = await readdir(CACHE_DIR);
|
|
1088
|
+
const presets = [];
|
|
1089
|
+
for (const file of files) {
|
|
1090
|
+
if (file.endsWith(".json")) {
|
|
1091
|
+
try {
|
|
1092
|
+
const content = await readFile(path3.join(CACHE_DIR, file));
|
|
1093
|
+
const cached = JSON.parse(content);
|
|
1094
|
+
presets.push(cached);
|
|
1095
|
+
} catch {
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
return presets;
|
|
1100
|
+
} catch {
|
|
1101
|
+
return [];
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
function getCacheDir() {
|
|
1105
|
+
return CACHE_DIR;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
// src/marketplace/preset-resolver.ts
|
|
1109
|
+
var TEMP_DIR = path4.join(os2.tmpdir(), "mcp-new-presets");
|
|
1110
|
+
async function resolveExternalPreset(source) {
|
|
1111
|
+
const cached = await getCachedPreset(source);
|
|
1112
|
+
if (cached) {
|
|
1113
|
+
return cached.manifest;
|
|
1114
|
+
}
|
|
1115
|
+
let manifest;
|
|
1116
|
+
switch (source.type) {
|
|
1117
|
+
case "npm":
|
|
1118
|
+
manifest = await resolveNpmPreset(source.identifier);
|
|
1119
|
+
break;
|
|
1120
|
+
case "github":
|
|
1121
|
+
manifest = await resolveGitHubPreset(source.identifier);
|
|
1122
|
+
break;
|
|
1123
|
+
default:
|
|
1124
|
+
throw new Error(`Unknown preset source type: ${source.type}`);
|
|
1125
|
+
}
|
|
1126
|
+
await setCachedPreset(source, manifest);
|
|
1127
|
+
return manifest;
|
|
1128
|
+
}
|
|
1129
|
+
async function resolveNpmPreset(packageName) {
|
|
1130
|
+
await ensureDir(TEMP_DIR);
|
|
1131
|
+
const extractDir = path4.join(TEMP_DIR, `npm_${packageName.replace(/[^a-zA-Z0-9]/g, "_")}`);
|
|
1132
|
+
try {
|
|
1133
|
+
if (await exists(extractDir)) {
|
|
1134
|
+
await remove(extractDir);
|
|
1135
|
+
}
|
|
1136
|
+
await ensureDir(extractDir);
|
|
1137
|
+
const { stdout } = await execa("npm", ["pack", packageName, "--pack-destination", extractDir], {
|
|
1138
|
+
cwd: extractDir
|
|
1139
|
+
});
|
|
1140
|
+
const tarballName = stdout.trim();
|
|
1141
|
+
const tarballPath = path4.join(extractDir, tarballName);
|
|
1142
|
+
await tar.x({
|
|
1143
|
+
file: tarballPath,
|
|
1144
|
+
cwd: extractDir
|
|
1145
|
+
});
|
|
1146
|
+
const manifestPath = path4.join(extractDir, "package", "mcp-preset.json");
|
|
1147
|
+
if (!await exists(manifestPath)) {
|
|
1148
|
+
throw new Error(
|
|
1149
|
+
`Invalid preset package: ${packageName} - missing mcp-preset.json manifest file`
|
|
1150
|
+
);
|
|
1151
|
+
}
|
|
1152
|
+
const manifestContent = await readFile(manifestPath);
|
|
1153
|
+
const rawManifest = JSON.parse(manifestContent);
|
|
1154
|
+
const manifest = ExternalPresetManifestSchema.parse(rawManifest);
|
|
1155
|
+
return manifest;
|
|
1156
|
+
} finally {
|
|
1157
|
+
try {
|
|
1158
|
+
if (await exists(extractDir)) {
|
|
1159
|
+
await remove(extractDir);
|
|
1160
|
+
}
|
|
1161
|
+
} catch {
|
|
1162
|
+
}
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
async function resolveGitHubPreset(repoPath) {
|
|
1166
|
+
const [repo, branch = "main"] = repoPath.split("@");
|
|
1167
|
+
const [owner, repoName] = repo.split("/");
|
|
1168
|
+
if (!owner || !repoName) {
|
|
1169
|
+
throw new Error(`Invalid GitHub preset format: ${repoPath}. Expected: user/repo[@branch]`);
|
|
1170
|
+
}
|
|
1171
|
+
await ensureDir(TEMP_DIR);
|
|
1172
|
+
const extractDir = path4.join(TEMP_DIR, `github_${owner}_${repoName}`);
|
|
1173
|
+
try {
|
|
1174
|
+
if (await exists(extractDir)) {
|
|
1175
|
+
await remove(extractDir);
|
|
1176
|
+
}
|
|
1177
|
+
await ensureDir(extractDir);
|
|
1178
|
+
const tarballUrl = `https://github.com/${owner}/${repoName}/archive/refs/heads/${branch}.tar.gz`;
|
|
1179
|
+
const tarballPath = path4.join(extractDir, "repo.tar.gz");
|
|
1180
|
+
await execa("curl", ["-L", "-o", tarballPath, tarballUrl]);
|
|
1181
|
+
await tar.x({
|
|
1182
|
+
file: tarballPath,
|
|
1183
|
+
cwd: extractDir
|
|
1184
|
+
});
|
|
1185
|
+
const { readdir } = await import("fs/promises");
|
|
1186
|
+
const entries = await readdir(extractDir);
|
|
1187
|
+
const repoDir = entries.find((e) => e.startsWith(`${repoName}-`));
|
|
1188
|
+
if (!repoDir) {
|
|
1189
|
+
throw new Error(`Failed to extract GitHub repository: ${repoPath}`);
|
|
1190
|
+
}
|
|
1191
|
+
const manifestPath = path4.join(extractDir, repoDir, "mcp-preset.json");
|
|
1192
|
+
if (!await exists(manifestPath)) {
|
|
1193
|
+
throw new Error(
|
|
1194
|
+
`Invalid preset repository: ${repoPath} - missing mcp-preset.json manifest file`
|
|
1195
|
+
);
|
|
1196
|
+
}
|
|
1197
|
+
const manifestContent = await readFile(manifestPath);
|
|
1198
|
+
const rawManifest = JSON.parse(manifestContent);
|
|
1199
|
+
const manifest = ExternalPresetManifestSchema.parse(rawManifest);
|
|
1200
|
+
return manifest;
|
|
1201
|
+
} finally {
|
|
1202
|
+
try {
|
|
1203
|
+
if (await exists(extractDir)) {
|
|
1204
|
+
await remove(extractDir);
|
|
1205
|
+
}
|
|
1206
|
+
} catch {
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
|
|
660
1211
|
// src/presets/index.ts
|
|
661
1212
|
var PRESETS = {
|
|
662
1213
|
database: DATABASE_PRESET,
|
|
@@ -670,6 +1221,28 @@ function getPreset(id) {
|
|
|
670
1221
|
function isValidPresetId(id) {
|
|
671
1222
|
return id in PRESETS;
|
|
672
1223
|
}
|
|
1224
|
+
async function getPresetByIdentifier(identifier) {
|
|
1225
|
+
if (!isExternalPreset(identifier)) {
|
|
1226
|
+
const preset = getPreset(identifier);
|
|
1227
|
+
if (!preset) {
|
|
1228
|
+
throw new Error(
|
|
1229
|
+
`Unknown preset: ${identifier}. Valid local presets: ${PRESET_IDS.join(", ")}`
|
|
1230
|
+
);
|
|
1231
|
+
}
|
|
1232
|
+
return preset;
|
|
1233
|
+
}
|
|
1234
|
+
const source = parsePresetIdentifier(identifier);
|
|
1235
|
+
const manifest = await resolveExternalPreset(source);
|
|
1236
|
+
return externalManifestToPreset(manifest);
|
|
1237
|
+
}
|
|
1238
|
+
function externalManifestToPreset(manifest) {
|
|
1239
|
+
return {
|
|
1240
|
+
id: manifest.id,
|
|
1241
|
+
name: manifest.name,
|
|
1242
|
+
description: manifest.description,
|
|
1243
|
+
tools: manifest.tools
|
|
1244
|
+
};
|
|
1245
|
+
}
|
|
673
1246
|
|
|
674
1247
|
// src/prompts/preset.ts
|
|
675
1248
|
async function promptPreset() {
|
|
@@ -677,7 +1250,7 @@ async function promptPreset() {
|
|
|
677
1250
|
name: `${preset2.name} - ${preset2.description}`,
|
|
678
1251
|
value: preset2.id
|
|
679
1252
|
}));
|
|
680
|
-
const { preset } = await
|
|
1253
|
+
const { preset } = await inquirer8.prompt([
|
|
681
1254
|
{
|
|
682
1255
|
type: "list",
|
|
683
1256
|
name: "preset",
|
|
@@ -689,6 +1262,24 @@ async function promptPreset() {
|
|
|
689
1262
|
return preset;
|
|
690
1263
|
}
|
|
691
1264
|
|
|
1265
|
+
// src/prompts/ci-provider.ts
|
|
1266
|
+
import inquirer9 from "inquirer";
|
|
1267
|
+
async function promptCIProvider() {
|
|
1268
|
+
const { provider } = await inquirer9.prompt([
|
|
1269
|
+
{
|
|
1270
|
+
type: "list",
|
|
1271
|
+
name: "provider",
|
|
1272
|
+
message: "Which CI/CD provider would you like to use?",
|
|
1273
|
+
choices: [
|
|
1274
|
+
{ name: "GitHub Actions", value: "github" },
|
|
1275
|
+
{ name: "GitLab CI", value: "gitlab" },
|
|
1276
|
+
{ name: "CircleCI", value: "circleci" }
|
|
1277
|
+
]
|
|
1278
|
+
}
|
|
1279
|
+
]);
|
|
1280
|
+
return provider;
|
|
1281
|
+
}
|
|
1282
|
+
|
|
692
1283
|
// src/prompts/index.ts
|
|
693
1284
|
async function runWizard(options = {}) {
|
|
694
1285
|
const name = await promptProjectName(options.defaultName);
|
|
@@ -697,6 +1288,10 @@ async function runWizard(options = {}) {
|
|
|
697
1288
|
description = await promptProjectDescription();
|
|
698
1289
|
}
|
|
699
1290
|
const language = options.presetLanguage || await promptLanguage();
|
|
1291
|
+
let javaBuildTool;
|
|
1292
|
+
if (language === "java" || language === "kotlin") {
|
|
1293
|
+
javaBuildTool = options.presetJavaBuildTool || await promptJavaBuildTool();
|
|
1294
|
+
}
|
|
700
1295
|
const transport = await promptTransport();
|
|
701
1296
|
const includeExampleTool = await promptIncludeExampleTool();
|
|
702
1297
|
let tools = [];
|
|
@@ -720,14 +1315,19 @@ async function runWizard(options = {}) {
|
|
|
720
1315
|
resources,
|
|
721
1316
|
includeExampleTool,
|
|
722
1317
|
skipInstall: false,
|
|
723
|
-
initGit: true
|
|
1318
|
+
initGit: true,
|
|
1319
|
+
javaBuildTool
|
|
724
1320
|
};
|
|
725
1321
|
}
|
|
726
|
-
async function runQuickWizard(defaultName, presetLanguage) {
|
|
727
|
-
const name = await promptProjectName(
|
|
1322
|
+
async function runQuickWizard(defaultName, presetLanguage, presetJavaBuildTool) {
|
|
1323
|
+
const name = defaultName || await promptProjectName();
|
|
728
1324
|
const language = presetLanguage || await promptLanguage();
|
|
729
|
-
|
|
730
|
-
|
|
1325
|
+
let javaBuildTool;
|
|
1326
|
+
if (language === "java" || language === "kotlin") {
|
|
1327
|
+
javaBuildTool = presetJavaBuildTool || await promptJavaBuildTool();
|
|
1328
|
+
}
|
|
1329
|
+
const transport = "stdio";
|
|
1330
|
+
const includeExampleTool = true;
|
|
731
1331
|
return {
|
|
732
1332
|
name,
|
|
733
1333
|
description: "",
|
|
@@ -737,102 +1337,33 @@ async function runQuickWizard(defaultName, presetLanguage) {
|
|
|
737
1337
|
resources: [],
|
|
738
1338
|
includeExampleTool,
|
|
739
1339
|
skipInstall: false,
|
|
740
|
-
initGit: true
|
|
1340
|
+
initGit: true,
|
|
1341
|
+
javaBuildTool
|
|
741
1342
|
};
|
|
742
1343
|
}
|
|
743
1344
|
|
|
744
|
-
// src/utils/file-system.ts
|
|
745
|
-
import fs from "fs-extra";
|
|
746
|
-
import path from "path";
|
|
747
|
-
import ejs from "ejs";
|
|
748
|
-
async function ensureDir(dirPath) {
|
|
749
|
-
await fs.ensureDir(dirPath);
|
|
750
|
-
}
|
|
751
|
-
async function writeFile(filePath, content) {
|
|
752
|
-
await fs.ensureDir(path.dirname(filePath));
|
|
753
|
-
await fs.writeFile(filePath, content, "utf-8");
|
|
754
|
-
}
|
|
755
|
-
async function readFile(filePath) {
|
|
756
|
-
return fs.readFile(filePath, "utf-8");
|
|
757
|
-
}
|
|
758
|
-
async function copyFile(src, dest) {
|
|
759
|
-
await fs.ensureDir(path.dirname(dest));
|
|
760
|
-
await fs.copyFile(src, dest);
|
|
761
|
-
}
|
|
762
|
-
async function copyDir(src, dest) {
|
|
763
|
-
await fs.copy(src, dest);
|
|
764
|
-
}
|
|
765
|
-
async function exists(filePath) {
|
|
766
|
-
return fs.pathExists(filePath);
|
|
767
|
-
}
|
|
768
|
-
async function remove(filePath) {
|
|
769
|
-
await fs.remove(filePath);
|
|
770
|
-
}
|
|
771
|
-
async function readDir(dirPath) {
|
|
772
|
-
return fs.readdir(dirPath);
|
|
773
|
-
}
|
|
774
|
-
async function isDirectory(filePath) {
|
|
775
|
-
try {
|
|
776
|
-
const stat = await fs.stat(filePath);
|
|
777
|
-
return stat.isDirectory();
|
|
778
|
-
} catch {
|
|
779
|
-
return false;
|
|
780
|
-
}
|
|
781
|
-
}
|
|
782
|
-
async function renderTemplate(templatePath, data) {
|
|
783
|
-
const template = await readFile(templatePath);
|
|
784
|
-
return ejs.render(template, data, { async: false });
|
|
785
|
-
}
|
|
786
|
-
async function renderTemplateToFile(templatePath, outputPath, data) {
|
|
787
|
-
const content = await renderTemplate(templatePath, data);
|
|
788
|
-
const finalPath = outputPath.replace(/\.ejs$/, "");
|
|
789
|
-
await writeFile(finalPath, content);
|
|
790
|
-
}
|
|
791
|
-
async function walkDir(dirPath, callback) {
|
|
792
|
-
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
793
|
-
for (const entry of entries) {
|
|
794
|
-
const fullPath = path.join(dirPath, entry.name);
|
|
795
|
-
const isDir = entry.isDirectory();
|
|
796
|
-
await callback(fullPath, isDir);
|
|
797
|
-
if (isDir) {
|
|
798
|
-
await walkDir(fullPath, callback);
|
|
799
|
-
}
|
|
800
|
-
}
|
|
801
|
-
}
|
|
802
|
-
function getTemplateDir() {
|
|
803
|
-
const devPath = path.join(import.meta.dirname, "..", "templates");
|
|
804
|
-
const prodPath = path.join(import.meta.dirname, "..", "..", "templates");
|
|
805
|
-
if (fs.existsSync(devPath)) {
|
|
806
|
-
return devPath;
|
|
807
|
-
}
|
|
808
|
-
return prodPath;
|
|
809
|
-
}
|
|
810
|
-
function resolveOutputPath(basePath, ...segments) {
|
|
811
|
-
return path.resolve(basePath, ...segments);
|
|
812
|
-
}
|
|
813
|
-
|
|
814
1345
|
// src/utils/git.ts
|
|
815
|
-
import { execa } from "execa";
|
|
816
|
-
import
|
|
1346
|
+
import { execa as execa2 } from "execa";
|
|
1347
|
+
import path5 from "path";
|
|
817
1348
|
async function isGitInstalled() {
|
|
818
1349
|
try {
|
|
819
|
-
await
|
|
1350
|
+
await execa2("git", ["--version"]);
|
|
820
1351
|
return true;
|
|
821
1352
|
} catch {
|
|
822
1353
|
return false;
|
|
823
1354
|
}
|
|
824
1355
|
}
|
|
825
1356
|
async function initGitRepository(projectPath) {
|
|
826
|
-
const gitDir =
|
|
1357
|
+
const gitDir = path5.join(projectPath, ".git");
|
|
827
1358
|
if (await exists(gitDir)) {
|
|
828
1359
|
return;
|
|
829
1360
|
}
|
|
830
|
-
await
|
|
1361
|
+
await execa2("git", ["init"], { cwd: projectPath });
|
|
831
1362
|
}
|
|
832
1363
|
async function createInitialCommit(projectPath) {
|
|
833
1364
|
try {
|
|
834
|
-
await
|
|
835
|
-
await
|
|
1365
|
+
await execa2("git", ["add", "."], { cwd: projectPath });
|
|
1366
|
+
await execa2("git", ["commit", "-m", "Initial commit from create-mcp-server"], {
|
|
836
1367
|
cwd: projectPath
|
|
837
1368
|
});
|
|
838
1369
|
} catch {
|
|
@@ -841,8 +1372,8 @@ async function createInitialCommit(projectPath) {
|
|
|
841
1372
|
async function getGitUser() {
|
|
842
1373
|
try {
|
|
843
1374
|
const [nameResult, emailResult] = await Promise.all([
|
|
844
|
-
|
|
845
|
-
|
|
1375
|
+
execa2("git", ["config", "--get", "user.name"]).catch(() => ({ stdout: "" })),
|
|
1376
|
+
execa2("git", ["config", "--get", "user.email"]).catch(() => ({ stdout: "" }))
|
|
846
1377
|
]);
|
|
847
1378
|
return {
|
|
848
1379
|
name: nameResult.stdout.trim() || void 0,
|
|
@@ -854,7 +1385,7 @@ async function getGitUser() {
|
|
|
854
1385
|
}
|
|
855
1386
|
async function isInsideGitRepository(dirPath) {
|
|
856
1387
|
try {
|
|
857
|
-
await
|
|
1388
|
+
await execa2("git", ["rev-parse", "--is-inside-work-tree"], { cwd: dirPath });
|
|
858
1389
|
return true;
|
|
859
1390
|
} catch {
|
|
860
1391
|
return false;
|
|
@@ -903,30 +1434,55 @@ var logger = {
|
|
|
903
1434
|
});
|
|
904
1435
|
console.log(chalk.green("\u2514\u2500"));
|
|
905
1436
|
},
|
|
906
|
-
nextSteps: (projectName, language) => {
|
|
1437
|
+
nextSteps: (projectName, language, javaBuildTool) => {
|
|
907
1438
|
logger.blank();
|
|
908
1439
|
let installCmd;
|
|
909
1440
|
let runCmd;
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
1441
|
+
if (!isBuiltinLanguage(language)) {
|
|
1442
|
+
const pluginInstallCmd = pluginRegistry.getPluginInstallCommand(language);
|
|
1443
|
+
const pluginRunCmd = pluginRegistry.getPluginRunCommand(language);
|
|
1444
|
+
installCmd = pluginInstallCmd || "# See plugin documentation for install command";
|
|
1445
|
+
runCmd = pluginRunCmd || "# See plugin documentation for run command";
|
|
1446
|
+
} else {
|
|
1447
|
+
switch (language) {
|
|
1448
|
+
case "typescript":
|
|
1449
|
+
installCmd = "npm install";
|
|
1450
|
+
runCmd = "npm run dev";
|
|
1451
|
+
break;
|
|
1452
|
+
case "python":
|
|
1453
|
+
installCmd = "pip install -e .";
|
|
1454
|
+
runCmd = "python -m src.server";
|
|
1455
|
+
break;
|
|
1456
|
+
case "go":
|
|
1457
|
+
installCmd = "go mod download";
|
|
1458
|
+
runCmd = "go run ./cmd/server";
|
|
1459
|
+
break;
|
|
1460
|
+
case "rust":
|
|
1461
|
+
installCmd = "cargo build";
|
|
1462
|
+
runCmd = "cargo run";
|
|
1463
|
+
break;
|
|
1464
|
+
case "java":
|
|
1465
|
+
case "kotlin":
|
|
1466
|
+
if (javaBuildTool === "gradle") {
|
|
1467
|
+
installCmd = "./gradlew build";
|
|
1468
|
+
runCmd = "./gradlew run";
|
|
1469
|
+
} else {
|
|
1470
|
+
installCmd = "mvn install";
|
|
1471
|
+
runCmd = 'mvn exec:java -Dexec.mainClass="com.example.mcp.McpServer"';
|
|
1472
|
+
}
|
|
1473
|
+
break;
|
|
1474
|
+
case "csharp":
|
|
1475
|
+
installCmd = "dotnet restore";
|
|
1476
|
+
runCmd = "dotnet run";
|
|
1477
|
+
break;
|
|
1478
|
+
case "elixir":
|
|
1479
|
+
installCmd = "mix deps.get";
|
|
1480
|
+
runCmd = "mix run --no-halt";
|
|
1481
|
+
break;
|
|
1482
|
+
default:
|
|
1483
|
+
installCmd = "npm install";
|
|
1484
|
+
runCmd = "npm run dev";
|
|
1485
|
+
}
|
|
930
1486
|
}
|
|
931
1487
|
logger.box("Next steps:", [
|
|
932
1488
|
"",
|
|
@@ -995,8 +1551,8 @@ async function withSpinner(text, fn, successText, failText) {
|
|
|
995
1551
|
}
|
|
996
1552
|
|
|
997
1553
|
// src/generators/base.ts
|
|
998
|
-
import
|
|
999
|
-
import { execa as
|
|
1554
|
+
import path6 from "path";
|
|
1555
|
+
import { execa as execa3 } from "execa";
|
|
1000
1556
|
var BaseGenerator = class {
|
|
1001
1557
|
config;
|
|
1002
1558
|
outputDir;
|
|
@@ -1008,14 +1564,14 @@ var BaseGenerator = class {
|
|
|
1008
1564
|
}
|
|
1009
1565
|
async createProjectStructure() {
|
|
1010
1566
|
await ensureDir(this.outputDir);
|
|
1011
|
-
await ensureDir(
|
|
1567
|
+
await ensureDir(path6.join(this.outputDir, "src"));
|
|
1012
1568
|
}
|
|
1013
1569
|
async renderTemplates() {
|
|
1014
1570
|
const templateData = this.getTemplateData();
|
|
1015
1571
|
await walkDir(this.templateDir, async (filePath, isDir) => {
|
|
1016
1572
|
if (isDir) return;
|
|
1017
|
-
const relativePath =
|
|
1018
|
-
const outputPath =
|
|
1573
|
+
const relativePath = path6.relative(this.templateDir, filePath);
|
|
1574
|
+
const outputPath = path6.join(this.outputDir, relativePath);
|
|
1019
1575
|
if (filePath.endsWith(".ejs")) {
|
|
1020
1576
|
await renderTemplateToFile(filePath, outputPath, templateData);
|
|
1021
1577
|
} else {
|
|
@@ -1024,6 +1580,8 @@ var BaseGenerator = class {
|
|
|
1024
1580
|
});
|
|
1025
1581
|
}
|
|
1026
1582
|
getTemplateData() {
|
|
1583
|
+
const cleanName = this.config.name.replace(/[^a-zA-Z0-9]/g, "");
|
|
1584
|
+
const capitalizedName = cleanName.charAt(0).toUpperCase() + cleanName.slice(1);
|
|
1027
1585
|
return {
|
|
1028
1586
|
name: this.config.name,
|
|
1029
1587
|
description: this.config.description,
|
|
@@ -1031,7 +1589,12 @@ var BaseGenerator = class {
|
|
|
1031
1589
|
transport: this.config.transport,
|
|
1032
1590
|
tools: this.config.tools,
|
|
1033
1591
|
resources: this.config.resources,
|
|
1034
|
-
includeExampleTool: this.config.includeExampleTool
|
|
1592
|
+
includeExampleTool: this.config.includeExampleTool,
|
|
1593
|
+
javaBuildTool: this.config.javaBuildTool,
|
|
1594
|
+
// Helper for Java/Elixir package name (lowercase, no special chars)
|
|
1595
|
+
packageName: this.config.name.toLowerCase().replace(/[^a-z0-9]/g, ""),
|
|
1596
|
+
// Helper for C#/Elixir namespace (PascalCase)
|
|
1597
|
+
namespace: capitalizedName
|
|
1035
1598
|
};
|
|
1036
1599
|
}
|
|
1037
1600
|
async installDependencies() {
|
|
@@ -1039,6 +1602,10 @@ var BaseGenerator = class {
|
|
|
1039
1602
|
logger.info("Skipping dependency installation (--skip-install)");
|
|
1040
1603
|
return;
|
|
1041
1604
|
}
|
|
1605
|
+
if (!isBuiltinLanguage(this.config.language)) {
|
|
1606
|
+
await this.installPluginDependencies();
|
|
1607
|
+
return;
|
|
1608
|
+
}
|
|
1042
1609
|
switch (this.config.language) {
|
|
1043
1610
|
case "typescript":
|
|
1044
1611
|
await this.installNodeDependencies();
|
|
@@ -1052,13 +1619,39 @@ var BaseGenerator = class {
|
|
|
1052
1619
|
case "rust":
|
|
1053
1620
|
await this.installRustDependencies();
|
|
1054
1621
|
break;
|
|
1622
|
+
case "java":
|
|
1623
|
+
case "kotlin":
|
|
1624
|
+
await this.installJavaDependencies();
|
|
1625
|
+
break;
|
|
1626
|
+
case "csharp":
|
|
1627
|
+
await this.installDotnetDependencies();
|
|
1628
|
+
break;
|
|
1629
|
+
case "elixir":
|
|
1630
|
+
await this.installElixirDependencies();
|
|
1631
|
+
break;
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
async installPluginDependencies() {
|
|
1635
|
+
const installCommand = pluginRegistry.getPluginInstallCommand(this.config.language);
|
|
1636
|
+
if (!installCommand) {
|
|
1637
|
+
logger.info(`No install command defined for plugin language: ${this.config.language}`);
|
|
1638
|
+
return;
|
|
1055
1639
|
}
|
|
1640
|
+
await withSpinner(
|
|
1641
|
+
"Installing dependencies...",
|
|
1642
|
+
async () => {
|
|
1643
|
+
const [cmd, ...args] = installCommand.split(" ");
|
|
1644
|
+
await execa3(cmd, args, { cwd: this.outputDir });
|
|
1645
|
+
},
|
|
1646
|
+
"Dependencies installed",
|
|
1647
|
+
"Failed to install dependencies"
|
|
1648
|
+
);
|
|
1056
1649
|
}
|
|
1057
1650
|
async installNodeDependencies() {
|
|
1058
1651
|
await withSpinner(
|
|
1059
1652
|
"Installing dependencies...",
|
|
1060
1653
|
async () => {
|
|
1061
|
-
await
|
|
1654
|
+
await execa3("npm", ["install"], { cwd: this.outputDir });
|
|
1062
1655
|
},
|
|
1063
1656
|
"Dependencies installed",
|
|
1064
1657
|
"Failed to install dependencies"
|
|
@@ -1076,7 +1669,7 @@ var BaseGenerator = class {
|
|
|
1076
1669
|
await withSpinner(
|
|
1077
1670
|
"Installing dependencies...",
|
|
1078
1671
|
async () => {
|
|
1079
|
-
await
|
|
1672
|
+
await execa3(pipCommand, ["install", "-r", "requirements.txt"], {
|
|
1080
1673
|
cwd: this.outputDir
|
|
1081
1674
|
});
|
|
1082
1675
|
},
|
|
@@ -1094,10 +1687,10 @@ var BaseGenerator = class {
|
|
|
1094
1687
|
await withSpinner(
|
|
1095
1688
|
"Installing Go dependencies...",
|
|
1096
1689
|
async () => {
|
|
1097
|
-
await
|
|
1690
|
+
await execa3("go", ["mod", "download"], {
|
|
1098
1691
|
cwd: this.outputDir
|
|
1099
1692
|
});
|
|
1100
|
-
await
|
|
1693
|
+
await execa3("go", ["mod", "tidy"], {
|
|
1101
1694
|
cwd: this.outputDir
|
|
1102
1695
|
});
|
|
1103
1696
|
},
|
|
@@ -1115,7 +1708,7 @@ var BaseGenerator = class {
|
|
|
1115
1708
|
await withSpinner(
|
|
1116
1709
|
"Building Rust project...",
|
|
1117
1710
|
async () => {
|
|
1118
|
-
await
|
|
1711
|
+
await execa3("cargo", ["build"], {
|
|
1119
1712
|
cwd: this.outputDir
|
|
1120
1713
|
});
|
|
1121
1714
|
},
|
|
@@ -1123,10 +1716,92 @@ var BaseGenerator = class {
|
|
|
1123
1716
|
"Failed to build project"
|
|
1124
1717
|
);
|
|
1125
1718
|
}
|
|
1719
|
+
async installJavaDependencies() {
|
|
1720
|
+
const buildTool = this.config.javaBuildTool || "maven";
|
|
1721
|
+
if (buildTool === "maven") {
|
|
1722
|
+
const hasMvn = await this.checkCommand("mvn");
|
|
1723
|
+
if (!hasMvn) {
|
|
1724
|
+
logger.warning("Maven not found. Please install dependencies manually:");
|
|
1725
|
+
logger.code("mvn install");
|
|
1726
|
+
return;
|
|
1727
|
+
}
|
|
1728
|
+
await withSpinner(
|
|
1729
|
+
"Installing Maven dependencies...",
|
|
1730
|
+
async () => {
|
|
1731
|
+
await execa3("mvn", ["install", "-DskipTests"], {
|
|
1732
|
+
cwd: this.outputDir
|
|
1733
|
+
});
|
|
1734
|
+
},
|
|
1735
|
+
"Dependencies installed",
|
|
1736
|
+
"Failed to install dependencies"
|
|
1737
|
+
);
|
|
1738
|
+
} else {
|
|
1739
|
+
const hasGradle = await this.checkCommand("gradle");
|
|
1740
|
+
const hasGradlew = await exists(path6.join(this.outputDir, "gradlew"));
|
|
1741
|
+
if (!hasGradle && !hasGradlew) {
|
|
1742
|
+
logger.warning("Gradle not found. Please install dependencies manually:");
|
|
1743
|
+
logger.code("gradle build");
|
|
1744
|
+
return;
|
|
1745
|
+
}
|
|
1746
|
+
const gradleCmd = hasGradlew ? "./gradlew" : "gradle";
|
|
1747
|
+
await withSpinner(
|
|
1748
|
+
"Installing Gradle dependencies...",
|
|
1749
|
+
async () => {
|
|
1750
|
+
await execa3(gradleCmd, ["build", "-x", "test"], {
|
|
1751
|
+
cwd: this.outputDir
|
|
1752
|
+
});
|
|
1753
|
+
},
|
|
1754
|
+
"Dependencies installed",
|
|
1755
|
+
"Failed to install dependencies"
|
|
1756
|
+
);
|
|
1757
|
+
}
|
|
1758
|
+
}
|
|
1759
|
+
async installDotnetDependencies() {
|
|
1760
|
+
const hasDotnet = await this.checkCommand("dotnet");
|
|
1761
|
+
if (!hasDotnet) {
|
|
1762
|
+
logger.warning(".NET SDK not found. Please install dependencies manually:");
|
|
1763
|
+
logger.code("dotnet restore");
|
|
1764
|
+
return;
|
|
1765
|
+
}
|
|
1766
|
+
await withSpinner(
|
|
1767
|
+
"Restoring .NET dependencies...",
|
|
1768
|
+
async () => {
|
|
1769
|
+
await execa3("dotnet", ["restore"], {
|
|
1770
|
+
cwd: this.outputDir
|
|
1771
|
+
});
|
|
1772
|
+
await execa3("dotnet", ["build"], {
|
|
1773
|
+
cwd: this.outputDir
|
|
1774
|
+
});
|
|
1775
|
+
},
|
|
1776
|
+
"Dependencies installed",
|
|
1777
|
+
"Failed to install dependencies"
|
|
1778
|
+
);
|
|
1779
|
+
}
|
|
1780
|
+
async installElixirDependencies() {
|
|
1781
|
+
const hasMix = await this.checkCommand("mix");
|
|
1782
|
+
if (!hasMix) {
|
|
1783
|
+
logger.warning("Elixir/Mix not found. Please install dependencies manually:");
|
|
1784
|
+
logger.code("mix deps.get");
|
|
1785
|
+
return;
|
|
1786
|
+
}
|
|
1787
|
+
await withSpinner(
|
|
1788
|
+
"Installing Elixir dependencies...",
|
|
1789
|
+
async () => {
|
|
1790
|
+
await execa3("mix", ["deps.get"], {
|
|
1791
|
+
cwd: this.outputDir
|
|
1792
|
+
});
|
|
1793
|
+
await execa3("mix", ["compile"], {
|
|
1794
|
+
cwd: this.outputDir
|
|
1795
|
+
});
|
|
1796
|
+
},
|
|
1797
|
+
"Dependencies installed",
|
|
1798
|
+
"Failed to install dependencies"
|
|
1799
|
+
);
|
|
1800
|
+
}
|
|
1126
1801
|
async checkCommand(command) {
|
|
1127
1802
|
try {
|
|
1128
1803
|
const checkCmd = process.platform === "win32" ? "where" : "which";
|
|
1129
|
-
await
|
|
1804
|
+
await execa3(checkCmd, [command]);
|
|
1130
1805
|
return true;
|
|
1131
1806
|
} catch {
|
|
1132
1807
|
return false;
|
|
@@ -1162,8 +1837,16 @@ var BaseGenerator = class {
|
|
|
1162
1837
|
}
|
|
1163
1838
|
};
|
|
1164
1839
|
function createGeneratorContext(config, outputPath) {
|
|
1165
|
-
const outputDir = outputPath ||
|
|
1166
|
-
|
|
1840
|
+
const outputDir = outputPath || path6.resolve(process.cwd(), config.name);
|
|
1841
|
+
let templateDir;
|
|
1842
|
+
const pluginTemplateDir = pluginRegistry.getPluginTemplateDir(config.language);
|
|
1843
|
+
if (pluginTemplateDir) {
|
|
1844
|
+
templateDir = pluginTemplateDir;
|
|
1845
|
+
} else if ((config.language === "java" || config.language === "kotlin") && config.javaBuildTool) {
|
|
1846
|
+
templateDir = path6.join(getTemplateDir(), config.language, config.javaBuildTool);
|
|
1847
|
+
} else {
|
|
1848
|
+
templateDir = path6.join(getTemplateDir(), config.language);
|
|
1849
|
+
}
|
|
1167
1850
|
return {
|
|
1168
1851
|
config,
|
|
1169
1852
|
outputDir,
|
|
@@ -1201,7 +1884,7 @@ var WizardGenerator = class extends BaseGenerator {
|
|
|
1201
1884
|
await this.installDependencies();
|
|
1202
1885
|
await this.initializeGit();
|
|
1203
1886
|
logger.success(`Project ${this.config.name} created successfully!`);
|
|
1204
|
-
logger.nextSteps(this.config.name, this.config.language);
|
|
1887
|
+
logger.nextSteps(this.config.name, this.config.language, this.config.javaBuildTool);
|
|
1205
1888
|
}
|
|
1206
1889
|
};
|
|
1207
1890
|
async function generateFromWizard(config, outputPath) {
|
|
@@ -1212,7 +1895,7 @@ async function generateFromWizard(config, outputPath) {
|
|
|
1212
1895
|
|
|
1213
1896
|
// src/parsers/openapi.ts
|
|
1214
1897
|
import YAML from "yaml";
|
|
1215
|
-
import
|
|
1898
|
+
import inquirer10 from "inquirer";
|
|
1216
1899
|
async function parseOpenAPISpec(content) {
|
|
1217
1900
|
let spec;
|
|
1218
1901
|
try {
|
|
@@ -1224,18 +1907,18 @@ async function parseOpenAPISpec(content) {
|
|
|
1224
1907
|
throw new Error('Invalid OpenAPI specification. Missing "openapi" or "swagger" field.');
|
|
1225
1908
|
}
|
|
1226
1909
|
const endpoints = [];
|
|
1227
|
-
for (const [
|
|
1910
|
+
for (const [path11, pathItem] of Object.entries(spec.paths)) {
|
|
1228
1911
|
const methods = ["get", "post", "put", "delete", "patch", "options", "head"];
|
|
1229
1912
|
for (const method of methods) {
|
|
1230
1913
|
const operation = pathItem[method];
|
|
1231
1914
|
if (!operation) continue;
|
|
1232
|
-
const endpoint = parseOperation(
|
|
1915
|
+
const endpoint = parseOperation(path11, method, operation, spec);
|
|
1233
1916
|
endpoints.push(endpoint);
|
|
1234
1917
|
}
|
|
1235
1918
|
}
|
|
1236
1919
|
return endpoints;
|
|
1237
1920
|
}
|
|
1238
|
-
function parseOperation(
|
|
1921
|
+
function parseOperation(path11, method, operation, spec) {
|
|
1239
1922
|
const parameters = [];
|
|
1240
1923
|
if (operation.parameters) {
|
|
1241
1924
|
for (const param of operation.parameters) {
|
|
@@ -1259,7 +1942,7 @@ function parseOperation(path7, method, operation, spec) {
|
|
|
1259
1942
|
}
|
|
1260
1943
|
}
|
|
1261
1944
|
return {
|
|
1262
|
-
path:
|
|
1945
|
+
path: path11,
|
|
1263
1946
|
method: method.toUpperCase(),
|
|
1264
1947
|
operationId: operation.operationId || "",
|
|
1265
1948
|
summary: operation.summary || "",
|
|
@@ -1312,7 +1995,7 @@ async function selectEndpoints(endpoints) {
|
|
|
1312
1995
|
value: ep,
|
|
1313
1996
|
checked: true
|
|
1314
1997
|
}));
|
|
1315
|
-
const { selected } = await
|
|
1998
|
+
const { selected } = await inquirer10.prompt([
|
|
1316
1999
|
{
|
|
1317
2000
|
type: "checkbox",
|
|
1318
2001
|
name: "selected",
|
|
@@ -1359,9 +2042,7 @@ var OpenAPIGenerator = class extends BaseGenerator {
|
|
|
1359
2042
|
logger.title(`Creating ${this.config.name} from OpenAPI`);
|
|
1360
2043
|
const isSafe = await this.checkOutputDir();
|
|
1361
2044
|
if (!isSafe) {
|
|
1362
|
-
throw new Error(
|
|
1363
|
-
`Directory ${this.outputDir} already exists and is not empty.`
|
|
1364
|
-
);
|
|
2045
|
+
throw new Error(`Directory ${this.outputDir} already exists and is not empty.`);
|
|
1365
2046
|
}
|
|
1366
2047
|
await withSpinner(
|
|
1367
2048
|
"Creating project structure...",
|
|
@@ -1381,7 +2062,7 @@ var OpenAPIGenerator = class extends BaseGenerator {
|
|
|
1381
2062
|
await this.initializeGit();
|
|
1382
2063
|
logger.success(`Project ${this.config.name} created successfully!`);
|
|
1383
2064
|
logger.info(`Generated ${this.config.tools.length} tools from OpenAPI spec`);
|
|
1384
|
-
logger.nextSteps(this.config.name, this.config.language);
|
|
2065
|
+
logger.nextSteps(this.config.name, this.config.language, this.config.javaBuildTool);
|
|
1385
2066
|
}
|
|
1386
2067
|
setEndpoints(endpoints) {
|
|
1387
2068
|
this._endpoints = endpoints;
|
|
@@ -1415,7 +2096,8 @@ async function generateFromOpenAPI(specPath, baseConfig) {
|
|
|
1415
2096
|
resources: [],
|
|
1416
2097
|
includeExampleTool: false,
|
|
1417
2098
|
skipInstall: baseConfig.skipInstall || false,
|
|
1418
|
-
initGit: baseConfig.initGit !== false
|
|
2099
|
+
initGit: baseConfig.initGit !== false,
|
|
2100
|
+
javaBuildTool: baseConfig.javaBuildTool
|
|
1419
2101
|
};
|
|
1420
2102
|
const context = createGeneratorContext(config);
|
|
1421
2103
|
const generator = new OpenAPIGenerator(context);
|
|
@@ -1448,7 +2130,7 @@ function mapOpenAPIType(type) {
|
|
|
1448
2130
|
|
|
1449
2131
|
// src/generators/from-prompt.ts
|
|
1450
2132
|
import Anthropic from "@anthropic-ai/sdk";
|
|
1451
|
-
import
|
|
2133
|
+
import inquirer11 from "inquirer";
|
|
1452
2134
|
var SYSTEM_PROMPT = `You are an expert at designing MCP (Model Context Protocol) servers.
|
|
1453
2135
|
Given a description of an API or functionality, you generate a list of tools that would be useful for that API.
|
|
1454
2136
|
|
|
@@ -1480,9 +2162,7 @@ var PromptGenerator = class extends BaseGenerator {
|
|
|
1480
2162
|
logger.title(`Creating ${this.config.name}`);
|
|
1481
2163
|
const isSafe = await this.checkOutputDir();
|
|
1482
2164
|
if (!isSafe) {
|
|
1483
|
-
throw new Error(
|
|
1484
|
-
`Directory ${this.outputDir} already exists and is not empty.`
|
|
1485
|
-
);
|
|
2165
|
+
throw new Error(`Directory ${this.outputDir} already exists and is not empty.`);
|
|
1486
2166
|
}
|
|
1487
2167
|
await withSpinner(
|
|
1488
2168
|
"Creating project structure...",
|
|
@@ -1502,11 +2182,11 @@ var PromptGenerator = class extends BaseGenerator {
|
|
|
1502
2182
|
await this.initializeGit();
|
|
1503
2183
|
logger.success(`Project ${this.config.name} created successfully!`);
|
|
1504
2184
|
logger.info(`Generated ${this.config.tools.length} tools from your description`);
|
|
1505
|
-
logger.nextSteps(this.config.name, this.config.language);
|
|
2185
|
+
logger.nextSteps(this.config.name, this.config.language, this.config.javaBuildTool);
|
|
1506
2186
|
}
|
|
1507
2187
|
};
|
|
1508
2188
|
async function generateFromPrompt(baseConfig) {
|
|
1509
|
-
const { description } = await
|
|
2189
|
+
const { description } = await inquirer11.prompt([
|
|
1510
2190
|
{
|
|
1511
2191
|
type: "editor",
|
|
1512
2192
|
name: "description",
|
|
@@ -1562,7 +2242,7 @@ async function generateFromPrompt(baseConfig) {
|
|
|
1562
2242
|
logger.list([`${index + 1}. ${tool.name} - ${tool.description}`]);
|
|
1563
2243
|
});
|
|
1564
2244
|
logger.blank();
|
|
1565
|
-
const { confirm } = await
|
|
2245
|
+
const { confirm } = await inquirer11.prompt([
|
|
1566
2246
|
{
|
|
1567
2247
|
type: "confirm",
|
|
1568
2248
|
name: "confirm",
|
|
@@ -1582,7 +2262,8 @@ async function generateFromPrompt(baseConfig) {
|
|
|
1582
2262
|
resources: [],
|
|
1583
2263
|
includeExampleTool: false,
|
|
1584
2264
|
skipInstall: baseConfig.skipInstall || false,
|
|
1585
|
-
initGit: baseConfig.initGit !== false
|
|
2265
|
+
initGit: baseConfig.initGit !== false,
|
|
2266
|
+
javaBuildTool: baseConfig.javaBuildTool
|
|
1586
2267
|
};
|
|
1587
2268
|
const context = createGeneratorContext(config);
|
|
1588
2269
|
const generator = new PromptGenerator(context);
|
|
@@ -1623,17 +2304,32 @@ var PresetGenerator = class extends BaseGenerator {
|
|
|
1623
2304
|
logger.success(`Project ${this.config.name} created successfully!`);
|
|
1624
2305
|
logger.info(`Preset: ${this.presetName}`);
|
|
1625
2306
|
logger.info(`Tools included: ${this.config.tools.map((t) => t.name).join(", ")}`);
|
|
1626
|
-
logger.nextSteps(this.config.name, this.config.language);
|
|
2307
|
+
logger.nextSteps(this.config.name, this.config.language, this.config.javaBuildTool);
|
|
1627
2308
|
}
|
|
1628
2309
|
};
|
|
1629
2310
|
async function generateFromPreset(options) {
|
|
1630
|
-
|
|
1631
|
-
if (
|
|
1632
|
-
|
|
2311
|
+
let preset;
|
|
2312
|
+
if (isExternalPreset(options.presetId)) {
|
|
2313
|
+
logger.info(`Fetching external preset: ${options.presetId}...`);
|
|
2314
|
+
preset = await withSpinner(
|
|
2315
|
+
"Resolving external preset...",
|
|
2316
|
+
async () => await getPresetByIdentifier(options.presetId),
|
|
2317
|
+
"Preset resolved",
|
|
2318
|
+
"Failed to resolve preset"
|
|
2319
|
+
);
|
|
2320
|
+
} else {
|
|
2321
|
+
preset = getPreset(options.presetId);
|
|
2322
|
+
if (!preset) {
|
|
2323
|
+
throw new Error(`Invalid preset: ${options.presetId}`);
|
|
2324
|
+
}
|
|
1633
2325
|
}
|
|
1634
2326
|
const name = options.projectName || await promptProjectName();
|
|
1635
2327
|
const description = options.useDefaults ? "" : await promptProjectDescription();
|
|
1636
2328
|
const language = options.language || (options.useDefaults ? "typescript" : await promptLanguage());
|
|
2329
|
+
let javaBuildTool;
|
|
2330
|
+
if (language === "java" || language === "kotlin") {
|
|
2331
|
+
javaBuildTool = options.javaBuildTool || (options.useDefaults ? "maven" : await promptJavaBuildTool());
|
|
2332
|
+
}
|
|
1637
2333
|
const transport = options.useDefaults ? "stdio" : await promptTransport();
|
|
1638
2334
|
const config = {
|
|
1639
2335
|
name,
|
|
@@ -1644,24 +2340,221 @@ async function generateFromPreset(options) {
|
|
|
1644
2340
|
resources: [],
|
|
1645
2341
|
includeExampleTool: false,
|
|
1646
2342
|
skipInstall: options.skipInstall || false,
|
|
1647
|
-
initGit: true
|
|
2343
|
+
initGit: true,
|
|
2344
|
+
javaBuildTool
|
|
1648
2345
|
};
|
|
1649
2346
|
const context = createGeneratorContext(config);
|
|
1650
2347
|
const generator = new PresetGenerator(context, preset.name);
|
|
1651
2348
|
await generator.generate();
|
|
2349
|
+
return config;
|
|
1652
2350
|
}
|
|
1653
2351
|
function validatePresetId(presetId) {
|
|
1654
2352
|
if (!isValidPresetId(presetId)) {
|
|
1655
2353
|
const validPresets = ["database", "rest-api", "filesystem"];
|
|
1656
|
-
throw new Error(
|
|
1657
|
-
`Invalid preset "${presetId}". Valid presets are: ${validPresets.join(", ")}`
|
|
1658
|
-
);
|
|
2354
|
+
throw new Error(`Invalid preset "${presetId}". Valid presets are: ${validPresets.join(", ")}`);
|
|
1659
2355
|
}
|
|
1660
2356
|
return true;
|
|
1661
2357
|
}
|
|
1662
2358
|
|
|
1663
2359
|
// src/commands/create.ts
|
|
1664
|
-
import
|
|
2360
|
+
import path8 from "path";
|
|
2361
|
+
|
|
2362
|
+
// src/types/ci.ts
|
|
2363
|
+
import { z as z4 } from "zod";
|
|
2364
|
+
var CIProviderSchema = z4.enum(["github", "gitlab", "circleci"]);
|
|
2365
|
+
var CI_PROVIDERS = ["github", "gitlab", "circleci"];
|
|
2366
|
+
function isValidCIProvider(provider) {
|
|
2367
|
+
return CI_PROVIDERS.includes(provider);
|
|
2368
|
+
}
|
|
2369
|
+
|
|
2370
|
+
// src/generators/ci.ts
|
|
2371
|
+
import path7 from "path";
|
|
2372
|
+
|
|
2373
|
+
// src/ci/language-config.ts
|
|
2374
|
+
var LANGUAGE_CI_CONFIG = {
|
|
2375
|
+
typescript: {
|
|
2376
|
+
installCommand: "npm ci",
|
|
2377
|
+
buildCommand: "npm run build",
|
|
2378
|
+
testCommand: "npm test",
|
|
2379
|
+
nodeVersion: "20"
|
|
2380
|
+
},
|
|
2381
|
+
python: {
|
|
2382
|
+
installCommand: "pip install -r requirements.txt",
|
|
2383
|
+
testCommand: "pytest",
|
|
2384
|
+
pythonVersion: "3.11"
|
|
2385
|
+
},
|
|
2386
|
+
go: {
|
|
2387
|
+
installCommand: "go mod download",
|
|
2388
|
+
buildCommand: "go build ./...",
|
|
2389
|
+
testCommand: "go test ./...",
|
|
2390
|
+
goVersion: "1.21"
|
|
2391
|
+
},
|
|
2392
|
+
rust: {
|
|
2393
|
+
installCommand: "cargo fetch",
|
|
2394
|
+
buildCommand: "cargo build --release",
|
|
2395
|
+
testCommand: "cargo test",
|
|
2396
|
+
rustVersion: "stable"
|
|
2397
|
+
},
|
|
2398
|
+
java: {
|
|
2399
|
+
installCommand: "mvn install -DskipTests",
|
|
2400
|
+
buildCommand: "mvn package -DskipTests",
|
|
2401
|
+
testCommand: "mvn test",
|
|
2402
|
+
javaVersion: "21"
|
|
2403
|
+
},
|
|
2404
|
+
kotlin: {
|
|
2405
|
+
installCommand: "mvn install -DskipTests",
|
|
2406
|
+
buildCommand: "mvn package -DskipTests",
|
|
2407
|
+
testCommand: "mvn test",
|
|
2408
|
+
javaVersion: "21"
|
|
2409
|
+
},
|
|
2410
|
+
csharp: {
|
|
2411
|
+
installCommand: "dotnet restore",
|
|
2412
|
+
buildCommand: "dotnet build --configuration Release",
|
|
2413
|
+
testCommand: "dotnet test",
|
|
2414
|
+
dotnetVersion: "8.0"
|
|
2415
|
+
},
|
|
2416
|
+
elixir: {
|
|
2417
|
+
installCommand: "mix deps.get",
|
|
2418
|
+
buildCommand: "mix compile",
|
|
2419
|
+
testCommand: "mix test",
|
|
2420
|
+
elixirVersion: "1.15"
|
|
2421
|
+
}
|
|
2422
|
+
};
|
|
2423
|
+
function getJavaCIConfig(buildTool) {
|
|
2424
|
+
if (buildTool === "gradle") {
|
|
2425
|
+
return {
|
|
2426
|
+
installCommand: "./gradlew dependencies",
|
|
2427
|
+
buildCommand: "./gradlew build -x test",
|
|
2428
|
+
testCommand: "./gradlew test",
|
|
2429
|
+
javaVersion: "21"
|
|
2430
|
+
};
|
|
2431
|
+
}
|
|
2432
|
+
return LANGUAGE_CI_CONFIG.java;
|
|
2433
|
+
}
|
|
2434
|
+
function getCITemplateContext(projectName, language, javaBuildTool) {
|
|
2435
|
+
const config = (language === "java" || language === "kotlin") && javaBuildTool === "gradle" ? getJavaCIConfig("gradle") : LANGUAGE_CI_CONFIG[language];
|
|
2436
|
+
return {
|
|
2437
|
+
projectName,
|
|
2438
|
+
language,
|
|
2439
|
+
...config
|
|
2440
|
+
};
|
|
2441
|
+
}
|
|
2442
|
+
|
|
2443
|
+
// src/generators/ci.ts
|
|
2444
|
+
var CIGenerator = class {
|
|
2445
|
+
options;
|
|
2446
|
+
templateDir;
|
|
2447
|
+
context;
|
|
2448
|
+
constructor(options) {
|
|
2449
|
+
this.options = options;
|
|
2450
|
+
this.templateDir = path7.join(getTemplateDir(), "ci", options.provider);
|
|
2451
|
+
this.context = getCITemplateContext(
|
|
2452
|
+
options.projectName || path7.basename(options.projectDir),
|
|
2453
|
+
options.language,
|
|
2454
|
+
options.javaBuildTool
|
|
2455
|
+
);
|
|
2456
|
+
}
|
|
2457
|
+
async generate() {
|
|
2458
|
+
await withSpinner(
|
|
2459
|
+
`Generating ${this.getProviderName()} CI configuration...`,
|
|
2460
|
+
async () => {
|
|
2461
|
+
switch (this.options.provider) {
|
|
2462
|
+
case "github":
|
|
2463
|
+
await this.generateGitHubActions();
|
|
2464
|
+
break;
|
|
2465
|
+
case "gitlab":
|
|
2466
|
+
await this.generateGitLabCI();
|
|
2467
|
+
break;
|
|
2468
|
+
case "circleci":
|
|
2469
|
+
await this.generateCircleCI();
|
|
2470
|
+
break;
|
|
2471
|
+
}
|
|
2472
|
+
},
|
|
2473
|
+
`${this.getProviderName()} CI configuration generated`,
|
|
2474
|
+
`Failed to generate ${this.getProviderName()} CI configuration`
|
|
2475
|
+
);
|
|
2476
|
+
}
|
|
2477
|
+
async generateGitHubActions() {
|
|
2478
|
+
const workflowDir = path7.join(this.options.projectDir, ".github", "workflows");
|
|
2479
|
+
await ensureDir(workflowDir);
|
|
2480
|
+
const templatePath = path7.join(this.templateDir, "ci.yml.ejs");
|
|
2481
|
+
const outputPath = path7.join(workflowDir, "ci.yml");
|
|
2482
|
+
await renderTemplateToFile(templatePath, outputPath, this.context);
|
|
2483
|
+
}
|
|
2484
|
+
async generateGitLabCI() {
|
|
2485
|
+
const templatePath = path7.join(this.templateDir, ".gitlab-ci.yml.ejs");
|
|
2486
|
+
const outputPath = path7.join(this.options.projectDir, ".gitlab-ci.yml");
|
|
2487
|
+
await renderTemplateToFile(templatePath, outputPath, this.context);
|
|
2488
|
+
}
|
|
2489
|
+
async generateCircleCI() {
|
|
2490
|
+
const circleDir = path7.join(this.options.projectDir, ".circleci");
|
|
2491
|
+
await ensureDir(circleDir);
|
|
2492
|
+
const templatePath = path7.join(this.templateDir, "config.yml.ejs");
|
|
2493
|
+
const outputPath = path7.join(circleDir, "config.yml");
|
|
2494
|
+
await renderTemplateToFile(templatePath, outputPath, this.context);
|
|
2495
|
+
}
|
|
2496
|
+
getProviderName() {
|
|
2497
|
+
switch (this.options.provider) {
|
|
2498
|
+
case "github":
|
|
2499
|
+
return "GitHub Actions";
|
|
2500
|
+
case "gitlab":
|
|
2501
|
+
return "GitLab CI";
|
|
2502
|
+
case "circleci":
|
|
2503
|
+
return "CircleCI";
|
|
2504
|
+
}
|
|
2505
|
+
}
|
|
2506
|
+
};
|
|
2507
|
+
async function generateCI(options) {
|
|
2508
|
+
const generator = new CIGenerator(options);
|
|
2509
|
+
await generator.generate();
|
|
2510
|
+
}
|
|
2511
|
+
async function detectLanguageFromProject(projectDir) {
|
|
2512
|
+
const checks = [
|
|
2513
|
+
{ file: "package.json", language: "typescript" },
|
|
2514
|
+
{ file: "pyproject.toml", language: "python" },
|
|
2515
|
+
{ file: "requirements.txt", language: "python" },
|
|
2516
|
+
{ file: "go.mod", language: "go" },
|
|
2517
|
+
{ file: "Cargo.toml", language: "rust" },
|
|
2518
|
+
{ file: "pom.xml", language: "java" },
|
|
2519
|
+
{ file: "build.gradle", language: "java" },
|
|
2520
|
+
{ file: "build.gradle.kts", language: "kotlin" },
|
|
2521
|
+
{ file: "*.csproj", language: "csharp" },
|
|
2522
|
+
{ file: "mix.exs", language: "elixir" }
|
|
2523
|
+
];
|
|
2524
|
+
for (const check of checks) {
|
|
2525
|
+
if (await exists(path7.join(projectDir, check.file))) {
|
|
2526
|
+
return check.language;
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2529
|
+
return void 0;
|
|
2530
|
+
}
|
|
2531
|
+
async function detectJavaBuildTool(projectDir) {
|
|
2532
|
+
if (await exists(path7.join(projectDir, "build.gradle")) || await exists(path7.join(projectDir, "build.gradle.kts"))) {
|
|
2533
|
+
return "gradle";
|
|
2534
|
+
}
|
|
2535
|
+
if (await exists(path7.join(projectDir, "pom.xml"))) {
|
|
2536
|
+
return "maven";
|
|
2537
|
+
}
|
|
2538
|
+
return void 0;
|
|
2539
|
+
}
|
|
2540
|
+
|
|
2541
|
+
// src/commands/create.ts
|
|
2542
|
+
function getLanguageFromOptions(options) {
|
|
2543
|
+
if (options.typescript) return "typescript";
|
|
2544
|
+
if (options.python) return "python";
|
|
2545
|
+
if (options.go) return "go";
|
|
2546
|
+
if (options.rust) return "rust";
|
|
2547
|
+
if (options.java) return "java";
|
|
2548
|
+
if (options.kotlin) return "kotlin";
|
|
2549
|
+
if (options.csharp) return "csharp";
|
|
2550
|
+
if (options.elixir) return "elixir";
|
|
2551
|
+
return void 0;
|
|
2552
|
+
}
|
|
2553
|
+
function getJavaBuildToolFromOptions(options) {
|
|
2554
|
+
if (options.maven) return "maven";
|
|
2555
|
+
if (options.gradle) return "gradle";
|
|
2556
|
+
return void 0;
|
|
2557
|
+
}
|
|
1665
2558
|
async function createCommand(projectName, options) {
|
|
1666
2559
|
try {
|
|
1667
2560
|
if (options.preset) {
|
|
@@ -1688,16 +2581,17 @@ async function createCommand(projectName, options) {
|
|
|
1688
2581
|
}
|
|
1689
2582
|
async function handleWizardGeneration(projectName, options) {
|
|
1690
2583
|
let config;
|
|
1691
|
-
const presetLanguage = options
|
|
2584
|
+
const presetLanguage = getLanguageFromOptions(options);
|
|
2585
|
+
const presetJavaBuildTool = getJavaBuildToolFromOptions(options);
|
|
1692
2586
|
if (options.yes) {
|
|
1693
|
-
config = await runQuickWizard(projectName, presetLanguage);
|
|
2587
|
+
config = await runQuickWizard(projectName, presetLanguage, presetJavaBuildTool);
|
|
1694
2588
|
} else {
|
|
1695
|
-
config = await runWizard({ defaultName: projectName, presetLanguage });
|
|
2589
|
+
config = await runWizard({ defaultName: projectName, presetLanguage, presetJavaBuildTool });
|
|
1696
2590
|
}
|
|
1697
2591
|
if (options.skipInstall) {
|
|
1698
2592
|
config.skipInstall = true;
|
|
1699
2593
|
}
|
|
1700
|
-
const outputPath =
|
|
2594
|
+
const outputPath = path8.resolve(process.cwd(), config.name);
|
|
1701
2595
|
if (await exists(outputPath)) {
|
|
1702
2596
|
const files = await import("fs-extra").then((m) => m.readdir(outputPath));
|
|
1703
2597
|
if (files.length > 0) {
|
|
@@ -1706,6 +2600,9 @@ async function handleWizardGeneration(projectName, options) {
|
|
|
1706
2600
|
}
|
|
1707
2601
|
}
|
|
1708
2602
|
await generateFromWizard(config);
|
|
2603
|
+
if (options.ci) {
|
|
2604
|
+
await handleCIGeneration(config.name, config.language, config.javaBuildTool, options.ci);
|
|
2605
|
+
}
|
|
1709
2606
|
}
|
|
1710
2607
|
async function handleOpenAPIGeneration(projectName, options) {
|
|
1711
2608
|
const specPath = options.fromOpenapi;
|
|
@@ -1713,45 +2610,71 @@ async function handleOpenAPIGeneration(projectName, options) {
|
|
|
1713
2610
|
logger.error(`OpenAPI specification file not found: ${specPath}`);
|
|
1714
2611
|
process.exit(1);
|
|
1715
2612
|
}
|
|
1716
|
-
const name = projectName ||
|
|
2613
|
+
const name = projectName || path8.basename(specPath, path8.extname(specPath)) + "-mcp";
|
|
1717
2614
|
await generateFromOpenAPI(specPath, {
|
|
1718
2615
|
name,
|
|
1719
|
-
language: options
|
|
1720
|
-
skipInstall: options.skipInstall
|
|
2616
|
+
language: getLanguageFromOptions(options),
|
|
2617
|
+
skipInstall: options.skipInstall,
|
|
2618
|
+
javaBuildTool: getJavaBuildToolFromOptions(options)
|
|
1721
2619
|
});
|
|
1722
2620
|
}
|
|
1723
2621
|
async function handlePromptGeneration(projectName, options) {
|
|
1724
2622
|
await generateFromPrompt({
|
|
1725
2623
|
name: projectName,
|
|
1726
|
-
language: options
|
|
1727
|
-
skipInstall: options.skipInstall
|
|
2624
|
+
language: getLanguageFromOptions(options),
|
|
2625
|
+
skipInstall: options.skipInstall,
|
|
2626
|
+
javaBuildTool: getJavaBuildToolFromOptions(options)
|
|
1728
2627
|
});
|
|
1729
2628
|
}
|
|
1730
2629
|
async function handlePresetGeneration(projectName, options) {
|
|
1731
2630
|
const presetId = options.preset;
|
|
1732
|
-
|
|
1733
|
-
|
|
2631
|
+
if (!isExternalPreset(presetId) && !isValidPresetId(presetId)) {
|
|
2632
|
+
logger.error(
|
|
2633
|
+
`Invalid preset "${presetId}". Valid local presets: ${PRESET_IDS.join(", ")}
|
|
2634
|
+
For external presets use: @org/package or github:user/repo`
|
|
2635
|
+
);
|
|
2636
|
+
process.exit(1);
|
|
2637
|
+
}
|
|
2638
|
+
const result = await generateFromPreset({
|
|
1734
2639
|
projectName,
|
|
1735
2640
|
presetId,
|
|
1736
|
-
language: options
|
|
2641
|
+
language: getLanguageFromOptions(options),
|
|
1737
2642
|
skipInstall: options.skipInstall,
|
|
1738
|
-
useDefaults: options.yes
|
|
2643
|
+
useDefaults: options.yes,
|
|
2644
|
+
javaBuildTool: getJavaBuildToolFromOptions(options)
|
|
2645
|
+
});
|
|
2646
|
+
if (options.ci && result) {
|
|
2647
|
+
await handleCIGeneration(result.name, result.language, result.javaBuildTool, options.ci);
|
|
2648
|
+
}
|
|
2649
|
+
}
|
|
2650
|
+
async function handleCIGeneration(projectName, language, javaBuildTool, ciProvider) {
|
|
2651
|
+
if (!isValidCIProvider(ciProvider)) {
|
|
2652
|
+
logger.error(`Invalid CI provider: ${ciProvider}. Valid options: github, gitlab, circleci`);
|
|
2653
|
+
return;
|
|
2654
|
+
}
|
|
2655
|
+
const projectDir = path8.resolve(process.cwd(), projectName);
|
|
2656
|
+
await generateCI({
|
|
2657
|
+
projectDir,
|
|
2658
|
+
provider: ciProvider,
|
|
2659
|
+
language,
|
|
2660
|
+
javaBuildTool,
|
|
2661
|
+
projectName
|
|
1739
2662
|
});
|
|
1740
2663
|
}
|
|
1741
2664
|
|
|
1742
2665
|
// src/commands/init.ts
|
|
1743
|
-
import
|
|
1744
|
-
import
|
|
2666
|
+
import path9 from "path";
|
|
2667
|
+
import inquirer12 from "inquirer";
|
|
1745
2668
|
async function initCommand(options) {
|
|
1746
2669
|
try {
|
|
1747
2670
|
const currentDir = process.cwd();
|
|
1748
|
-
const dirName =
|
|
1749
|
-
const hasPackageJson = await exists(
|
|
1750
|
-
const hasPyproject = await exists(
|
|
1751
|
-
const hasGoMod = await exists(
|
|
1752
|
-
const hasCargoToml = await exists(
|
|
2671
|
+
const dirName = path9.basename(currentDir);
|
|
2672
|
+
const hasPackageJson = await exists(path9.join(currentDir, "package.json"));
|
|
2673
|
+
const hasPyproject = await exists(path9.join(currentDir, "pyproject.toml"));
|
|
2674
|
+
const hasGoMod = await exists(path9.join(currentDir, "go.mod"));
|
|
2675
|
+
const hasCargoToml = await exists(path9.join(currentDir, "Cargo.toml"));
|
|
1753
2676
|
if ((hasPackageJson || hasPyproject || hasGoMod || hasCargoToml) && !options.force) {
|
|
1754
|
-
const { proceed } = await
|
|
2677
|
+
const { proceed } = await inquirer12.prompt([
|
|
1755
2678
|
{
|
|
1756
2679
|
type: "confirm",
|
|
1757
2680
|
name: "proceed",
|
|
@@ -1793,7 +2716,7 @@ async function initCommand(options) {
|
|
|
1793
2716
|
let projectName = dirName;
|
|
1794
2717
|
if (hasPackageJson) {
|
|
1795
2718
|
try {
|
|
1796
|
-
const pkgContent = await readFile(
|
|
2719
|
+
const pkgContent = await readFile(path9.join(currentDir, "package.json"));
|
|
1797
2720
|
const pkg = JSON.parse(pkgContent);
|
|
1798
2721
|
projectName = pkg.name || dirName;
|
|
1799
2722
|
} catch {
|
|
@@ -1823,14 +2746,14 @@ async function initCommand(options) {
|
|
|
1823
2746
|
}
|
|
1824
2747
|
|
|
1825
2748
|
// src/commands/add-tool.ts
|
|
1826
|
-
import
|
|
2749
|
+
import path10 from "path";
|
|
1827
2750
|
async function addToolCommand(options) {
|
|
1828
2751
|
try {
|
|
1829
2752
|
const currentDir = process.cwd();
|
|
1830
|
-
const isTypeScript = await exists(
|
|
1831
|
-
const isPython = await exists(
|
|
1832
|
-
const isGo = await exists(
|
|
1833
|
-
const isRust = await exists(
|
|
2753
|
+
const isTypeScript = await exists(path10.join(currentDir, "package.json"));
|
|
2754
|
+
const isPython = await exists(path10.join(currentDir, "pyproject.toml"));
|
|
2755
|
+
const isGo = await exists(path10.join(currentDir, "go.mod"));
|
|
2756
|
+
const isRust = await exists(path10.join(currentDir, "Cargo.toml"));
|
|
1834
2757
|
if (!isTypeScript && !isPython && !isGo && !isRust) {
|
|
1835
2758
|
logger.error("No MCP server project found in current directory.");
|
|
1836
2759
|
logger.info("Run this command from the root of your MCP server project.");
|
|
@@ -1868,9 +2791,9 @@ async function addToolCommand(options) {
|
|
|
1868
2791
|
}
|
|
1869
2792
|
}
|
|
1870
2793
|
async function addToolToTypeScript(projectDir, tool) {
|
|
1871
|
-
const toolsDir =
|
|
2794
|
+
const toolsDir = path10.join(projectDir, "src", "tools");
|
|
1872
2795
|
const toolFileName = `${tool.name.replace(/_/g, "-")}.ts`;
|
|
1873
|
-
const toolFilePath =
|
|
2796
|
+
const toolFilePath = path10.join(toolsDir, toolFileName);
|
|
1874
2797
|
if (await exists(toolFilePath)) {
|
|
1875
2798
|
logger.error(`Tool file already exists: ${toolFilePath}`);
|
|
1876
2799
|
process.exit(1);
|
|
@@ -1886,9 +2809,9 @@ async function addToolToTypeScript(projectDir, tool) {
|
|
|
1886
2809
|
]);
|
|
1887
2810
|
}
|
|
1888
2811
|
async function addToolToPython(projectDir, tool) {
|
|
1889
|
-
const toolsDir =
|
|
2812
|
+
const toolsDir = path10.join(projectDir, "src", "tools");
|
|
1890
2813
|
const toolFileName = `${tool.name}.py`;
|
|
1891
|
-
const toolFilePath =
|
|
2814
|
+
const toolFilePath = path10.join(toolsDir, toolFileName);
|
|
1892
2815
|
if (await exists(toolFilePath)) {
|
|
1893
2816
|
logger.error(`Tool file already exists: ${toolFilePath}`);
|
|
1894
2817
|
process.exit(1);
|
|
@@ -2032,9 +2955,9 @@ function mapTypeToPython(type) {
|
|
|
2032
2955
|
}
|
|
2033
2956
|
}
|
|
2034
2957
|
async function addToolToGo(projectDir, tool) {
|
|
2035
|
-
const toolsDir =
|
|
2958
|
+
const toolsDir = path10.join(projectDir, "internal", "tools");
|
|
2036
2959
|
const toolFileName = `${tool.name}.go`;
|
|
2037
|
-
const toolFilePath =
|
|
2960
|
+
const toolFilePath = path10.join(toolsDir, toolFileName);
|
|
2038
2961
|
if (await exists(toolFilePath)) {
|
|
2039
2962
|
logger.error(`Tool file already exists: ${toolFilePath}`);
|
|
2040
2963
|
process.exit(1);
|
|
@@ -2050,9 +2973,9 @@ async function addToolToGo(projectDir, tool) {
|
|
|
2050
2973
|
]);
|
|
2051
2974
|
}
|
|
2052
2975
|
async function addToolToRust(projectDir, tool) {
|
|
2053
|
-
const srcDir =
|
|
2976
|
+
const srcDir = path10.join(projectDir, "src");
|
|
2054
2977
|
const toolFileName = `${tool.name}.rs`;
|
|
2055
|
-
const toolFilePath =
|
|
2978
|
+
const toolFilePath = path10.join(srcDir, toolFileName);
|
|
2056
2979
|
if (await exists(toolFilePath)) {
|
|
2057
2980
|
logger.error(`Tool file already exists: ${toolFilePath}`);
|
|
2058
2981
|
process.exit(1);
|
|
@@ -2200,6 +3123,7 @@ function mapTypeToRust(type) {
|
|
|
2200
3123
|
}
|
|
2201
3124
|
|
|
2202
3125
|
export {
|
|
3126
|
+
isValidCIProvider,
|
|
2203
3127
|
projectNameRegex,
|
|
2204
3128
|
validateProjectName,
|
|
2205
3129
|
validateToolName,
|
|
@@ -2209,20 +3133,6 @@ export {
|
|
|
2209
3133
|
safeParseAndValidate,
|
|
2210
3134
|
promptProjectName,
|
|
2211
3135
|
promptProjectDescription,
|
|
2212
|
-
promptLanguage,
|
|
2213
|
-
promptTransport,
|
|
2214
|
-
promptIncludeExampleTool,
|
|
2215
|
-
promptAddTools,
|
|
2216
|
-
promptToolConfig,
|
|
2217
|
-
promptMultipleTools,
|
|
2218
|
-
promptAddResources,
|
|
2219
|
-
promptResourceConfig,
|
|
2220
|
-
promptMultipleResources,
|
|
2221
|
-
promptGenerationMethod,
|
|
2222
|
-
PRESETS,
|
|
2223
|
-
promptPreset,
|
|
2224
|
-
runWizard,
|
|
2225
|
-
runQuickWizard,
|
|
2226
3136
|
ensureDir,
|
|
2227
3137
|
writeFile,
|
|
2228
3138
|
readFile,
|
|
@@ -2236,7 +3146,39 @@ export {
|
|
|
2236
3146
|
renderTemplateToFile,
|
|
2237
3147
|
walkDir,
|
|
2238
3148
|
getTemplateDir,
|
|
3149
|
+
getTemplateDirForLanguage,
|
|
2239
3150
|
resolveOutputPath,
|
|
3151
|
+
pluginRegistry,
|
|
3152
|
+
promptLanguage,
|
|
3153
|
+
promptTransport,
|
|
3154
|
+
promptIncludeExampleTool,
|
|
3155
|
+
promptAddTools,
|
|
3156
|
+
promptToolConfig,
|
|
3157
|
+
promptMultipleTools,
|
|
3158
|
+
promptAddResources,
|
|
3159
|
+
promptResourceConfig,
|
|
3160
|
+
promptMultipleResources,
|
|
3161
|
+
promptJavaBuildTool,
|
|
3162
|
+
promptGenerationMethod,
|
|
3163
|
+
BuiltinLanguageSchema,
|
|
3164
|
+
LanguageSchema,
|
|
3165
|
+
BUILTIN_LANGUAGES,
|
|
3166
|
+
isBuiltinLanguage,
|
|
3167
|
+
JavaBuildToolSchema,
|
|
3168
|
+
TransportSchema,
|
|
3169
|
+
ToolParameterSchema,
|
|
3170
|
+
ToolConfigSchema,
|
|
3171
|
+
ResourceConfigSchema,
|
|
3172
|
+
ProjectConfigSchema,
|
|
3173
|
+
PresetIdSchema,
|
|
3174
|
+
clearPresetCache,
|
|
3175
|
+
listCachedPresets,
|
|
3176
|
+
getCacheDir,
|
|
3177
|
+
PRESETS,
|
|
3178
|
+
promptPreset,
|
|
3179
|
+
promptCIProvider,
|
|
3180
|
+
runWizard,
|
|
3181
|
+
runQuickWizard,
|
|
2240
3182
|
isGitInstalled,
|
|
2241
3183
|
initGitRepository,
|
|
2242
3184
|
createInitialCommit,
|
|
@@ -2259,6 +3201,9 @@ export {
|
|
|
2259
3201
|
PresetGenerator,
|
|
2260
3202
|
generateFromPreset,
|
|
2261
3203
|
validatePresetId,
|
|
3204
|
+
generateCI,
|
|
3205
|
+
detectLanguageFromProject,
|
|
3206
|
+
detectJavaBuildTool,
|
|
2262
3207
|
createCommand,
|
|
2263
3208
|
initCommand,
|
|
2264
3209
|
addToolCommand
|