@agiflowai/scaffold-mcp 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -11
- package/dist/ScaffoldConfigLoader-CnVkzUxL.js +3 -0
- package/dist/{ScaffoldConfigLoader-CI0T6zdG.js → ScaffoldConfigLoader-yDhzLQpC.js} +34 -25
- package/dist/{ScaffoldService-CnJ1nj1v.js → ScaffoldService-B8-dPa7L.js} +62 -52
- package/dist/ScaffoldService-BXKXXg4M.js +3 -0
- package/dist/TemplateService-B0ns4TR_.js +3 -0
- package/dist/{TemplateService-CnxvhRVW.js → TemplateService-DvKjDjQE.js} +10 -3
- package/dist/{VariableReplacementService-Bq0GDhTo.js → VariableReplacementService-DJqXiBC2.js} +11 -4
- package/dist/VariableReplacementService-_GgLG4Im.js +3 -0
- package/dist/chunk-nOFOJqeH.js +30 -0
- package/dist/index.js +371 -226
- package/package.json +2 -3
- package/dist/ScaffoldConfigLoader-DhthV6xq.js +0 -3
- package/dist/ScaffoldService-CDhYAUrp.js +0 -3
- package/dist/TemplateService-PmTU3_On.js +0 -3
- package/dist/VariableReplacementService-CrxFJrqU.js +0 -3
package/dist/index.js
CHANGED
|
@@ -1,28 +1,41 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
2
|
+
const require_chunk = require('./chunk-nOFOJqeH.js');
|
|
3
|
+
const require_ScaffoldConfigLoader = require('./ScaffoldConfigLoader-yDhzLQpC.js');
|
|
4
|
+
const require_ScaffoldService = require('./ScaffoldService-B8-dPa7L.js');
|
|
5
|
+
const require_TemplateService = require('./TemplateService-DvKjDjQE.js');
|
|
6
|
+
const require_VariableReplacementService = require('./VariableReplacementService-DJqXiBC2.js');
|
|
7
|
+
let commander = require("commander");
|
|
8
|
+
commander = require_chunk.__toESM(commander);
|
|
9
|
+
let node_path = require("node:path");
|
|
10
|
+
node_path = require_chunk.__toESM(node_path);
|
|
11
|
+
let fs_extra = require("fs-extra");
|
|
12
|
+
fs_extra = require_chunk.__toESM(fs_extra);
|
|
13
|
+
let chalk = require("chalk");
|
|
14
|
+
chalk = require_chunk.__toESM(chalk);
|
|
15
|
+
let node_child_process = require("node:child_process");
|
|
16
|
+
node_child_process = require_chunk.__toESM(node_child_process);
|
|
17
|
+
let node_util = require("node:util");
|
|
18
|
+
node_util = require_chunk.__toESM(node_util);
|
|
19
|
+
let __composio_json_schema_to_zod = require("@composio/json-schema-to-zod");
|
|
20
|
+
__composio_json_schema_to_zod = require_chunk.__toESM(__composio_json_schema_to_zod);
|
|
21
|
+
let js_yaml = require("js-yaml");
|
|
22
|
+
js_yaml = require_chunk.__toESM(js_yaml);
|
|
23
|
+
let zod = require("zod");
|
|
24
|
+
zod = require_chunk.__toESM(zod);
|
|
25
|
+
let __modelcontextprotocol_sdk_server_index_js = require("@modelcontextprotocol/sdk/server/index.js");
|
|
26
|
+
__modelcontextprotocol_sdk_server_index_js = require_chunk.__toESM(__modelcontextprotocol_sdk_server_index_js);
|
|
27
|
+
let __modelcontextprotocol_sdk_types_js = require("@modelcontextprotocol/sdk/types.js");
|
|
28
|
+
__modelcontextprotocol_sdk_types_js = require_chunk.__toESM(__modelcontextprotocol_sdk_types_js);
|
|
29
|
+
let node_crypto = require("node:crypto");
|
|
30
|
+
node_crypto = require_chunk.__toESM(node_crypto);
|
|
31
|
+
let __modelcontextprotocol_sdk_server_streamableHttp_js = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
32
|
+
__modelcontextprotocol_sdk_server_streamableHttp_js = require_chunk.__toESM(__modelcontextprotocol_sdk_server_streamableHttp_js);
|
|
33
|
+
let express = require("express");
|
|
34
|
+
express = require_chunk.__toESM(express);
|
|
35
|
+
let __modelcontextprotocol_sdk_server_sse_js = require("@modelcontextprotocol/sdk/server/sse.js");
|
|
36
|
+
__modelcontextprotocol_sdk_server_sse_js = require_chunk.__toESM(__modelcontextprotocol_sdk_server_sse_js);
|
|
37
|
+
let __modelcontextprotocol_sdk_server_stdio_js = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
38
|
+
__modelcontextprotocol_sdk_server_stdio_js = require_chunk.__toESM(__modelcontextprotocol_sdk_server_stdio_js);
|
|
26
39
|
|
|
27
40
|
//#region src/utils/console.ts
|
|
28
41
|
/**
|
|
@@ -30,34 +43,34 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
30
43
|
*/
|
|
31
44
|
const logger = {
|
|
32
45
|
info: (message) => {
|
|
33
|
-
console.log(chalk.cyan(message));
|
|
46
|
+
console.log(chalk.default.cyan(message));
|
|
34
47
|
},
|
|
35
48
|
success: (message) => {
|
|
36
|
-
console.log(chalk.green(message));
|
|
49
|
+
console.log(chalk.default.green(message));
|
|
37
50
|
},
|
|
38
51
|
warning: (message) => {
|
|
39
|
-
console.log(chalk.yellow(message));
|
|
52
|
+
console.log(chalk.default.yellow(message));
|
|
40
53
|
},
|
|
41
54
|
error: (message, error) => {
|
|
42
55
|
if (error) {
|
|
43
56
|
const errorMsg = error instanceof Error ? error.message : error;
|
|
44
|
-
console.error(chalk.red(message), errorMsg);
|
|
45
|
-
} else console.error(chalk.red(message));
|
|
57
|
+
console.error(chalk.default.red(message), errorMsg);
|
|
58
|
+
} else console.error(chalk.default.red(message));
|
|
46
59
|
},
|
|
47
60
|
debug: (message) => {
|
|
48
|
-
console.log(chalk.gray(message));
|
|
61
|
+
console.log(chalk.default.gray(message));
|
|
49
62
|
},
|
|
50
63
|
header: (message) => {
|
|
51
|
-
console.log(chalk.bold.cyan(message));
|
|
64
|
+
console.log(chalk.default.bold.cyan(message));
|
|
52
65
|
},
|
|
53
66
|
item: (message) => {
|
|
54
|
-
console.log(chalk.gray(` - ${message}`));
|
|
67
|
+
console.log(chalk.default.gray(` - ${message}`));
|
|
55
68
|
},
|
|
56
69
|
indent: (message) => {
|
|
57
|
-
console.log(chalk.gray(` ${message}`));
|
|
70
|
+
console.log(chalk.default.gray(` ${message}`));
|
|
58
71
|
},
|
|
59
72
|
highlight: (message) => {
|
|
60
|
-
console.log(chalk.bold.green(message));
|
|
73
|
+
console.log(chalk.default.bold.green(message));
|
|
61
74
|
},
|
|
62
75
|
newline: () => {
|
|
63
76
|
console.log();
|
|
@@ -82,7 +95,8 @@ const icons = {
|
|
|
82
95
|
download: "=�",
|
|
83
96
|
upload: "=�",
|
|
84
97
|
gear: "�",
|
|
85
|
-
clipboard: "=�"
|
|
98
|
+
clipboard: "=�",
|
|
99
|
+
skip: "⏭"
|
|
86
100
|
};
|
|
87
101
|
/**
|
|
88
102
|
* Themed message helpers
|
|
@@ -135,15 +149,98 @@ const sections = {
|
|
|
135
149
|
}
|
|
136
150
|
};
|
|
137
151
|
|
|
152
|
+
//#endregion
|
|
153
|
+
//#region src/utils/git.ts
|
|
154
|
+
const execAsync = (0, node_util.promisify)(node_child_process.exec);
|
|
155
|
+
/**
|
|
156
|
+
* Parse GitHub URL to detect if it's a subdirectory
|
|
157
|
+
* Supports formats:
|
|
158
|
+
* - https://github.com/user/repo
|
|
159
|
+
* - https://github.com/user/repo/tree/branch/path/to/dir
|
|
160
|
+
* - https://github.com/user/repo/tree/main/path/to/dir
|
|
161
|
+
*/
|
|
162
|
+
function parseGitHubUrl(url) {
|
|
163
|
+
const treeMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)\/(.+)$/);
|
|
164
|
+
const blobMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/blob\/([^/]+)\/(.+)$/);
|
|
165
|
+
const rootMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/);
|
|
166
|
+
if (treeMatch || blobMatch) {
|
|
167
|
+
const match = treeMatch || blobMatch;
|
|
168
|
+
return {
|
|
169
|
+
owner: match[1],
|
|
170
|
+
repo: match[2],
|
|
171
|
+
repoUrl: `https://github.com/${match[1]}/${match[2]}.git`,
|
|
172
|
+
branch: match[3],
|
|
173
|
+
subdirectory: match[4],
|
|
174
|
+
isSubdirectory: true
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
if (rootMatch) return {
|
|
178
|
+
owner: rootMatch[1],
|
|
179
|
+
repo: rootMatch[2],
|
|
180
|
+
repoUrl: `https://github.com/${rootMatch[1]}/${rootMatch[2]}.git`,
|
|
181
|
+
isSubdirectory: false
|
|
182
|
+
};
|
|
183
|
+
return {
|
|
184
|
+
repoUrl: url,
|
|
185
|
+
isSubdirectory: false
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Clone a subdirectory from a git repository using sparse checkout
|
|
190
|
+
*/
|
|
191
|
+
async function cloneSubdirectory(repoUrl, branch, subdirectory, targetFolder) {
|
|
192
|
+
const tempFolder = `${targetFolder}.tmp`;
|
|
193
|
+
try {
|
|
194
|
+
await execAsync(`git init "${tempFolder}"`);
|
|
195
|
+
await execAsync(`git -C "${tempFolder}" remote add origin ${repoUrl}`);
|
|
196
|
+
await execAsync(`git -C "${tempFolder}" config core.sparseCheckout true`);
|
|
197
|
+
const sparseCheckoutFile = node_path.default.join(tempFolder, ".git", "info", "sparse-checkout");
|
|
198
|
+
await fs_extra.writeFile(sparseCheckoutFile, `${subdirectory}\n`);
|
|
199
|
+
await execAsync(`git -C "${tempFolder}" pull --depth=1 origin ${branch}`);
|
|
200
|
+
const sourceDir = node_path.default.join(tempFolder, subdirectory);
|
|
201
|
+
if (!await fs_extra.pathExists(sourceDir)) throw new Error(`Subdirectory '${subdirectory}' not found in repository at branch '${branch}'`);
|
|
202
|
+
await fs_extra.move(sourceDir, targetFolder);
|
|
203
|
+
await fs_extra.remove(tempFolder);
|
|
204
|
+
} catch (error) {
|
|
205
|
+
if (await fs_extra.pathExists(tempFolder)) await fs_extra.remove(tempFolder);
|
|
206
|
+
throw error;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Clone entire repository
|
|
211
|
+
*/
|
|
212
|
+
async function cloneRepository(repoUrl, targetFolder) {
|
|
213
|
+
await execAsync(`git clone ${repoUrl} "${targetFolder}"`);
|
|
214
|
+
const gitFolder = node_path.default.join(targetFolder, ".git");
|
|
215
|
+
if (await fs_extra.pathExists(gitFolder)) await fs_extra.remove(gitFolder);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Fetch directory listing from GitHub API
|
|
219
|
+
*/
|
|
220
|
+
async function fetchGitHubDirectoryContents(owner, repo, path$6, branch = "main") {
|
|
221
|
+
const url = `https://api.github.com/repos/${owner}/${repo}/contents/${path$6}?ref=${branch}`;
|
|
222
|
+
const response = await fetch(url, { headers: {
|
|
223
|
+
Accept: "application/vnd.github.v3+json",
|
|
224
|
+
"User-Agent": "scaffold-mcp"
|
|
225
|
+
} });
|
|
226
|
+
if (!response.ok) throw new Error(`Failed to fetch directory contents: ${response.statusText}`);
|
|
227
|
+
const data = await response.json();
|
|
228
|
+
if (!Array.isArray(data)) throw new Error("Expected directory but got file");
|
|
229
|
+
return data.map((item) => ({
|
|
230
|
+
name: item.name,
|
|
231
|
+
type: item.type,
|
|
232
|
+
path: item.path
|
|
233
|
+
}));
|
|
234
|
+
}
|
|
235
|
+
|
|
138
236
|
//#endregion
|
|
139
237
|
//#region src/cli/add.ts
|
|
140
|
-
const execAsync = promisify(exec);
|
|
141
238
|
/**
|
|
142
239
|
* Add command - add a template to templates folder
|
|
143
240
|
*/
|
|
144
|
-
const addCommand = new Command("add").description("Add a template to templates folder").requiredOption("--name <name>", "Template name").requiredOption("--url <url>", "URL of the template repository to download").option("--path <path>", "Path to templates folder", "./templates").option("--type <type>", "Template type: boilerplate or scaffold", "boilerplate").action(async (options) => {
|
|
241
|
+
const addCommand = new commander.Command("add").description("Add a template to templates folder").requiredOption("--name <name>", "Template name").requiredOption("--url <url>", "URL of the template repository to download").option("--path <path>", "Path to templates folder", "./templates").option("--type <type>", "Template type: boilerplate or scaffold", "boilerplate").action(async (options) => {
|
|
145
242
|
try {
|
|
146
|
-
const templatesPath =
|
|
243
|
+
const templatesPath = node_path.default.resolve(options.path);
|
|
147
244
|
const templateType = options.type.toLowerCase();
|
|
148
245
|
const templateName = options.name;
|
|
149
246
|
const templateUrl = options.url;
|
|
@@ -151,25 +248,27 @@ const addCommand = new Command("add").description("Add a template to templates f
|
|
|
151
248
|
messages.error("Invalid template type. Use: boilerplate or scaffold");
|
|
152
249
|
process.exit(1);
|
|
153
250
|
}
|
|
154
|
-
const targetFolder =
|
|
155
|
-
if (await
|
|
251
|
+
const targetFolder = node_path.default.join(templatesPath, `${templateType}s`, templateName);
|
|
252
|
+
if (await fs_extra.pathExists(targetFolder)) {
|
|
156
253
|
messages.error(`Template '${templateName}' already exists at ${targetFolder}`);
|
|
157
254
|
process.exit(1);
|
|
158
255
|
}
|
|
159
256
|
logger.info(`${icons.download} Downloading template '${templateName}' from ${templateUrl}...`);
|
|
160
|
-
await
|
|
257
|
+
await fs_extra.ensureDir(node_path.default.dirname(targetFolder));
|
|
258
|
+
const parsedUrl = parseGitHubUrl(templateUrl);
|
|
161
259
|
try {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
260
|
+
if (parsedUrl.isSubdirectory && parsedUrl.branch && parsedUrl.subdirectory) {
|
|
261
|
+
logger.info(`${icons.folder} Detected subdirectory: ${parsedUrl.subdirectory} (branch: ${parsedUrl.branch})`);
|
|
262
|
+
await cloneSubdirectory(parsedUrl.repoUrl, parsedUrl.branch, parsedUrl.subdirectory, targetFolder);
|
|
263
|
+
} else await cloneRepository(parsedUrl.repoUrl, targetFolder);
|
|
165
264
|
messages.success(`Template '${templateName}' added successfully!`);
|
|
166
265
|
logger.header(`\n${icons.folder} Template location:`);
|
|
167
266
|
logger.indent(targetFolder);
|
|
168
|
-
const configFiles = [
|
|
267
|
+
const configFiles = [node_path.default.join(targetFolder, "boilerplate.yaml"), node_path.default.join(targetFolder, "scaffold.yaml")];
|
|
169
268
|
let hasConfig = false;
|
|
170
|
-
for (const configFile of configFiles) if (await
|
|
269
|
+
for (const configFile of configFiles) if (await fs_extra.pathExists(configFile)) {
|
|
171
270
|
logger.header(`\n${icons.config} Configuration file found:`);
|
|
172
|
-
logger.indent(
|
|
271
|
+
logger.indent(node_path.default.basename(configFile));
|
|
173
272
|
hasConfig = true;
|
|
174
273
|
break;
|
|
175
274
|
}
|
|
@@ -194,29 +293,29 @@ const addCommand = new Command("add").description("Add a template to templates f
|
|
|
194
293
|
//#endregion
|
|
195
294
|
//#region src/services/FileSystemService.ts
|
|
196
295
|
var FileSystemService = class {
|
|
197
|
-
async pathExists(path$
|
|
198
|
-
return
|
|
296
|
+
async pathExists(path$6) {
|
|
297
|
+
return fs_extra.default.pathExists(path$6);
|
|
199
298
|
}
|
|
200
|
-
async readFile(path$
|
|
201
|
-
return
|
|
299
|
+
async readFile(path$6, encoding = "utf8") {
|
|
300
|
+
return fs_extra.default.readFile(path$6, encoding);
|
|
202
301
|
}
|
|
203
|
-
async readJson(path$
|
|
204
|
-
return
|
|
302
|
+
async readJson(path$6) {
|
|
303
|
+
return fs_extra.default.readJson(path$6);
|
|
205
304
|
}
|
|
206
|
-
async writeFile(path$
|
|
207
|
-
return
|
|
305
|
+
async writeFile(path$6, content, encoding = "utf8") {
|
|
306
|
+
return fs_extra.default.writeFile(path$6, content, encoding);
|
|
208
307
|
}
|
|
209
|
-
async ensureDir(path$
|
|
210
|
-
return
|
|
308
|
+
async ensureDir(path$6) {
|
|
309
|
+
return fs_extra.default.ensureDir(path$6);
|
|
211
310
|
}
|
|
212
311
|
async copy(src, dest) {
|
|
213
|
-
return
|
|
312
|
+
return fs_extra.default.copy(src, dest);
|
|
214
313
|
}
|
|
215
|
-
async readdir(path$
|
|
216
|
-
return
|
|
314
|
+
async readdir(path$6) {
|
|
315
|
+
return fs_extra.default.readdir(path$6);
|
|
217
316
|
}
|
|
218
|
-
async stat(path$
|
|
219
|
-
return
|
|
317
|
+
async stat(path$6) {
|
|
318
|
+
return fs_extra.default.stat(path$6);
|
|
220
319
|
}
|
|
221
320
|
};
|
|
222
321
|
|
|
@@ -228,11 +327,11 @@ var BoilerplateService = class {
|
|
|
228
327
|
scaffoldService;
|
|
229
328
|
constructor(templatesPath) {
|
|
230
329
|
this.templatesPath = templatesPath;
|
|
231
|
-
this.templateService = new TemplateService();
|
|
330
|
+
this.templateService = new require_TemplateService.TemplateService();
|
|
232
331
|
const fileSystemService = new FileSystemService();
|
|
233
|
-
const scaffoldConfigLoader = new ScaffoldConfigLoader(fileSystemService, this.templateService);
|
|
234
|
-
const variableReplacementService = new VariableReplacementService(fileSystemService, this.templateService);
|
|
235
|
-
this.scaffoldService = new ScaffoldService(fileSystemService, scaffoldConfigLoader, variableReplacementService, templatesPath);
|
|
332
|
+
const scaffoldConfigLoader = new require_ScaffoldConfigLoader.ScaffoldConfigLoader(fileSystemService, this.templateService);
|
|
333
|
+
const variableReplacementService = new require_VariableReplacementService.VariableReplacementService(fileSystemService, this.templateService);
|
|
334
|
+
this.scaffoldService = new require_ScaffoldService.ScaffoldService(fileSystemService, scaffoldConfigLoader, variableReplacementService, templatesPath);
|
|
236
335
|
}
|
|
237
336
|
/**
|
|
238
337
|
* Scans all scaffold.yaml files and returns available boilerplates
|
|
@@ -241,10 +340,10 @@ var BoilerplateService = class {
|
|
|
241
340
|
const boilerplates = [];
|
|
242
341
|
const templateDirs = await this.discoverTemplateDirectories();
|
|
243
342
|
for (const templatePath of templateDirs) {
|
|
244
|
-
const scaffoldYamlPath =
|
|
245
|
-
if (
|
|
246
|
-
const scaffoldContent =
|
|
247
|
-
const scaffoldConfig =
|
|
343
|
+
const scaffoldYamlPath = node_path.join(this.templatesPath, templatePath, "scaffold.yaml");
|
|
344
|
+
if (fs_extra.existsSync(scaffoldYamlPath)) try {
|
|
345
|
+
const scaffoldContent = fs_extra.readFileSync(scaffoldYamlPath, "utf8");
|
|
346
|
+
const scaffoldConfig = js_yaml.load(scaffoldContent);
|
|
248
347
|
if (scaffoldConfig.boilerplate) for (const boilerplate of scaffoldConfig.boilerplate) {
|
|
249
348
|
if (!boilerplate.targetFolder) {
|
|
250
349
|
console.warn(`Skipping boilerplate '${boilerplate.name}' in ${templatePath}: targetFolder is required in scaffold.yaml`);
|
|
@@ -273,15 +372,15 @@ var BoilerplateService = class {
|
|
|
273
372
|
async discoverTemplateDirectories() {
|
|
274
373
|
const templateDirs = [];
|
|
275
374
|
const findTemplates = (dir, baseDir = "") => {
|
|
276
|
-
if (!
|
|
277
|
-
const items =
|
|
375
|
+
if (!fs_extra.existsSync(dir)) return;
|
|
376
|
+
const items = fs_extra.readdirSync(dir);
|
|
278
377
|
const hasPackageJson = items.includes("package.json") || items.includes("package.json.liquid");
|
|
279
378
|
const hasScaffoldYaml = items.includes("scaffold.yaml");
|
|
280
379
|
if (hasPackageJson && hasScaffoldYaml) templateDirs.push(baseDir);
|
|
281
380
|
for (const item of items) {
|
|
282
|
-
const itemPath =
|
|
283
|
-
if (
|
|
284
|
-
const newBaseDir = baseDir ?
|
|
381
|
+
const itemPath = node_path.join(dir, item);
|
|
382
|
+
if (fs_extra.statSync(itemPath).isDirectory() && !item.startsWith(".") && item !== "node_modules") {
|
|
383
|
+
const newBaseDir = baseDir ? node_path.join(baseDir, item) : item;
|
|
285
384
|
findTemplates(itemPath, newBaseDir);
|
|
286
385
|
}
|
|
287
386
|
}
|
|
@@ -366,13 +465,13 @@ var BoilerplateService = class {
|
|
|
366
465
|
validateBoilerplateVariables(boilerplate, variables) {
|
|
367
466
|
const errors = [];
|
|
368
467
|
try {
|
|
369
|
-
jsonSchemaToZod(boilerplate.variables_schema).parse(variables);
|
|
468
|
+
(0, __composio_json_schema_to_zod.jsonSchemaToZod)(boilerplate.variables_schema).parse(variables);
|
|
370
469
|
return {
|
|
371
470
|
isValid: true,
|
|
372
471
|
errors: []
|
|
373
472
|
};
|
|
374
473
|
} catch (error) {
|
|
375
|
-
if (error instanceof z.ZodError) {
|
|
474
|
+
if (error instanceof zod.z.ZodError) {
|
|
376
475
|
const zodErrors = error.errors.map((err) => {
|
|
377
476
|
return `${err.path.length > 0 ? err.path.join(".") : "root"}: ${err.message}`;
|
|
378
477
|
});
|
|
@@ -389,11 +488,11 @@ var BoilerplateService = class {
|
|
|
389
488
|
* If project.json exists, updates it; otherwise creates a new one
|
|
390
489
|
*/
|
|
391
490
|
ensureProjectJsonSourceTemplate(targetFolder, projectName, sourceTemplate) {
|
|
392
|
-
const projectJsonPath =
|
|
491
|
+
const projectJsonPath = node_path.join(targetFolder, projectName, "project.json");
|
|
393
492
|
try {
|
|
394
493
|
let projectJson;
|
|
395
|
-
if (
|
|
396
|
-
const content =
|
|
494
|
+
if (fs_extra.existsSync(projectJsonPath)) {
|
|
495
|
+
const content = fs_extra.readFileSync(projectJsonPath, "utf8");
|
|
397
496
|
projectJson = JSON.parse(content);
|
|
398
497
|
} else projectJson = {
|
|
399
498
|
name: projectName,
|
|
@@ -402,7 +501,7 @@ var BoilerplateService = class {
|
|
|
402
501
|
projectType: "application"
|
|
403
502
|
};
|
|
404
503
|
projectJson.sourceTemplate = sourceTemplate;
|
|
405
|
-
|
|
504
|
+
fs_extra.writeFileSync(projectJsonPath, `${JSON.stringify(projectJson, null, 2)}\n`, "utf8");
|
|
406
505
|
} catch (error) {
|
|
407
506
|
console.warn(`Failed to update project.json with sourceTemplate: ${error}`);
|
|
408
507
|
}
|
|
@@ -411,14 +510,14 @@ var BoilerplateService = class {
|
|
|
411
510
|
|
|
412
511
|
//#endregion
|
|
413
512
|
//#region src/cli/boilerplate.ts
|
|
414
|
-
const templatesDir$1 = TemplatesManager.findTemplatesPathSync();
|
|
415
513
|
/**
|
|
416
514
|
* Boilerplate CLI command
|
|
417
515
|
*/
|
|
418
|
-
const boilerplateCommand = new Command("boilerplate").description("Manage boilerplate templates");
|
|
516
|
+
const boilerplateCommand = new commander.Command("boilerplate").description("Manage boilerplate templates");
|
|
419
517
|
boilerplateCommand.command("list").description("List all available boilerplate templates").action(async () => {
|
|
420
518
|
try {
|
|
421
|
-
const
|
|
519
|
+
const templatesDir = await require_ScaffoldService.TemplatesManager.findTemplatesPath();
|
|
520
|
+
const { boilerplates } = await new BoilerplateService(templatesDir).listBoilerplates();
|
|
422
521
|
if (boilerplates.length === 0) {
|
|
423
522
|
messages.warning("No boilerplate templates found.");
|
|
424
523
|
return;
|
|
@@ -439,7 +538,8 @@ boilerplateCommand.command("list").description("List all available boilerplate t
|
|
|
439
538
|
});
|
|
440
539
|
boilerplateCommand.command("create <boilerplateName>").description("Create a new project from a boilerplate template").option("-v, --vars <json>", "JSON string containing variables for the boilerplate").option("--verbose", "Enable verbose logging").action(async (boilerplateName, options) => {
|
|
441
540
|
try {
|
|
442
|
-
const
|
|
541
|
+
const templatesDir = await require_ScaffoldService.TemplatesManager.findTemplatesPath();
|
|
542
|
+
const boilerplateService = new BoilerplateService(templatesDir);
|
|
443
543
|
let variables = {};
|
|
444
544
|
if (options.vars) try {
|
|
445
545
|
variables = JSON.parse(options.vars);
|
|
@@ -498,7 +598,8 @@ boilerplateCommand.command("create <boilerplateName>").description("Create a new
|
|
|
498
598
|
});
|
|
499
599
|
boilerplateCommand.command("info <boilerplateName>").description("Show detailed information about a boilerplate template").action(async (boilerplateName) => {
|
|
500
600
|
try {
|
|
501
|
-
const
|
|
601
|
+
const templatesDir = await require_ScaffoldService.TemplatesManager.findTemplatesPath();
|
|
602
|
+
const bp = await new BoilerplateService(templatesDir).getBoilerplate(boilerplateName);
|
|
502
603
|
if (!bp) {
|
|
503
604
|
messages.error(`Boilerplate '${boilerplateName}' not found.`);
|
|
504
605
|
process.exit(1);
|
|
@@ -522,36 +623,69 @@ boilerplateCommand.command("info <boilerplateName>").description("Show detailed
|
|
|
522
623
|
* Find the workspace root by searching upwards for .git folder
|
|
523
624
|
*/
|
|
524
625
|
async function findWorkspaceRoot(startPath = process.cwd()) {
|
|
525
|
-
let currentPath =
|
|
526
|
-
const rootPath =
|
|
626
|
+
let currentPath = node_path.default.resolve(startPath);
|
|
627
|
+
const rootPath = node_path.default.parse(currentPath).root;
|
|
527
628
|
while (true) {
|
|
528
|
-
const gitPath =
|
|
529
|
-
if (await
|
|
629
|
+
const gitPath = node_path.default.join(currentPath, ".git");
|
|
630
|
+
if (await fs_extra.pathExists(gitPath)) return currentPath;
|
|
530
631
|
if (currentPath === rootPath) return process.cwd();
|
|
531
|
-
currentPath =
|
|
632
|
+
currentPath = node_path.default.dirname(currentPath);
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
const DEFAULT_TEMPLATE_REPO = {
|
|
636
|
+
owner: "AgiFlow",
|
|
637
|
+
repo: "aicode-toolkit",
|
|
638
|
+
branch: "main",
|
|
639
|
+
path: "templates"
|
|
640
|
+
};
|
|
641
|
+
/**
|
|
642
|
+
* Download templates from GitHub repository
|
|
643
|
+
*/
|
|
644
|
+
async function downloadTemplates(templatesPath) {
|
|
645
|
+
try {
|
|
646
|
+
logger.info(`${icons.download} Fetching templates from ${DEFAULT_TEMPLATE_REPO.owner}/${DEFAULT_TEMPLATE_REPO.repo}...`);
|
|
647
|
+
const templateDirs = (await fetchGitHubDirectoryContents(DEFAULT_TEMPLATE_REPO.owner, DEFAULT_TEMPLATE_REPO.repo, DEFAULT_TEMPLATE_REPO.path, DEFAULT_TEMPLATE_REPO.branch)).filter((item) => item.type === "dir");
|
|
648
|
+
if (templateDirs.length === 0) {
|
|
649
|
+
messages.warning("No templates found in repository");
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
logger.info(`${icons.folder} Found ${templateDirs.length} template(s)`);
|
|
653
|
+
for (const template of templateDirs) {
|
|
654
|
+
const targetFolder = node_path.default.join(templatesPath, template.name);
|
|
655
|
+
if (await fs_extra.pathExists(targetFolder)) {
|
|
656
|
+
logger.info(`${icons.skip} Skipping ${template.name} (already exists)`);
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
logger.info(`${icons.download} Downloading ${template.name}...`);
|
|
660
|
+
const repoUrl = `https://github.com/${DEFAULT_TEMPLATE_REPO.owner}/${DEFAULT_TEMPLATE_REPO.repo}.git`;
|
|
661
|
+
await cloneSubdirectory(repoUrl, DEFAULT_TEMPLATE_REPO.branch, template.path, targetFolder);
|
|
662
|
+
logger.success(`${icons.check} Downloaded ${template.name}`);
|
|
663
|
+
}
|
|
664
|
+
logger.success(`\n${icons.check} All templates downloaded successfully!`);
|
|
665
|
+
} catch (error) {
|
|
666
|
+
throw new Error(`Failed to download templates: ${error.message}`);
|
|
532
667
|
}
|
|
533
668
|
}
|
|
534
669
|
/**
|
|
535
670
|
* Init command - initialize templates folder
|
|
536
671
|
*/
|
|
537
|
-
const initCommand = new Command("init").description("Initialize templates folder structure at workspace root").action(async () => {
|
|
672
|
+
const initCommand = new commander.Command("init").description("Initialize templates folder structure at workspace root").option("--no-download", "Skip downloading templates from repository").option("--path <path>", "Custom path for templates folder (relative to workspace root)").action(async (options) => {
|
|
538
673
|
try {
|
|
539
674
|
const workspaceRoot = await findWorkspaceRoot();
|
|
540
|
-
const templatesPath = path.join(workspaceRoot, "templates");
|
|
675
|
+
const templatesPath = options.path ? node_path.default.join(workspaceRoot, options.path) : node_path.default.join(workspaceRoot, "templates");
|
|
541
676
|
logger.info(`${icons.rocket} Initializing templates folder at: ${templatesPath}`);
|
|
542
|
-
await
|
|
543
|
-
await
|
|
544
|
-
await fs$1.ensureDir(path.join(templatesPath, "scaffolds"));
|
|
545
|
-
await fs$1.writeFile(path.join(templatesPath, "README.md"), `# Templates
|
|
677
|
+
await fs_extra.ensureDir(templatesPath);
|
|
678
|
+
await fs_extra.writeFile(node_path.default.join(templatesPath, "README.md"), `# Templates
|
|
546
679
|
|
|
547
680
|
This folder contains boilerplate templates and scaffolding methods for your projects.
|
|
548
681
|
|
|
549
|
-
##
|
|
682
|
+
## Templates
|
|
550
683
|
|
|
551
|
-
|
|
552
|
-
-
|
|
684
|
+
Templates are organized by framework/technology and include configuration files (\`scaffold.yaml\`) that define:
|
|
685
|
+
- Boilerplates: Full project starter templates
|
|
686
|
+
- Features: Code scaffolding methods for adding new features to existing projects
|
|
553
687
|
|
|
554
|
-
## Adding Templates
|
|
688
|
+
## Adding More Templates
|
|
555
689
|
|
|
556
690
|
Use the \`add\` command to add templates from remote repositories:
|
|
557
691
|
|
|
@@ -559,31 +693,38 @@ Use the \`add\` command to add templates from remote repositories:
|
|
|
559
693
|
scaffold-mcp add --name my-template --url https://github.com/user/template
|
|
560
694
|
\`\`\`
|
|
561
695
|
|
|
562
|
-
|
|
696
|
+
Or add templates from subdirectories:
|
|
563
697
|
|
|
564
|
-
|
|
698
|
+
\`\`\`bash
|
|
699
|
+
scaffold-mcp add --name nextjs-template --url https://github.com/user/repo/tree/main/templates/nextjs
|
|
700
|
+
\`\`\`
|
|
565
701
|
|
|
566
|
-
|
|
567
|
-
- \`boilerplate.yaml\` - Configuration file
|
|
568
|
-
- Template files with variable placeholders using Liquid syntax (\`{{ variableName }}\`)
|
|
702
|
+
## Creating Custom Templates
|
|
569
703
|
|
|
570
|
-
|
|
704
|
+
Each template should have a \`scaffold.yaml\` configuration file defining:
|
|
705
|
+
- \`boilerplate\`: Array of boilerplate configurations
|
|
706
|
+
- \`features\`: Array of feature scaffold configurations
|
|
571
707
|
|
|
572
|
-
|
|
573
|
-
- \`scaffold.yaml\` - Configuration file
|
|
574
|
-
- Template files organized by project type
|
|
708
|
+
Template files use Liquid syntax for variable placeholders: \`{{ variableName }}\`
|
|
575
709
|
|
|
576
|
-
See documentation for more details
|
|
710
|
+
See existing templates for examples and documentation for more details.
|
|
577
711
|
`);
|
|
578
|
-
logger.success(`${icons.check} Templates folder
|
|
579
|
-
|
|
580
|
-
logger.
|
|
581
|
-
logger.
|
|
582
|
-
logger.indent(
|
|
583
|
-
|
|
584
|
-
|
|
712
|
+
logger.success(`${icons.check} Templates folder created!`);
|
|
713
|
+
if (options.download !== false) await downloadTemplates(templatesPath);
|
|
714
|
+
else logger.info(`${icons.skip} Skipping template download (use --download to enable)`);
|
|
715
|
+
logger.header(`\n${icons.folder} Templates location:`);
|
|
716
|
+
logger.indent(templatesPath);
|
|
717
|
+
const nextSteps = [];
|
|
718
|
+
if (options.download === false) {
|
|
719
|
+
nextSteps.push(`Download templates: scaffold-mcp init --download`);
|
|
720
|
+
nextSteps.push(`Add templates manually: scaffold-mcp add --name <name> --url <url>`);
|
|
721
|
+
} else {
|
|
722
|
+
nextSteps.push(`List available boilerplates: scaffold-mcp boilerplate list`);
|
|
723
|
+
nextSteps.push(`Add more templates: scaffold-mcp add --name <name> --url <url>`);
|
|
724
|
+
}
|
|
725
|
+
sections.nextSteps(nextSteps);
|
|
585
726
|
} catch (error) {
|
|
586
|
-
|
|
727
|
+
messages.error(`Error initializing templates folder: ${error.message}`);
|
|
587
728
|
process.exit(1);
|
|
588
729
|
}
|
|
589
730
|
});
|
|
@@ -1025,7 +1166,7 @@ var BoilerplateGeneratorService = class {
|
|
|
1025
1166
|
* Custom YAML dumper that forces literal block style (|) for description and instruction fields
|
|
1026
1167
|
*/
|
|
1027
1168
|
dumpYamlWithLiteralBlocks(config) {
|
|
1028
|
-
const LiteralBlockType = new
|
|
1169
|
+
const LiteralBlockType = new js_yaml.Type("tag:yaml.org,2002:str", {
|
|
1029
1170
|
kind: "scalar",
|
|
1030
1171
|
construct: (data) => data,
|
|
1031
1172
|
represent: (data) => {
|
|
@@ -1033,9 +1174,9 @@ var BoilerplateGeneratorService = class {
|
|
|
1033
1174
|
},
|
|
1034
1175
|
defaultStyle: "|"
|
|
1035
1176
|
});
|
|
1036
|
-
const LITERAL_SCHEMA =
|
|
1177
|
+
const LITERAL_SCHEMA = js_yaml.DEFAULT_SCHEMA.extend([LiteralBlockType]);
|
|
1037
1178
|
const processedConfig = this.processConfigForLiteralBlocks(config);
|
|
1038
|
-
return
|
|
1179
|
+
return js_yaml.dump(processedConfig, {
|
|
1039
1180
|
schema: LITERAL_SCHEMA,
|
|
1040
1181
|
indent: 2,
|
|
1041
1182
|
lineWidth: -1,
|
|
@@ -1078,13 +1219,13 @@ var BoilerplateGeneratorService = class {
|
|
|
1078
1219
|
*/
|
|
1079
1220
|
async generateBoilerplate(options) {
|
|
1080
1221
|
const { templateName, boilerplateName, description, instruction, targetFolder, variables, includes = [] } = options;
|
|
1081
|
-
const templatePath =
|
|
1082
|
-
await
|
|
1083
|
-
const scaffoldYamlPath =
|
|
1222
|
+
const templatePath = node_path.join(this.templatesPath, templateName);
|
|
1223
|
+
await fs_extra.ensureDir(templatePath);
|
|
1224
|
+
const scaffoldYamlPath = node_path.join(templatePath, "scaffold.yaml");
|
|
1084
1225
|
let scaffoldConfig = {};
|
|
1085
|
-
if (await
|
|
1086
|
-
const yamlContent$1 = await
|
|
1087
|
-
scaffoldConfig =
|
|
1226
|
+
if (await fs_extra.pathExists(scaffoldYamlPath)) {
|
|
1227
|
+
const yamlContent$1 = await fs_extra.readFile(scaffoldYamlPath, "utf-8");
|
|
1228
|
+
scaffoldConfig = js_yaml.load(yamlContent$1);
|
|
1088
1229
|
}
|
|
1089
1230
|
if (!scaffoldConfig.boilerplate) scaffoldConfig.boilerplate = [];
|
|
1090
1231
|
if (scaffoldConfig.boilerplate.findIndex((b) => b.name === boilerplateName) !== -1) return {
|
|
@@ -1115,7 +1256,7 @@ var BoilerplateGeneratorService = class {
|
|
|
1115
1256
|
if (instruction) boilerplateDefinition.instruction = instruction;
|
|
1116
1257
|
scaffoldConfig.boilerplate.push(boilerplateDefinition);
|
|
1117
1258
|
const yamlContent = this.dumpYamlWithLiteralBlocks(scaffoldConfig);
|
|
1118
|
-
await
|
|
1259
|
+
await fs_extra.writeFile(scaffoldYamlPath, yamlContent, "utf-8");
|
|
1119
1260
|
return {
|
|
1120
1261
|
success: true,
|
|
1121
1262
|
message: `Boilerplate '${boilerplateName}' added to ${scaffoldYamlPath}`,
|
|
@@ -1127,43 +1268,43 @@ var BoilerplateGeneratorService = class {
|
|
|
1127
1268
|
* List all templates (directories in templates folder)
|
|
1128
1269
|
*/
|
|
1129
1270
|
async listTemplates() {
|
|
1130
|
-
return (await
|
|
1271
|
+
return (await fs_extra.readdir(this.templatesPath, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
1131
1272
|
}
|
|
1132
1273
|
/**
|
|
1133
1274
|
* Check if a template exists
|
|
1134
1275
|
*/
|
|
1135
1276
|
async templateExists(templateName) {
|
|
1136
|
-
const templatePath =
|
|
1137
|
-
return
|
|
1277
|
+
const templatePath = node_path.join(this.templatesPath, templateName);
|
|
1278
|
+
return fs_extra.pathExists(templatePath);
|
|
1138
1279
|
}
|
|
1139
1280
|
/**
|
|
1140
1281
|
* Create or update a template file for a boilerplate
|
|
1141
1282
|
*/
|
|
1142
1283
|
async createTemplateFile(options) {
|
|
1143
1284
|
const { templateName, filePath, content, sourceFile, header } = options;
|
|
1144
|
-
const templatePath =
|
|
1145
|
-
if (!await
|
|
1285
|
+
const templatePath = node_path.join(this.templatesPath, templateName);
|
|
1286
|
+
if (!await fs_extra.pathExists(templatePath)) return {
|
|
1146
1287
|
success: false,
|
|
1147
1288
|
message: `Template directory '${templateName}' does not exist at ${templatePath}`
|
|
1148
1289
|
};
|
|
1149
1290
|
let fileContent = content || "";
|
|
1150
1291
|
if (sourceFile) {
|
|
1151
|
-
if (!await
|
|
1292
|
+
if (!await fs_extra.pathExists(sourceFile)) return {
|
|
1152
1293
|
success: false,
|
|
1153
1294
|
message: `Source file '${sourceFile}' does not exist`
|
|
1154
1295
|
};
|
|
1155
|
-
fileContent = await
|
|
1296
|
+
fileContent = await fs_extra.readFile(sourceFile, "utf-8");
|
|
1156
1297
|
}
|
|
1157
1298
|
if (!fileContent && !sourceFile) return {
|
|
1158
1299
|
success: false,
|
|
1159
1300
|
message: "Either content or sourceFile must be provided"
|
|
1160
1301
|
};
|
|
1161
1302
|
const templateFilePath = filePath.endsWith(".liquid") ? filePath : `${filePath}.liquid`;
|
|
1162
|
-
const fullPath =
|
|
1163
|
-
await
|
|
1303
|
+
const fullPath = node_path.join(templatePath, templateFilePath);
|
|
1304
|
+
await fs_extra.ensureDir(node_path.dirname(fullPath));
|
|
1164
1305
|
let finalContent = fileContent;
|
|
1165
1306
|
if (header) finalContent = `${header}\n\n${fileContent}`;
|
|
1166
|
-
await
|
|
1307
|
+
await fs_extra.writeFile(fullPath, finalContent, "utf-8");
|
|
1167
1308
|
return {
|
|
1168
1309
|
success: true,
|
|
1169
1310
|
message: "Template file created successfully",
|
|
@@ -1525,7 +1666,7 @@ var ScaffoldGeneratorService = class {
|
|
|
1525
1666
|
* Custom YAML dumper that forces literal block style (|) for description and instruction fields
|
|
1526
1667
|
*/
|
|
1527
1668
|
dumpYamlWithLiteralBlocks(config) {
|
|
1528
|
-
const LiteralBlockType = new
|
|
1669
|
+
const LiteralBlockType = new js_yaml.Type("tag:yaml.org,2002:str", {
|
|
1529
1670
|
kind: "scalar",
|
|
1530
1671
|
construct: (data) => data,
|
|
1531
1672
|
represent: (data) => {
|
|
@@ -1533,9 +1674,9 @@ var ScaffoldGeneratorService = class {
|
|
|
1533
1674
|
},
|
|
1534
1675
|
defaultStyle: "|"
|
|
1535
1676
|
});
|
|
1536
|
-
const LITERAL_SCHEMA =
|
|
1677
|
+
const LITERAL_SCHEMA = js_yaml.DEFAULT_SCHEMA.extend([LiteralBlockType]);
|
|
1537
1678
|
const processedConfig = this.processConfigForLiteralBlocks(config);
|
|
1538
|
-
return
|
|
1679
|
+
return js_yaml.dump(processedConfig, {
|
|
1539
1680
|
schema: LITERAL_SCHEMA,
|
|
1540
1681
|
indent: 2,
|
|
1541
1682
|
lineWidth: -1,
|
|
@@ -1578,13 +1719,13 @@ var ScaffoldGeneratorService = class {
|
|
|
1578
1719
|
*/
|
|
1579
1720
|
async generateFeatureScaffold(options) {
|
|
1580
1721
|
const { templateName, featureName, description, instruction, variables, includes = [], patterns = [] } = options;
|
|
1581
|
-
const templatePath =
|
|
1582
|
-
await
|
|
1583
|
-
const scaffoldYamlPath =
|
|
1722
|
+
const templatePath = node_path.join(this.templatesPath, templateName);
|
|
1723
|
+
await fs_extra.ensureDir(templatePath);
|
|
1724
|
+
const scaffoldYamlPath = node_path.join(templatePath, "scaffold.yaml");
|
|
1584
1725
|
let scaffoldConfig = {};
|
|
1585
|
-
if (await
|
|
1586
|
-
const yamlContent$1 = await
|
|
1587
|
-
scaffoldConfig =
|
|
1726
|
+
if (await fs_extra.pathExists(scaffoldYamlPath)) {
|
|
1727
|
+
const yamlContent$1 = await fs_extra.readFile(scaffoldYamlPath, "utf-8");
|
|
1728
|
+
scaffoldConfig = js_yaml.load(yamlContent$1);
|
|
1588
1729
|
}
|
|
1589
1730
|
if (!scaffoldConfig.features) scaffoldConfig.features = [];
|
|
1590
1731
|
if (scaffoldConfig.features.findIndex((f) => f.name === featureName) !== -1) return {
|
|
@@ -1615,7 +1756,7 @@ var ScaffoldGeneratorService = class {
|
|
|
1615
1756
|
if (patterns && patterns.length > 0) featureDefinition.patterns = patterns;
|
|
1616
1757
|
scaffoldConfig.features.push(featureDefinition);
|
|
1617
1758
|
const yamlContent = this.dumpYamlWithLiteralBlocks(scaffoldConfig);
|
|
1618
|
-
await
|
|
1759
|
+
await fs_extra.writeFile(scaffoldYamlPath, yamlContent, "utf-8");
|
|
1619
1760
|
return {
|
|
1620
1761
|
success: true,
|
|
1621
1762
|
message: `Feature '${featureName}' added to ${scaffoldYamlPath}`,
|
|
@@ -1627,14 +1768,14 @@ var ScaffoldGeneratorService = class {
|
|
|
1627
1768
|
* List all templates (directories in templates folder)
|
|
1628
1769
|
*/
|
|
1629
1770
|
async listTemplates() {
|
|
1630
|
-
return (await
|
|
1771
|
+
return (await fs_extra.readdir(this.templatesPath, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
1631
1772
|
}
|
|
1632
1773
|
/**
|
|
1633
1774
|
* Check if a template exists
|
|
1634
1775
|
*/
|
|
1635
1776
|
async templateExists(templateName) {
|
|
1636
|
-
const templatePath =
|
|
1637
|
-
return
|
|
1777
|
+
const templatePath = node_path.join(this.templatesPath, templateName);
|
|
1778
|
+
return fs_extra.pathExists(templatePath);
|
|
1638
1779
|
}
|
|
1639
1780
|
};
|
|
1640
1781
|
|
|
@@ -1759,9 +1900,7 @@ Best practices:
|
|
|
1759
1900
|
- Use conditional includes with ?variableName=value for optional files
|
|
1760
1901
|
- Use path mapping with -> when source and target paths differ
|
|
1761
1902
|
- Use {{ variableName }} in target paths for dynamic file placement
|
|
1762
|
-
- Avoid wildcards unless you have a good reason
|
|
1763
|
-
|
|
1764
|
-
See templates/nextjs-15/scaffold.yaml features section for examples.`,
|
|
1903
|
+
- Avoid wildcards unless you have a good reason`,
|
|
1765
1904
|
items: { type: "string" }
|
|
1766
1905
|
},
|
|
1767
1906
|
patterns: {
|
|
@@ -1891,22 +2030,22 @@ var ScaffoldingMethodsService = class {
|
|
|
1891
2030
|
constructor(fileSystem, templatesRootPath) {
|
|
1892
2031
|
this.fileSystem = fileSystem;
|
|
1893
2032
|
this.templatesRootPath = templatesRootPath;
|
|
1894
|
-
this.templateService = new TemplateService();
|
|
2033
|
+
this.templateService = new require_TemplateService.TemplateService();
|
|
1895
2034
|
}
|
|
1896
2035
|
async listScaffoldingMethods(projectPath) {
|
|
1897
|
-
const absoluteProjectPath =
|
|
1898
|
-
const projectJsonPath =
|
|
2036
|
+
const absoluteProjectPath = node_path.default.resolve(projectPath);
|
|
2037
|
+
const projectJsonPath = node_path.default.join(absoluteProjectPath, "project.json");
|
|
1899
2038
|
if (!await this.fileSystem.pathExists(projectJsonPath)) throw new Error(`project.json not found at ${projectJsonPath}`);
|
|
1900
2039
|
const projectConfig = await this.fileSystem.readJson(projectJsonPath);
|
|
1901
2040
|
if (!projectConfig.sourceTemplate) throw new Error(`sourceTemplate not specified in project.json at ${projectJsonPath}`);
|
|
1902
2041
|
const sourceTemplate = projectConfig.sourceTemplate;
|
|
1903
2042
|
const templatePath = await this.findTemplatePath(sourceTemplate);
|
|
1904
2043
|
if (!templatePath) throw new Error(`Template not found for sourceTemplate: ${sourceTemplate}`);
|
|
1905
|
-
const fullTemplatePath =
|
|
1906
|
-
const scaffoldYamlPath =
|
|
2044
|
+
const fullTemplatePath = node_path.default.join(this.templatesRootPath, templatePath);
|
|
2045
|
+
const scaffoldYamlPath = node_path.default.join(fullTemplatePath, "scaffold.yaml");
|
|
1907
2046
|
if (!await this.fileSystem.pathExists(scaffoldYamlPath)) throw new Error(`scaffold.yaml not found at ${scaffoldYamlPath}`);
|
|
1908
2047
|
const scaffoldContent = await this.fileSystem.readFile(scaffoldYamlPath, "utf8");
|
|
1909
|
-
const architectConfig =
|
|
2048
|
+
const architectConfig = js_yaml.default.load(scaffoldContent);
|
|
1910
2049
|
const methods = [];
|
|
1911
2050
|
if (architectConfig.features && Array.isArray(architectConfig.features)) architectConfig.features.forEach((feature) => {
|
|
1912
2051
|
if (feature.name) methods.push({
|
|
@@ -1953,11 +2092,11 @@ var ScaffoldingMethodsService = class {
|
|
|
1953
2092
|
const templateDirs = await this.discoverTemplateDirs();
|
|
1954
2093
|
if (templateDirs.includes(sourceTemplate)) return sourceTemplate;
|
|
1955
2094
|
for (const templateDir of templateDirs) {
|
|
1956
|
-
const templatePath =
|
|
1957
|
-
const scaffoldYamlPath =
|
|
2095
|
+
const templatePath = node_path.default.join(this.templatesRootPath, templateDir);
|
|
2096
|
+
const scaffoldYamlPath = node_path.default.join(templatePath, "scaffold.yaml");
|
|
1958
2097
|
if (await this.fileSystem.pathExists(scaffoldYamlPath)) try {
|
|
1959
2098
|
const scaffoldContent = await this.fileSystem.readFile(scaffoldYamlPath, "utf8");
|
|
1960
|
-
const architectConfig =
|
|
2099
|
+
const architectConfig = js_yaml.default.load(scaffoldContent);
|
|
1961
2100
|
if (architectConfig.boilerplate && Array.isArray(architectConfig.boilerplate)) {
|
|
1962
2101
|
for (const boilerplate of architectConfig.boilerplate) if (boilerplate.name?.includes(sourceTemplate)) return templateDir;
|
|
1963
2102
|
}
|
|
@@ -1976,9 +2115,9 @@ var ScaffoldingMethodsService = class {
|
|
|
1976
2115
|
try {
|
|
1977
2116
|
const items = await this.fileSystem.readdir(this.templatesRootPath);
|
|
1978
2117
|
for (const item of items) {
|
|
1979
|
-
const itemPath =
|
|
2118
|
+
const itemPath = node_path.default.join(this.templatesRootPath, item);
|
|
1980
2119
|
if (!(await this.fileSystem.stat(itemPath)).isDirectory()) continue;
|
|
1981
|
-
const scaffoldYamlPath =
|
|
2120
|
+
const scaffoldYamlPath = node_path.default.join(itemPath, "scaffold.yaml");
|
|
1982
2121
|
if (await this.fileSystem.pathExists(scaffoldYamlPath)) {
|
|
1983
2122
|
templateDirs.push(item);
|
|
1984
2123
|
continue;
|
|
@@ -1986,11 +2125,11 @@ var ScaffoldingMethodsService = class {
|
|
|
1986
2125
|
try {
|
|
1987
2126
|
const subItems = await this.fileSystem.readdir(itemPath);
|
|
1988
2127
|
for (const subItem of subItems) {
|
|
1989
|
-
const subItemPath =
|
|
2128
|
+
const subItemPath = node_path.default.join(itemPath, subItem);
|
|
1990
2129
|
if (!(await this.fileSystem.stat(subItemPath)).isDirectory()) continue;
|
|
1991
|
-
const subScaffoldYamlPath =
|
|
2130
|
+
const subScaffoldYamlPath = node_path.default.join(subItemPath, "scaffold.yaml");
|
|
1992
2131
|
if (await this.fileSystem.pathExists(subScaffoldYamlPath)) {
|
|
1993
|
-
const relativePath =
|
|
2132
|
+
const relativePath = node_path.default.join(item, subItem);
|
|
1994
2133
|
templateDirs.push(relativePath);
|
|
1995
2134
|
}
|
|
1996
2135
|
}
|
|
@@ -2011,16 +2150,16 @@ var ScaffoldingMethodsService = class {
|
|
|
2011
2150
|
const availableMethods = scaffoldingMethods.methods.map((m) => m.name).join(", ");
|
|
2012
2151
|
throw new Error(`Scaffold method '${scaffold_feature_name}' not found. Available methods: ${availableMethods}`);
|
|
2013
2152
|
}
|
|
2014
|
-
const ScaffoldService$1 = (await
|
|
2015
|
-
const ScaffoldConfigLoader$1 = (await
|
|
2016
|
-
const VariableReplacementService$1 = (await
|
|
2017
|
-
const TemplateService$1 = (await
|
|
2153
|
+
const ScaffoldService$1 = (await Promise.resolve().then(() => require("./ScaffoldService-BXKXXg4M.js"))).ScaffoldService;
|
|
2154
|
+
const ScaffoldConfigLoader$1 = (await Promise.resolve().then(() => require("./ScaffoldConfigLoader-CnVkzUxL.js"))).ScaffoldConfigLoader;
|
|
2155
|
+
const VariableReplacementService$1 = (await Promise.resolve().then(() => require("./VariableReplacementService-_GgLG4Im.js"))).VariableReplacementService;
|
|
2156
|
+
const TemplateService$1 = (await Promise.resolve().then(() => require("./TemplateService-B0ns4TR_.js"))).TemplateService;
|
|
2018
2157
|
const templateService = new TemplateService$1();
|
|
2019
2158
|
const scaffoldConfigLoader = new ScaffoldConfigLoader$1(this.fileSystem, templateService);
|
|
2020
2159
|
const variableReplacer = new VariableReplacementService$1(this.fileSystem, templateService);
|
|
2021
2160
|
const scaffoldService = new ScaffoldService$1(this.fileSystem, scaffoldConfigLoader, variableReplacer, this.templatesRootPath);
|
|
2022
|
-
const absoluteProjectPath =
|
|
2023
|
-
const projectName =
|
|
2161
|
+
const absoluteProjectPath = node_path.default.resolve(projectPath);
|
|
2162
|
+
const projectName = node_path.default.basename(absoluteProjectPath);
|
|
2024
2163
|
const result = await scaffoldService.useFeature({
|
|
2025
2164
|
projectPath: absoluteProjectPath,
|
|
2026
2165
|
templateFolder: scaffoldingMethods.templatePath,
|
|
@@ -2322,8 +2461,8 @@ Parameters:
|
|
|
2322
2461
|
const { file_path, content } = args;
|
|
2323
2462
|
if (!file_path) throw new Error("Missing required parameter: file_path");
|
|
2324
2463
|
if (content === void 0 || content === null) throw new Error("Missing required parameter: content");
|
|
2325
|
-
const resolvedPath =
|
|
2326
|
-
const dirPath =
|
|
2464
|
+
const resolvedPath = node_path.default.isAbsolute(file_path) ? file_path : node_path.default.resolve(process.cwd(), file_path);
|
|
2465
|
+
const dirPath = node_path.default.dirname(resolvedPath);
|
|
2327
2466
|
await this.fileSystemService.ensureDir(dirPath);
|
|
2328
2467
|
await this.fileSystemService.writeFile(resolvedPath, content);
|
|
2329
2468
|
return { content: [{
|
|
@@ -2346,7 +2485,7 @@ Parameters:
|
|
|
2346
2485
|
//#region src/server/index.ts
|
|
2347
2486
|
function createServer(options = {}) {
|
|
2348
2487
|
const { adminEnabled = false } = options;
|
|
2349
|
-
const templatesPath = TemplatesManager.findTemplatesPathSync();
|
|
2488
|
+
const templatesPath = require_ScaffoldService.TemplatesManager.findTemplatesPathSync();
|
|
2350
2489
|
const listBoilerplatesTool = new ListBoilerplatesTool(templatesPath);
|
|
2351
2490
|
const useBoilerplateTool = new UseBoilerplateTool(templatesPath);
|
|
2352
2491
|
const listScaffoldingMethodsTool = new ListScaffoldingMethodsTool(templatesPath);
|
|
@@ -2359,7 +2498,7 @@ function createServer(options = {}) {
|
|
|
2359
2498
|
const generateFeatureScaffoldPrompt = adminEnabled ? new GenerateFeatureScaffoldPrompt() : null;
|
|
2360
2499
|
const scaffoldApplicationPrompt = new ScaffoldApplicationPrompt();
|
|
2361
2500
|
const scaffoldFeaturePrompt = new ScaffoldFeaturePrompt();
|
|
2362
|
-
const server = new Server({
|
|
2501
|
+
const server = new __modelcontextprotocol_sdk_server_index_js.Server({
|
|
2363
2502
|
name: "scaffold-mcp",
|
|
2364
2503
|
version: "1.0.0"
|
|
2365
2504
|
}, {
|
|
@@ -2423,7 +2562,7 @@ Example workflow for feature:
|
|
|
2423
2562
|
prompts: {}
|
|
2424
2563
|
}
|
|
2425
2564
|
});
|
|
2426
|
-
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
|
2565
|
+
server.setRequestHandler(__modelcontextprotocol_sdk_types_js.ListToolsRequestSchema, async () => {
|
|
2427
2566
|
const listBoilerplateTool = listBoilerplatesTool.getDefinition();
|
|
2428
2567
|
const useBoilerplateToolDef = useBoilerplateTool.getDefinition();
|
|
2429
2568
|
const listScaffoldingMethodsToolDef = listScaffoldingMethodsTool.getDefinition();
|
|
@@ -2443,7 +2582,7 @@ Example workflow for feature:
|
|
|
2443
2582
|
}
|
|
2444
2583
|
return { tools };
|
|
2445
2584
|
});
|
|
2446
|
-
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
2585
|
+
server.setRequestHandler(__modelcontextprotocol_sdk_types_js.CallToolRequestSchema, async (request) => {
|
|
2447
2586
|
const { name, arguments: args } = request.params;
|
|
2448
2587
|
if (name === ListBoilerplatesTool.TOOL_NAME) return await listBoilerplatesTool.execute(args || {});
|
|
2449
2588
|
if (name === UseBoilerplateTool.TOOL_NAME) return await useBoilerplateTool.execute(args || {});
|
|
@@ -2464,7 +2603,7 @@ Example workflow for feature:
|
|
|
2464
2603
|
}
|
|
2465
2604
|
throw new Error(`Unknown tool: ${name}`);
|
|
2466
2605
|
});
|
|
2467
|
-
server.setRequestHandler(ListPromptsRequestSchema, async () => {
|
|
2606
|
+
server.setRequestHandler(__modelcontextprotocol_sdk_types_js.ListPromptsRequestSchema, async () => {
|
|
2468
2607
|
const prompts = [];
|
|
2469
2608
|
prompts.push(scaffoldApplicationPrompt.getDefinition());
|
|
2470
2609
|
prompts.push(scaffoldFeaturePrompt.getDefinition());
|
|
@@ -2474,7 +2613,7 @@ Example workflow for feature:
|
|
|
2474
2613
|
}
|
|
2475
2614
|
return { prompts };
|
|
2476
2615
|
});
|
|
2477
|
-
server.setRequestHandler(GetPromptRequestSchema, async (request) => {
|
|
2616
|
+
server.setRequestHandler(__modelcontextprotocol_sdk_types_js.GetPromptRequestSchema, async (request) => {
|
|
2478
2617
|
const { name, arguments: args } = request.params;
|
|
2479
2618
|
if (name === ScaffoldApplicationPrompt.PROMPT_NAME) return { messages: scaffoldApplicationPrompt.getMessages(args) };
|
|
2480
2619
|
if (name === ScaffoldFeaturePrompt.PROMPT_NAME) return { messages: scaffoldFeaturePrompt.getMessages(args) };
|
|
@@ -2494,24 +2633,30 @@ Example workflow for feature:
|
|
|
2494
2633
|
//#endregion
|
|
2495
2634
|
//#region src/transports/http.ts
|
|
2496
2635
|
/**
|
|
2497
|
-
*
|
|
2636
|
+
* HTTP session manager
|
|
2498
2637
|
*/
|
|
2499
|
-
var
|
|
2500
|
-
|
|
2638
|
+
var HttpFullSessionManager = class {
|
|
2639
|
+
sessions = /* @__PURE__ */ new Map();
|
|
2501
2640
|
getSession(sessionId) {
|
|
2502
|
-
return this.
|
|
2641
|
+
return this.sessions.get(sessionId);
|
|
2503
2642
|
}
|
|
2504
|
-
setSession(sessionId, transport) {
|
|
2505
|
-
this.
|
|
2643
|
+
setSession(sessionId, transport, server) {
|
|
2644
|
+
this.sessions.set(sessionId, {
|
|
2645
|
+
transport,
|
|
2646
|
+
server
|
|
2647
|
+
});
|
|
2506
2648
|
}
|
|
2507
2649
|
deleteSession(sessionId) {
|
|
2508
|
-
this.
|
|
2650
|
+
const session = this.sessions.get(sessionId);
|
|
2651
|
+
if (session) session.server.close();
|
|
2652
|
+
this.sessions.delete(sessionId);
|
|
2509
2653
|
}
|
|
2510
2654
|
hasSession(sessionId) {
|
|
2511
|
-
return this.
|
|
2655
|
+
return this.sessions.has(sessionId);
|
|
2512
2656
|
}
|
|
2513
2657
|
clear() {
|
|
2514
|
-
this.
|
|
2658
|
+
for (const session of this.sessions.values()) session.server.close();
|
|
2659
|
+
this.sessions.clear();
|
|
2515
2660
|
}
|
|
2516
2661
|
};
|
|
2517
2662
|
/**
|
|
@@ -2519,15 +2664,15 @@ var HttpSessionManager = class {
|
|
|
2519
2664
|
* Provides stateful session management with resumability support
|
|
2520
2665
|
*/
|
|
2521
2666
|
var HttpTransportHandler = class {
|
|
2522
|
-
|
|
2667
|
+
serverFactory;
|
|
2523
2668
|
app;
|
|
2524
2669
|
server = null;
|
|
2525
2670
|
sessionManager;
|
|
2526
2671
|
config;
|
|
2527
|
-
constructor(
|
|
2528
|
-
this.
|
|
2529
|
-
this.app = express();
|
|
2530
|
-
this.sessionManager = new
|
|
2672
|
+
constructor(serverFactory, config) {
|
|
2673
|
+
this.serverFactory = typeof serverFactory === "function" ? serverFactory : () => serverFactory;
|
|
2674
|
+
this.app = (0, express.default)();
|
|
2675
|
+
this.sessionManager = new HttpFullSessionManager();
|
|
2531
2676
|
this.config = {
|
|
2532
2677
|
mode: config.mode,
|
|
2533
2678
|
port: config.port ?? 3e3,
|
|
@@ -2537,7 +2682,7 @@ var HttpTransportHandler = class {
|
|
|
2537
2682
|
this.setupRoutes();
|
|
2538
2683
|
}
|
|
2539
2684
|
setupMiddleware() {
|
|
2540
|
-
this.app.use(express.json());
|
|
2685
|
+
this.app.use(express.default.json());
|
|
2541
2686
|
}
|
|
2542
2687
|
setupRoutes() {
|
|
2543
2688
|
this.app.post("/mcp", async (req, res) => {
|
|
@@ -2559,18 +2704,20 @@ var HttpTransportHandler = class {
|
|
|
2559
2704
|
async handlePostRequest(req, res) {
|
|
2560
2705
|
const sessionId = req.headers["mcp-session-id"];
|
|
2561
2706
|
let transport;
|
|
2562
|
-
if (sessionId && this.sessionManager.hasSession(sessionId)) transport = this.sessionManager.getSession(sessionId);
|
|
2563
|
-
else if (!sessionId && isInitializeRequest(req.body)) {
|
|
2564
|
-
|
|
2565
|
-
|
|
2707
|
+
if (sessionId && this.sessionManager.hasSession(sessionId)) transport = this.sessionManager.getSession(sessionId).transport;
|
|
2708
|
+
else if (!sessionId && (0, __modelcontextprotocol_sdk_types_js.isInitializeRequest)(req.body)) {
|
|
2709
|
+
const mcpServer = this.serverFactory();
|
|
2710
|
+
transport = new __modelcontextprotocol_sdk_server_streamableHttp_js.StreamableHTTPServerTransport({
|
|
2711
|
+
sessionIdGenerator: () => (0, node_crypto.randomUUID)(),
|
|
2712
|
+
enableJsonResponse: true,
|
|
2566
2713
|
onsessioninitialized: (sessionId$1) => {
|
|
2567
|
-
this.sessionManager.setSession(sessionId$1, transport);
|
|
2714
|
+
this.sessionManager.setSession(sessionId$1, transport, mcpServer);
|
|
2568
2715
|
}
|
|
2569
2716
|
});
|
|
2570
2717
|
transport.onclose = () => {
|
|
2571
2718
|
if (transport.sessionId) this.sessionManager.deleteSession(transport.sessionId);
|
|
2572
2719
|
};
|
|
2573
|
-
await
|
|
2720
|
+
await mcpServer.connect(transport);
|
|
2574
2721
|
} else {
|
|
2575
2722
|
res.status(400).json({
|
|
2576
2723
|
jsonrpc: "2.0",
|
|
@@ -2590,7 +2737,7 @@ var HttpTransportHandler = class {
|
|
|
2590
2737
|
res.status(400).send("Invalid or missing session ID");
|
|
2591
2738
|
return;
|
|
2592
2739
|
}
|
|
2593
|
-
await this.sessionManager.getSession(sessionId).handleRequest(req, res);
|
|
2740
|
+
await this.sessionManager.getSession(sessionId).transport.handleRequest(req, res);
|
|
2594
2741
|
}
|
|
2595
2742
|
async handleDeleteRequest(req, res) {
|
|
2596
2743
|
const sessionId = req.headers["mcp-session-id"];
|
|
@@ -2598,7 +2745,7 @@ var HttpTransportHandler = class {
|
|
|
2598
2745
|
res.status(400).send("Invalid or missing session ID");
|
|
2599
2746
|
return;
|
|
2600
2747
|
}
|
|
2601
|
-
await this.sessionManager.getSession(sessionId).handleRequest(req, res);
|
|
2748
|
+
await this.sessionManager.getSession(sessionId).transport.handleRequest(req, res);
|
|
2602
2749
|
this.sessionManager.deleteSession(sessionId);
|
|
2603
2750
|
}
|
|
2604
2751
|
async start() {
|
|
@@ -2681,7 +2828,7 @@ var SseTransportHandler = class {
|
|
|
2681
2828
|
config;
|
|
2682
2829
|
constructor(serverFactory, config) {
|
|
2683
2830
|
this.serverFactory = typeof serverFactory === "function" ? serverFactory : () => serverFactory;
|
|
2684
|
-
this.app = express();
|
|
2831
|
+
this.app = (0, express.default)();
|
|
2685
2832
|
this.sessionManager = new SseSessionManager();
|
|
2686
2833
|
this.config = {
|
|
2687
2834
|
mode: config.mode,
|
|
@@ -2692,7 +2839,7 @@ var SseTransportHandler = class {
|
|
|
2692
2839
|
this.setupRoutes();
|
|
2693
2840
|
}
|
|
2694
2841
|
setupMiddleware() {
|
|
2695
|
-
this.app.use(express.json());
|
|
2842
|
+
this.app.use(express.default.json());
|
|
2696
2843
|
}
|
|
2697
2844
|
setupRoutes() {
|
|
2698
2845
|
this.app.get("/sse", async (req, res) => {
|
|
@@ -2711,7 +2858,7 @@ var SseTransportHandler = class {
|
|
|
2711
2858
|
async handleSseConnection(_req, res) {
|
|
2712
2859
|
try {
|
|
2713
2860
|
const mcpServer = this.serverFactory();
|
|
2714
|
-
const transport = new SSEServerTransport("/messages", res);
|
|
2861
|
+
const transport = new __modelcontextprotocol_sdk_server_sse_js.SSEServerTransport("/messages", res);
|
|
2715
2862
|
this.sessionManager.setSession(transport.sessionId, transport, mcpServer);
|
|
2716
2863
|
res.on("close", () => {
|
|
2717
2864
|
this.sessionManager.deleteSession(transport.sessionId);
|
|
@@ -2794,7 +2941,7 @@ var StdioTransportHandler = class {
|
|
|
2794
2941
|
this.server = server;
|
|
2795
2942
|
}
|
|
2796
2943
|
async start() {
|
|
2797
|
-
this.transport = new StdioServerTransport();
|
|
2944
|
+
this.transport = new __modelcontextprotocol_sdk_server_stdio_js.StdioServerTransport();
|
|
2798
2945
|
await this.server.connect(this.transport);
|
|
2799
2946
|
console.error("Scaffolding MCP server started on stdio");
|
|
2800
2947
|
}
|
|
@@ -2842,7 +2989,7 @@ async function startServer(handler) {
|
|
|
2842
2989
|
/**
|
|
2843
2990
|
* MCP Serve command
|
|
2844
2991
|
*/
|
|
2845
|
-
const mcpServeCommand = new Command("mcp-serve").description("Start MCP server with specified transport").option("-t, --type <type>", "Transport type: stdio, http, or sse", "stdio").option("-p, --port <port>", "Port to listen on (http/sse only)", (val) => parseInt(val, 10), 3e3).option("--host <host>", "Host to bind to (http/sse only)", "localhost").option("--admin-enable", "Enable admin tools (generate-boilerplate)", false).action(async (options) => {
|
|
2992
|
+
const mcpServeCommand = new commander.Command("mcp-serve").description("Start MCP server with specified transport").option("-t, --type <type>", "Transport type: stdio, http, or sse", "stdio").option("-p, --port <port>", "Port to listen on (http/sse only)", (val) => parseInt(val, 10), 3e3).option("--host <host>", "Host to bind to (http/sse only)", "localhost").option("--admin-enable", "Enable admin tools (generate-boilerplate)", false).action(async (options) => {
|
|
2846
2993
|
try {
|
|
2847
2994
|
const transportType = options.type.toLowerCase();
|
|
2848
2995
|
const serverOptions = { adminEnabled: options.adminEnable };
|
|
@@ -2851,13 +2998,12 @@ const mcpServeCommand = new Command("mcp-serve").description("Start MCP server w
|
|
|
2851
2998
|
const handler = new StdioTransportHandler(server);
|
|
2852
2999
|
await startServer(handler);
|
|
2853
3000
|
} else if (transportType === "http") {
|
|
2854
|
-
const server = createServer(serverOptions);
|
|
2855
3001
|
const config = {
|
|
2856
3002
|
mode: TransportMode.HTTP,
|
|
2857
3003
|
port: options.port || Number(process.env.MCP_PORT) || 3e3,
|
|
2858
3004
|
host: options.host || process.env.MCP_HOST || "localhost"
|
|
2859
3005
|
};
|
|
2860
|
-
const handler = new HttpTransportHandler(
|
|
3006
|
+
const handler = new HttpTransportHandler(() => createServer(serverOptions), config);
|
|
2861
3007
|
await startServer(handler);
|
|
2862
3008
|
} else if (transportType === "sse") {
|
|
2863
3009
|
const config = {
|
|
@@ -2879,21 +3025,19 @@ const mcpServeCommand = new Command("mcp-serve").description("Start MCP server w
|
|
|
2879
3025
|
|
|
2880
3026
|
//#endregion
|
|
2881
3027
|
//#region src/cli/scaffold.ts
|
|
2882
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
2883
|
-
const __dirname = path.dirname(__filename);
|
|
2884
|
-
const templatesDir = path.resolve(__dirname, "../../../../templates");
|
|
2885
3028
|
/**
|
|
2886
3029
|
* Scaffold CLI command
|
|
2887
3030
|
*/
|
|
2888
|
-
const scaffoldCommand = new Command("scaffold").description("Add features to existing projects");
|
|
3031
|
+
const scaffoldCommand = new commander.Command("scaffold").description("Add features to existing projects");
|
|
2889
3032
|
scaffoldCommand.command("list <projectPath>").description("List available scaffolding methods for a project").action(async (projectPath) => {
|
|
2890
3033
|
try {
|
|
2891
|
-
const absolutePath =
|
|
2892
|
-
if (!
|
|
3034
|
+
const absolutePath = node_path.default.resolve(projectPath);
|
|
3035
|
+
if (!fs_extra.existsSync(node_path.default.join(absolutePath, "project.json"))) {
|
|
2893
3036
|
messages.error(`No project.json found in ${absolutePath}`);
|
|
2894
3037
|
messages.hint("Make sure you are in a valid project directory");
|
|
2895
3038
|
process.exit(1);
|
|
2896
3039
|
}
|
|
3040
|
+
const templatesDir = await require_ScaffoldService.TemplatesManager.findTemplatesPath();
|
|
2897
3041
|
const fileSystemService = new FileSystemService();
|
|
2898
3042
|
const methods = (await new ScaffoldingMethodsService(fileSystemService, templatesDir).listScaffoldingMethods(absolutePath)).methods;
|
|
2899
3043
|
if (methods.length === 0) {
|
|
@@ -2914,8 +3058,8 @@ scaffoldCommand.command("list <projectPath>").description("List available scaffo
|
|
|
2914
3058
|
});
|
|
2915
3059
|
scaffoldCommand.command("add <featureName>").description("Add a feature to an existing project").option("-p, --project <path>", "Project path", process.cwd()).option("-v, --vars <json>", "JSON string containing variables for the feature").option("--verbose", "Enable verbose logging").action(async (featureName, options) => {
|
|
2916
3060
|
try {
|
|
2917
|
-
const projectPath =
|
|
2918
|
-
if (!
|
|
3061
|
+
const projectPath = node_path.default.resolve(options.project);
|
|
3062
|
+
if (!fs_extra.existsSync(node_path.default.join(projectPath, "project.json"))) {
|
|
2919
3063
|
messages.error(`No project.json found in ${projectPath}`);
|
|
2920
3064
|
messages.hint("Make sure you are in a valid project directory");
|
|
2921
3065
|
process.exit(1);
|
|
@@ -2928,6 +3072,7 @@ scaffoldCommand.command("add <featureName>").description("Add a feature to an ex
|
|
|
2928
3072
|
messages.hint("Example: --vars '{\"componentName\": \"UserProfile\", \"description\": \"User profile component\"}'");
|
|
2929
3073
|
process.exit(1);
|
|
2930
3074
|
}
|
|
3075
|
+
const templatesDir = await require_ScaffoldService.TemplatesManager.findTemplatesPath();
|
|
2931
3076
|
const fileSystemService = new FileSystemService();
|
|
2932
3077
|
const scaffoldingMethodsService = new ScaffoldingMethodsService(fileSystemService, templatesDir);
|
|
2933
3078
|
const methods = (await scaffoldingMethodsService.listScaffoldingMethods(projectPath)).methods;
|
|
@@ -2988,11 +3133,12 @@ scaffoldCommand.command("add <featureName>").description("Add a feature to an ex
|
|
|
2988
3133
|
});
|
|
2989
3134
|
scaffoldCommand.command("info <featureName>").description("Show detailed information about a scaffold method").option("-p, --project <path>", "Project path", process.cwd()).action(async (featureName, options) => {
|
|
2990
3135
|
try {
|
|
2991
|
-
const projectPath =
|
|
2992
|
-
if (!
|
|
3136
|
+
const projectPath = node_path.default.resolve(options.project);
|
|
3137
|
+
if (!fs_extra.existsSync(node_path.default.join(projectPath, "project.json"))) {
|
|
2993
3138
|
messages.error(`❌ No project.json found in ${projectPath}`);
|
|
2994
3139
|
process.exit(1);
|
|
2995
3140
|
}
|
|
3141
|
+
const templatesDir = await require_ScaffoldService.TemplatesManager.findTemplatesPath();
|
|
2996
3142
|
const fileSystemService = new FileSystemService();
|
|
2997
3143
|
const method = (await new ScaffoldingMethodsService(fileSystemService, templatesDir).listScaffoldingMethods(projectPath)).methods.find((m) => m.name === featureName);
|
|
2998
3144
|
if (!method) {
|
|
@@ -3024,7 +3170,7 @@ scaffoldCommand.command("info <featureName>").description("Show detailed informa
|
|
|
3024
3170
|
* Main entry point
|
|
3025
3171
|
*/
|
|
3026
3172
|
async function main() {
|
|
3027
|
-
const program = new Command();
|
|
3173
|
+
const program = new commander.Command();
|
|
3028
3174
|
program.name("scaffold-mcp").description("MCP server for scaffolding applications with boilerplate templates").version("1.0.0");
|
|
3029
3175
|
program.addCommand(mcpServeCommand);
|
|
3030
3176
|
program.addCommand(boilerplateCommand);
|
|
@@ -3035,5 +3181,4 @@ async function main() {
|
|
|
3035
3181
|
}
|
|
3036
3182
|
main();
|
|
3037
3183
|
|
|
3038
|
-
//#endregion
|
|
3039
|
-
export { };
|
|
3184
|
+
//#endregion
|