@agiflowai/scaffold-mcp 0.3.1 → 0.3.3
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/dist/{ScaffoldConfigLoader-CnVkzUxL.js → ScaffoldConfigLoader-BhrrsLya.js} +1 -1
- package/dist/{ScaffoldService-B8-dPa7L.js → ScaffoldService-B5ZpIjsn.js} +8 -7
- package/dist/ScaffoldService-Dp9yhqVI.js +4 -0
- package/dist/TemplateService-lGQxhofk.js +4 -0
- package/dist/{TemplateService-DvKjDjQE.js → TemplateService-wsvfwvRN.js} +17 -2
- package/dist/{VariableReplacementService-_GgLG4Im.js → VariableReplacementService-C0BdOUm6.js} +2 -1
- package/dist/{VariableReplacementService-DJqXiBC2.js → VariableReplacementService-UjRQY5JS.js} +4 -3
- package/dist/index.js +340 -265
- package/dist/logger-qztMS7ET.js +32 -0
- package/package.json +5 -3
- package/dist/ScaffoldService-BXKXXg4M.js +0 -3
- package/dist/TemplateService-B0ns4TR_.js +0 -3
- /package/dist/{ScaffoldConfigLoader-yDhzLQpC.js → ScaffoldConfigLoader-CvIJEFcI.js} +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const require_chunk = require('./chunk-nOFOJqeH.js');
|
|
2
|
+
const require_logger = require('./logger-qztMS7ET.js');
|
|
2
3
|
let node_path = require("node:path");
|
|
3
4
|
node_path = require_chunk.__toESM(node_path);
|
|
4
5
|
let fs_extra = require("fs-extra");
|
|
@@ -65,7 +66,7 @@ var ScaffoldProcessingService = class {
|
|
|
65
66
|
try {
|
|
66
67
|
items = await this.fileSystem.readdir(dirPath);
|
|
67
68
|
} catch (error) {
|
|
68
|
-
|
|
69
|
+
require_logger.log.warn(`Cannot read directory ${dirPath}: ${error}`);
|
|
69
70
|
return;
|
|
70
71
|
}
|
|
71
72
|
for (const item of items) {
|
|
@@ -76,7 +77,7 @@ var ScaffoldProcessingService = class {
|
|
|
76
77
|
if (stat.isDirectory()) await this.trackCreatedFilesRecursive(itemPath, createdFiles);
|
|
77
78
|
else if (stat.isFile()) createdFiles.push(itemPath);
|
|
78
79
|
} catch (error) {
|
|
79
|
-
|
|
80
|
+
require_logger.log.warn(`Cannot stat ${itemPath}: ${error}`);
|
|
80
81
|
}
|
|
81
82
|
}
|
|
82
83
|
}
|
|
@@ -88,7 +89,7 @@ var ScaffoldProcessingService = class {
|
|
|
88
89
|
try {
|
|
89
90
|
items = await this.fileSystem.readdir(dirPath);
|
|
90
91
|
} catch (error) {
|
|
91
|
-
|
|
92
|
+
require_logger.log.warn(`Cannot read directory ${dirPath}: ${error}`);
|
|
92
93
|
return;
|
|
93
94
|
}
|
|
94
95
|
for (const item of items) {
|
|
@@ -99,7 +100,7 @@ var ScaffoldProcessingService = class {
|
|
|
99
100
|
if (stat.isDirectory()) await this.trackExistingFilesRecursive(itemPath, existingFiles);
|
|
100
101
|
else if (stat.isFile()) existingFiles.push(itemPath);
|
|
101
102
|
} catch (error) {
|
|
102
|
-
|
|
103
|
+
require_logger.log.warn(`Cannot stat ${itemPath}: ${error}`);
|
|
103
104
|
}
|
|
104
105
|
}
|
|
105
106
|
}
|
|
@@ -337,10 +338,10 @@ var ScaffoldService = class {
|
|
|
337
338
|
*/
|
|
338
339
|
async processScaffold(params) {
|
|
339
340
|
const { config, targetPath, templatePath, allVariables, scaffoldType } = params;
|
|
340
|
-
|
|
341
|
-
|
|
341
|
+
require_logger.log.debug("Config generator:", config.generator);
|
|
342
|
+
require_logger.log.debug("Config:", JSON.stringify(config, null, 2));
|
|
342
343
|
if (config.generator) {
|
|
343
|
-
|
|
344
|
+
require_logger.log.info("Using custom generator:", config.generator);
|
|
344
345
|
try {
|
|
345
346
|
const generator = (await import(node_path.default.join(templatePath, "generators", config.generator))).default;
|
|
346
347
|
if (typeof generator !== "function") return {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const require_chunk = require('./chunk-nOFOJqeH.js');
|
|
2
|
+
const require_logger = require('./logger-qztMS7ET.js');
|
|
2
3
|
let liquidjs = require("liquidjs");
|
|
3
4
|
liquidjs = require_chunk.__toESM(liquidjs);
|
|
4
5
|
|
|
@@ -11,6 +12,7 @@ var TemplateService = class {
|
|
|
11
12
|
strictVariables: false
|
|
12
13
|
});
|
|
13
14
|
this.setupCustomFilters();
|
|
15
|
+
require_logger.log.info("TemplateService initialized");
|
|
14
16
|
}
|
|
15
17
|
toPascalCase(str) {
|
|
16
18
|
const camelCase = str.replace(/[-_\s]+(.)?/g, (_, char) => char ? char.toUpperCase() : "");
|
|
@@ -48,12 +50,25 @@ var TemplateService = class {
|
|
|
48
50
|
else if (str.endsWith("s") && !str.endsWith("ss")) return str.slice(0, -1);
|
|
49
51
|
else return str;
|
|
50
52
|
});
|
|
53
|
+
this.liquid.registerFilter("strip", (str) => {
|
|
54
|
+
return str.trim();
|
|
55
|
+
});
|
|
51
56
|
}
|
|
52
57
|
renderString(template, variables) {
|
|
53
58
|
try {
|
|
54
|
-
|
|
59
|
+
require_logger.log.debug("Rendering template", {
|
|
60
|
+
variables,
|
|
61
|
+
templatePreview: template.substring(0, 100)
|
|
62
|
+
});
|
|
63
|
+
const result = this.liquid.parseAndRenderSync(template, variables);
|
|
64
|
+
require_logger.log.debug("Rendered template", { resultPreview: result.substring(0, 100) });
|
|
65
|
+
return result;
|
|
55
66
|
} catch (error) {
|
|
56
|
-
|
|
67
|
+
require_logger.log.error("LiquidJS rendering error", {
|
|
68
|
+
error: error instanceof Error ? error.message : String(error),
|
|
69
|
+
templatePreview: template.substring(0, 200),
|
|
70
|
+
variables
|
|
71
|
+
});
|
|
57
72
|
return template;
|
|
58
73
|
}
|
|
59
74
|
}
|
package/dist/{VariableReplacementService-_GgLG4Im.js → VariableReplacementService-C0BdOUm6.js}
RENAMED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
require('./logger-qztMS7ET.js');
|
|
2
|
+
const require_VariableReplacementService = require('./VariableReplacementService-UjRQY5JS.js');
|
|
2
3
|
|
|
3
4
|
exports.VariableReplacementService = require_VariableReplacementService.VariableReplacementService;
|
package/dist/{VariableReplacementService-DJqXiBC2.js → VariableReplacementService-UjRQY5JS.js}
RENAMED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const require_chunk = require('./chunk-nOFOJqeH.js');
|
|
2
|
+
const require_logger = require('./logger-qztMS7ET.js');
|
|
2
3
|
let node_path = require("node:path");
|
|
3
4
|
node_path = require_chunk.__toESM(node_path);
|
|
4
5
|
|
|
@@ -32,7 +33,7 @@ var VariableReplacementService = class {
|
|
|
32
33
|
try {
|
|
33
34
|
items = await this.fileSystem.readdir(dirPath);
|
|
34
35
|
} catch (error) {
|
|
35
|
-
|
|
36
|
+
require_logger.log.warn(`Skipping directory ${dirPath}: ${error}`);
|
|
36
37
|
return;
|
|
37
38
|
}
|
|
38
39
|
for (const item of items) {
|
|
@@ -43,7 +44,7 @@ var VariableReplacementService = class {
|
|
|
43
44
|
if (stat.isDirectory()) await this.processFilesForVariableReplacement(itemPath, variables);
|
|
44
45
|
else if (stat.isFile()) await this.replaceVariablesInFile(itemPath, variables);
|
|
45
46
|
} catch (error) {
|
|
46
|
-
|
|
47
|
+
require_logger.log.warn(`Skipping item ${itemPath}: ${error}`);
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
}
|
|
@@ -54,7 +55,7 @@ var VariableReplacementService = class {
|
|
|
54
55
|
const renderedContent = this.templateService.renderString(content, variables);
|
|
55
56
|
await this.fileSystem.writeFile(filePath, renderedContent, "utf8");
|
|
56
57
|
} catch (error) {
|
|
57
|
-
|
|
58
|
+
require_logger.log.warn(`Skipping file ${filePath}: ${error}`);
|
|
58
59
|
}
|
|
59
60
|
}
|
|
60
61
|
isBinaryFile(filePath) {
|
package/dist/index.js
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
const require_chunk = require('./chunk-nOFOJqeH.js');
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
3
|
+
const require_logger = require('./logger-qztMS7ET.js');
|
|
4
|
+
const require_ScaffoldConfigLoader = require('./ScaffoldConfigLoader-CvIJEFcI.js');
|
|
5
|
+
const require_ScaffoldService = require('./ScaffoldService-B5ZpIjsn.js');
|
|
6
|
+
const require_TemplateService = require('./TemplateService-wsvfwvRN.js');
|
|
7
|
+
const require_VariableReplacementService = require('./VariableReplacementService-UjRQY5JS.js');
|
|
7
8
|
let commander = require("commander");
|
|
8
9
|
commander = require_chunk.__toESM(commander);
|
|
9
10
|
let node_path = require("node:path");
|
|
10
11
|
node_path = require_chunk.__toESM(node_path);
|
|
11
12
|
let fs_extra = require("fs-extra");
|
|
12
13
|
fs_extra = require_chunk.__toESM(fs_extra);
|
|
13
|
-
let chalk = require("chalk");
|
|
14
|
-
chalk = require_chunk.__toESM(chalk);
|
|
15
14
|
let node_child_process = require("node:child_process");
|
|
16
15
|
node_child_process = require_chunk.__toESM(node_child_process);
|
|
17
16
|
let node_util = require("node:util");
|
|
18
17
|
node_util = require_chunk.__toESM(node_util);
|
|
18
|
+
let chalk = require("chalk");
|
|
19
|
+
chalk = require_chunk.__toESM(chalk);
|
|
19
20
|
let __composio_json_schema_to_zod = require("@composio/json-schema-to-zod");
|
|
20
21
|
__composio_json_schema_to_zod = require_chunk.__toESM(__composio_json_schema_to_zod);
|
|
21
22
|
let js_yaml = require("js-yaml");
|
|
@@ -37,11 +38,95 @@ __modelcontextprotocol_sdk_server_sse_js = require_chunk.__toESM(__modelcontextp
|
|
|
37
38
|
let __modelcontextprotocol_sdk_server_stdio_js = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
38
39
|
__modelcontextprotocol_sdk_server_stdio_js = require_chunk.__toESM(__modelcontextprotocol_sdk_server_stdio_js);
|
|
39
40
|
|
|
40
|
-
//#region src/utils/
|
|
41
|
+
//#region src/utils/git.ts
|
|
42
|
+
const execAsync = (0, node_util.promisify)(node_child_process.exec);
|
|
43
|
+
/**
|
|
44
|
+
* Parse GitHub URL to detect if it's a subdirectory
|
|
45
|
+
* Supports formats:
|
|
46
|
+
* - https://github.com/user/repo
|
|
47
|
+
* - https://github.com/user/repo/tree/branch/path/to/dir
|
|
48
|
+
* - https://github.com/user/repo/tree/main/path/to/dir
|
|
49
|
+
*/
|
|
50
|
+
function parseGitHubUrl(url) {
|
|
51
|
+
const treeMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)\/(.+)$/);
|
|
52
|
+
const blobMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/blob\/([^/]+)\/(.+)$/);
|
|
53
|
+
const rootMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/);
|
|
54
|
+
if (treeMatch || blobMatch) {
|
|
55
|
+
const match = treeMatch || blobMatch;
|
|
56
|
+
return {
|
|
57
|
+
owner: match[1],
|
|
58
|
+
repo: match[2],
|
|
59
|
+
repoUrl: `https://github.com/${match[1]}/${match[2]}.git`,
|
|
60
|
+
branch: match[3],
|
|
61
|
+
subdirectory: match[4],
|
|
62
|
+
isSubdirectory: true
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (rootMatch) return {
|
|
66
|
+
owner: rootMatch[1],
|
|
67
|
+
repo: rootMatch[2],
|
|
68
|
+
repoUrl: `https://github.com/${rootMatch[1]}/${rootMatch[2]}.git`,
|
|
69
|
+
isSubdirectory: false
|
|
70
|
+
};
|
|
71
|
+
return {
|
|
72
|
+
repoUrl: url,
|
|
73
|
+
isSubdirectory: false
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Clone a subdirectory from a git repository using sparse checkout
|
|
78
|
+
*/
|
|
79
|
+
async function cloneSubdirectory(repoUrl, branch, subdirectory, targetFolder) {
|
|
80
|
+
const tempFolder = `${targetFolder}.tmp`;
|
|
81
|
+
try {
|
|
82
|
+
await execAsync(`git init "${tempFolder}"`);
|
|
83
|
+
await execAsync(`git -C "${tempFolder}" remote add origin ${repoUrl}`);
|
|
84
|
+
await execAsync(`git -C "${tempFolder}" config core.sparseCheckout true`);
|
|
85
|
+
const sparseCheckoutFile = node_path.default.join(tempFolder, ".git", "info", "sparse-checkout");
|
|
86
|
+
await fs_extra.writeFile(sparseCheckoutFile, `${subdirectory}\n`);
|
|
87
|
+
await execAsync(`git -C "${tempFolder}" pull --depth=1 origin ${branch}`);
|
|
88
|
+
const sourceDir = node_path.default.join(tempFolder, subdirectory);
|
|
89
|
+
if (!await fs_extra.pathExists(sourceDir)) throw new Error(`Subdirectory '${subdirectory}' not found in repository at branch '${branch}'`);
|
|
90
|
+
await fs_extra.move(sourceDir, targetFolder);
|
|
91
|
+
await fs_extra.remove(tempFolder);
|
|
92
|
+
} catch (error) {
|
|
93
|
+
if (await fs_extra.pathExists(tempFolder)) await fs_extra.remove(tempFolder);
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Clone entire repository
|
|
99
|
+
*/
|
|
100
|
+
async function cloneRepository(repoUrl, targetFolder) {
|
|
101
|
+
await execAsync(`git clone ${repoUrl} "${targetFolder}"`);
|
|
102
|
+
const gitFolder = node_path.default.join(targetFolder, ".git");
|
|
103
|
+
if (await fs_extra.pathExists(gitFolder)) await fs_extra.remove(gitFolder);
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Fetch directory listing from GitHub API
|
|
107
|
+
*/
|
|
108
|
+
async function fetchGitHubDirectoryContents(owner, repo, path$6, branch = "main") {
|
|
109
|
+
const url = `https://api.github.com/repos/${owner}/${repo}/contents/${path$6}?ref=${branch}`;
|
|
110
|
+
const response = await fetch(url, { headers: {
|
|
111
|
+
Accept: "application/vnd.github.v3+json",
|
|
112
|
+
"User-Agent": "scaffold-mcp"
|
|
113
|
+
} });
|
|
114
|
+
if (!response.ok) throw new Error(`Failed to fetch directory contents: ${response.statusText}`);
|
|
115
|
+
const data = await response.json();
|
|
116
|
+
if (!Array.isArray(data)) throw new Error("Expected directory but got file");
|
|
117
|
+
return data.map((item) => ({
|
|
118
|
+
name: item.name,
|
|
119
|
+
type: item.type,
|
|
120
|
+
path: item.path
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
//#endregion
|
|
125
|
+
//#region src/utils/print.ts
|
|
41
126
|
/**
|
|
42
127
|
* Themed console utilities for consistent CLI output
|
|
43
128
|
*/
|
|
44
|
-
const
|
|
129
|
+
const print = {
|
|
45
130
|
info: (message) => {
|
|
46
131
|
console.log(chalk.default.cyan(message));
|
|
47
132
|
},
|
|
@@ -103,22 +188,22 @@ const icons = {
|
|
|
103
188
|
*/
|
|
104
189
|
const messages = {
|
|
105
190
|
info: (message) => {
|
|
106
|
-
|
|
191
|
+
print.info(`${icons.info} ${message}`);
|
|
107
192
|
},
|
|
108
193
|
success: (message) => {
|
|
109
|
-
|
|
194
|
+
print.success(`${icons.check} ${message}`);
|
|
110
195
|
},
|
|
111
196
|
error: (message, error) => {
|
|
112
|
-
|
|
197
|
+
print.error(`${icons.cross} ${message}`, error);
|
|
113
198
|
},
|
|
114
199
|
warning: (message) => {
|
|
115
|
-
|
|
200
|
+
print.warning(`${icons.warning} ${message}`);
|
|
116
201
|
},
|
|
117
202
|
hint: (message) => {
|
|
118
|
-
|
|
203
|
+
print.warning(`${icons.bulb} ${message}`);
|
|
119
204
|
},
|
|
120
205
|
loading: (message) => {
|
|
121
|
-
|
|
206
|
+
print.info(`${icons.rocket} ${message}`);
|
|
122
207
|
}
|
|
123
208
|
};
|
|
124
209
|
/**
|
|
@@ -126,113 +211,29 @@ const messages = {
|
|
|
126
211
|
*/
|
|
127
212
|
const sections = {
|
|
128
213
|
header: (title) => {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
214
|
+
print.newline();
|
|
215
|
+
print.header(`${title}`);
|
|
216
|
+
print.newline();
|
|
132
217
|
},
|
|
133
218
|
list: (title, items) => {
|
|
134
|
-
|
|
135
|
-
items.forEach((item) =>
|
|
219
|
+
print.header(`\n${title}\n`);
|
|
220
|
+
items.forEach((item) => print.item(item));
|
|
136
221
|
},
|
|
137
222
|
nextSteps: (steps) => {
|
|
138
|
-
|
|
139
|
-
steps.forEach((step) =>
|
|
223
|
+
print.header(`\n${icons.clipboard} Next steps:`);
|
|
224
|
+
steps.forEach((step) => print.indent(step));
|
|
140
225
|
},
|
|
141
226
|
createdFiles: (files, maxShow = 10) => {
|
|
142
|
-
|
|
143
|
-
files.slice(0, maxShow).forEach((file) =>
|
|
144
|
-
if (files.length > maxShow)
|
|
227
|
+
print.header(`\n${icons.folder} Created files:`);
|
|
228
|
+
files.slice(0, maxShow).forEach((file) => print.item(file));
|
|
229
|
+
if (files.length > maxShow) print.indent(`... and ${files.length - maxShow} more files`);
|
|
145
230
|
},
|
|
146
231
|
warnings: (warnings) => {
|
|
147
|
-
|
|
148
|
-
warnings.forEach((warning) =>
|
|
232
|
+
print.warning(`\n${icons.warning} Warnings:`);
|
|
233
|
+
warnings.forEach((warning) => print.item(warning));
|
|
149
234
|
}
|
|
150
235
|
};
|
|
151
236
|
|
|
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
|
-
|
|
236
237
|
//#endregion
|
|
237
238
|
//#region src/cli/add.ts
|
|
238
239
|
/**
|
|
@@ -253,28 +254,28 @@ const addCommand = new commander.Command("add").description("Add a template to t
|
|
|
253
254
|
messages.error(`Template '${templateName}' already exists at ${targetFolder}`);
|
|
254
255
|
process.exit(1);
|
|
255
256
|
}
|
|
256
|
-
|
|
257
|
+
print.info(`${icons.download} Downloading template '${templateName}' from ${templateUrl}...`);
|
|
257
258
|
await fs_extra.ensureDir(node_path.default.dirname(targetFolder));
|
|
258
259
|
const parsedUrl = parseGitHubUrl(templateUrl);
|
|
259
260
|
try {
|
|
260
261
|
if (parsedUrl.isSubdirectory && parsedUrl.branch && parsedUrl.subdirectory) {
|
|
261
|
-
|
|
262
|
+
print.info(`${icons.folder} Detected subdirectory: ${parsedUrl.subdirectory} (branch: ${parsedUrl.branch})`);
|
|
262
263
|
await cloneSubdirectory(parsedUrl.repoUrl, parsedUrl.branch, parsedUrl.subdirectory, targetFolder);
|
|
263
264
|
} else await cloneRepository(parsedUrl.repoUrl, targetFolder);
|
|
264
265
|
messages.success(`Template '${templateName}' added successfully!`);
|
|
265
|
-
|
|
266
|
-
|
|
266
|
+
print.header(`\n${icons.folder} Template location:`);
|
|
267
|
+
print.indent(targetFolder);
|
|
267
268
|
const configFiles = [node_path.default.join(targetFolder, "boilerplate.yaml"), node_path.default.join(targetFolder, "scaffold.yaml")];
|
|
268
269
|
let hasConfig = false;
|
|
269
270
|
for (const configFile of configFiles) if (await fs_extra.pathExists(configFile)) {
|
|
270
|
-
|
|
271
|
-
|
|
271
|
+
print.header(`\n${icons.config} Configuration file found:`);
|
|
272
|
+
print.indent(node_path.default.basename(configFile));
|
|
272
273
|
hasConfig = true;
|
|
273
274
|
break;
|
|
274
275
|
}
|
|
275
276
|
if (!hasConfig) {
|
|
276
277
|
messages.warning("Warning: No configuration file found (boilerplate.yaml or scaffold.yaml)");
|
|
277
|
-
|
|
278
|
+
print.indent("You may need to create one manually.");
|
|
278
279
|
}
|
|
279
280
|
sections.nextSteps([`Review the template in ${targetFolder}`, `Test it with: scaffold-mcp ${templateType} list`]);
|
|
280
281
|
} catch (error) {
|
|
@@ -329,9 +330,7 @@ var BoilerplateService = class {
|
|
|
329
330
|
this.templatesPath = templatesPath;
|
|
330
331
|
this.templateService = new require_TemplateService.TemplateService();
|
|
331
332
|
const fileSystemService = new FileSystemService();
|
|
332
|
-
|
|
333
|
-
const variableReplacementService = new require_VariableReplacementService.VariableReplacementService(fileSystemService, this.templateService);
|
|
334
|
-
this.scaffoldService = new require_ScaffoldService.ScaffoldService(fileSystemService, scaffoldConfigLoader, variableReplacementService, templatesPath);
|
|
333
|
+
this.scaffoldService = new require_ScaffoldService.ScaffoldService(fileSystemService, new require_ScaffoldConfigLoader.ScaffoldConfigLoader(fileSystemService, this.templateService), new require_VariableReplacementService.VariableReplacementService(fileSystemService, this.templateService), templatesPath);
|
|
335
334
|
}
|
|
336
335
|
/**
|
|
337
336
|
* Scans all scaffold.yaml files and returns available boilerplates
|
|
@@ -346,7 +345,7 @@ var BoilerplateService = class {
|
|
|
346
345
|
const scaffoldConfig = js_yaml.load(scaffoldContent);
|
|
347
346
|
if (scaffoldConfig.boilerplate) for (const boilerplate of scaffoldConfig.boilerplate) {
|
|
348
347
|
if (!boilerplate.targetFolder) {
|
|
349
|
-
|
|
348
|
+
require_logger.log.warn(`Skipping boilerplate '${boilerplate.name}' in ${templatePath}: targetFolder is required in scaffold.yaml`);
|
|
350
349
|
continue;
|
|
351
350
|
}
|
|
352
351
|
boilerplates.push({
|
|
@@ -360,7 +359,7 @@ var BoilerplateService = class {
|
|
|
360
359
|
});
|
|
361
360
|
}
|
|
362
361
|
} catch (error) {
|
|
363
|
-
|
|
362
|
+
require_logger.log.warn(`Failed to load scaffold.yaml for ${templatePath}:`, error);
|
|
364
363
|
}
|
|
365
364
|
}
|
|
366
365
|
return { boilerplates };
|
|
@@ -379,10 +378,7 @@ var BoilerplateService = class {
|
|
|
379
378
|
if (hasPackageJson && hasScaffoldYaml) templateDirs.push(baseDir);
|
|
380
379
|
for (const item of items) {
|
|
381
380
|
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;
|
|
384
|
-
findTemplates(itemPath, newBaseDir);
|
|
385
|
-
}
|
|
381
|
+
if (fs_extra.statSync(itemPath).isDirectory() && !item.startsWith(".") && item !== "node_modules") findTemplates(itemPath, baseDir ? node_path.join(baseDir, item) : item);
|
|
386
382
|
}
|
|
387
383
|
};
|
|
388
384
|
findTemplates(this.templatesPath);
|
|
@@ -503,7 +499,7 @@ var BoilerplateService = class {
|
|
|
503
499
|
projectJson.sourceTemplate = sourceTemplate;
|
|
504
500
|
fs_extra.writeFileSync(projectJsonPath, `${JSON.stringify(projectJson, null, 2)}\n`, "utf8");
|
|
505
501
|
} catch (error) {
|
|
506
|
-
|
|
502
|
+
require_logger.log.warn(`Failed to update project.json with sourceTemplate: ${error}`);
|
|
507
503
|
}
|
|
508
504
|
}
|
|
509
505
|
};
|
|
@@ -516,20 +512,19 @@ var BoilerplateService = class {
|
|
|
516
512
|
const boilerplateCommand = new commander.Command("boilerplate").description("Manage boilerplate templates");
|
|
517
513
|
boilerplateCommand.command("list").description("List all available boilerplate templates").action(async () => {
|
|
518
514
|
try {
|
|
519
|
-
const
|
|
520
|
-
const { boilerplates } = await new BoilerplateService(templatesDir).listBoilerplates();
|
|
515
|
+
const { boilerplates } = await new BoilerplateService(await require_ScaffoldService.TemplatesManager.findTemplatesPath()).listBoilerplates();
|
|
521
516
|
if (boilerplates.length === 0) {
|
|
522
517
|
messages.warning("No boilerplate templates found.");
|
|
523
518
|
return;
|
|
524
519
|
}
|
|
525
|
-
|
|
520
|
+
print.header(`\n${icons.package} Available Boilerplate Templates:\n`);
|
|
526
521
|
for (const bp of boilerplates) {
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
522
|
+
print.highlight(` ${bp.name}`);
|
|
523
|
+
print.debug(` ${bp.description}`);
|
|
524
|
+
print.debug(` Target: ${bp.target_folder}`);
|
|
530
525
|
const required = typeof bp.variables_schema === "object" && bp.variables_schema !== null && "required" in bp.variables_schema ? bp.variables_schema.required : [];
|
|
531
|
-
if (required && required.length > 0)
|
|
532
|
-
|
|
526
|
+
if (required && required.length > 0) print.debug(` Required: ${required.join(", ")}`);
|
|
527
|
+
print.newline();
|
|
533
528
|
}
|
|
534
529
|
} catch (error) {
|
|
535
530
|
messages.error("Error listing boilerplates:", error);
|
|
@@ -538,8 +533,7 @@ boilerplateCommand.command("list").description("List all available boilerplate t
|
|
|
538
533
|
});
|
|
539
534
|
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) => {
|
|
540
535
|
try {
|
|
541
|
-
const
|
|
542
|
-
const boilerplateService = new BoilerplateService(templatesDir);
|
|
536
|
+
const boilerplateService = new BoilerplateService(await require_ScaffoldService.TemplatesManager.findTemplatesPath());
|
|
543
537
|
let variables = {};
|
|
544
538
|
if (options.vars) try {
|
|
545
539
|
variables = JSON.parse(options.vars);
|
|
@@ -552,7 +546,7 @@ boilerplateCommand.command("create <boilerplateName>").description("Create a new
|
|
|
552
546
|
if (!boilerplate) {
|
|
553
547
|
const { boilerplates } = await boilerplateService.listBoilerplates();
|
|
554
548
|
messages.error(`Boilerplate '${boilerplateName}' not found.`);
|
|
555
|
-
|
|
549
|
+
print.warning(`Available boilerplates: ${boilerplates.map((b) => b.name).join(", ")}`);
|
|
556
550
|
process.exit(1);
|
|
557
551
|
}
|
|
558
552
|
const required = typeof boilerplate.variables_schema === "object" && boilerplate.variables_schema !== null && "required" in boilerplate.variables_schema ? boilerplate.variables_schema.required : [];
|
|
@@ -564,12 +558,12 @@ boilerplateCommand.command("create <boilerplateName>").description("Create a new
|
|
|
564
558
|
for (const key of required) if (key === "appName" || key === "packageName") exampleVars[key] = "my-app";
|
|
565
559
|
else if (key === "description") exampleVars[key] = "My application description";
|
|
566
560
|
else exampleVars[key] = `<${key}>`;
|
|
567
|
-
|
|
561
|
+
print.debug(`Example: scaffold-mcp boilerplate create ${boilerplateName} --vars '${JSON.stringify(exampleVars)}'`);
|
|
568
562
|
process.exit(1);
|
|
569
563
|
}
|
|
570
564
|
if (options.verbose) {
|
|
571
|
-
|
|
572
|
-
|
|
565
|
+
print.info(`${icons.wrench} Boilerplate: ${boilerplateName}`);
|
|
566
|
+
print.info(`${icons.chart} Variables: ${JSON.stringify(variables, null, 2)}`);
|
|
573
567
|
}
|
|
574
568
|
messages.loading(`Creating project from boilerplate '${boilerplateName}'...`);
|
|
575
569
|
const result = await boilerplateService.useBoilerplate({
|
|
@@ -578,7 +572,7 @@ boilerplateCommand.command("create <boilerplateName>").description("Create a new
|
|
|
578
572
|
});
|
|
579
573
|
if (result.success) {
|
|
580
574
|
messages.success("Project created successfully!");
|
|
581
|
-
|
|
575
|
+
print.info(result.message);
|
|
582
576
|
if (result.createdFiles && result.createdFiles.length > 0) sections.createdFiles(result.createdFiles);
|
|
583
577
|
const projectName = variables.appName || variables.packageName;
|
|
584
578
|
if (projectName) sections.nextSteps([
|
|
@@ -598,17 +592,16 @@ boilerplateCommand.command("create <boilerplateName>").description("Create a new
|
|
|
598
592
|
});
|
|
599
593
|
boilerplateCommand.command("info <boilerplateName>").description("Show detailed information about a boilerplate template").action(async (boilerplateName) => {
|
|
600
594
|
try {
|
|
601
|
-
const
|
|
602
|
-
const bp = await new BoilerplateService(templatesDir).getBoilerplate(boilerplateName);
|
|
595
|
+
const bp = await new BoilerplateService(await require_ScaffoldService.TemplatesManager.findTemplatesPath()).getBoilerplate(boilerplateName);
|
|
603
596
|
if (!bp) {
|
|
604
597
|
messages.error(`Boilerplate '${boilerplateName}' not found.`);
|
|
605
598
|
process.exit(1);
|
|
606
599
|
}
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
600
|
+
print.header(`\n${icons.package} Boilerplate: ${bp.name}\n`);
|
|
601
|
+
print.debug(`Description: ${bp.description}`);
|
|
602
|
+
print.debug(`Template Path: ${bp.template_path}`);
|
|
603
|
+
print.debug(`Target Folder: ${bp.target_folder}`);
|
|
604
|
+
print.header(`\n${icons.config} Variables Schema:`);
|
|
612
605
|
console.log(JSON.stringify(bp.variables_schema, null, 2));
|
|
613
606
|
if (bp.includes && bp.includes.length > 0) sections.list(`${icons.folder} Included Files:`, bp.includes);
|
|
614
607
|
} catch (error) {
|
|
@@ -643,25 +636,24 @@ const DEFAULT_TEMPLATE_REPO = {
|
|
|
643
636
|
*/
|
|
644
637
|
async function downloadTemplates(templatesPath) {
|
|
645
638
|
try {
|
|
646
|
-
|
|
639
|
+
print.info(`${icons.download} Fetching templates from ${DEFAULT_TEMPLATE_REPO.owner}/${DEFAULT_TEMPLATE_REPO.repo}...`);
|
|
647
640
|
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
641
|
if (templateDirs.length === 0) {
|
|
649
642
|
messages.warning("No templates found in repository");
|
|
650
643
|
return;
|
|
651
644
|
}
|
|
652
|
-
|
|
645
|
+
print.info(`${icons.folder} Found ${templateDirs.length} template(s)`);
|
|
653
646
|
for (const template of templateDirs) {
|
|
654
647
|
const targetFolder = node_path.default.join(templatesPath, template.name);
|
|
655
648
|
if (await fs_extra.pathExists(targetFolder)) {
|
|
656
|
-
|
|
649
|
+
print.info(`${icons.skip} Skipping ${template.name} (already exists)`);
|
|
657
650
|
continue;
|
|
658
651
|
}
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
logger.success(`${icons.check} Downloaded ${template.name}`);
|
|
652
|
+
print.info(`${icons.download} Downloading ${template.name}...`);
|
|
653
|
+
await cloneSubdirectory(`https://github.com/${DEFAULT_TEMPLATE_REPO.owner}/${DEFAULT_TEMPLATE_REPO.repo}.git`, DEFAULT_TEMPLATE_REPO.branch, template.path, targetFolder);
|
|
654
|
+
print.success(`${icons.check} Downloaded ${template.name}`);
|
|
663
655
|
}
|
|
664
|
-
|
|
656
|
+
print.success(`\n${icons.check} All templates downloaded successfully!`);
|
|
665
657
|
} catch (error) {
|
|
666
658
|
throw new Error(`Failed to download templates: ${error.message}`);
|
|
667
659
|
}
|
|
@@ -673,7 +665,7 @@ const initCommand = new commander.Command("init").description("Initialize templa
|
|
|
673
665
|
try {
|
|
674
666
|
const workspaceRoot = await findWorkspaceRoot();
|
|
675
667
|
const templatesPath = options.path ? node_path.default.join(workspaceRoot, options.path) : node_path.default.join(workspaceRoot, "templates");
|
|
676
|
-
|
|
668
|
+
print.info(`${icons.rocket} Initializing templates folder at: ${templatesPath}`);
|
|
677
669
|
await fs_extra.ensureDir(templatesPath);
|
|
678
670
|
await fs_extra.writeFile(node_path.default.join(templatesPath, "README.md"), `# Templates
|
|
679
671
|
|
|
@@ -709,11 +701,11 @@ Template files use Liquid syntax for variable placeholders: \`{{ variableName }}
|
|
|
709
701
|
|
|
710
702
|
See existing templates for examples and documentation for more details.
|
|
711
703
|
`);
|
|
712
|
-
|
|
704
|
+
print.success(`${icons.check} Templates folder created!`);
|
|
713
705
|
if (options.download !== false) await downloadTemplates(templatesPath);
|
|
714
|
-
else
|
|
715
|
-
|
|
716
|
-
|
|
706
|
+
else print.info(`${icons.skip} Skipping template download (use --download to enable)`);
|
|
707
|
+
print.header(`\n${icons.folder} Templates location:`);
|
|
708
|
+
print.indent(templatesPath);
|
|
717
709
|
const nextSteps = [];
|
|
718
710
|
if (options.download === false) {
|
|
719
711
|
nextSteps.push(`Download templates: scaffold-mcp init --download`);
|
|
@@ -1025,12 +1017,27 @@ Use the \`use-boilerplate\` tool with:
|
|
|
1025
1017
|
- The tool will create the project in the appropriate directory automatically
|
|
1026
1018
|
- After creation, inform the user where the project was created
|
|
1027
1019
|
|
|
1020
|
+
## Step 4: Review and Add Features (If Needed)
|
|
1021
|
+
After the boilerplate is created, **consider if additional features are needed**:
|
|
1022
|
+
1. **READ** the generated project structure to understand what was created
|
|
1023
|
+
2. **REVIEW** the user's request to see if they asked for specific features (e.g., "with tool for X", "with prompt for Y")
|
|
1024
|
+
3. **If features are needed**:
|
|
1025
|
+
- Use \`list-scaffolding-methods\` with the new project path
|
|
1026
|
+
- Use \`use-scaffold-method\` to add tools, services, prompts, etc.
|
|
1027
|
+
- **IMPLEMENT** the actual logic in the scaffolded feature files
|
|
1028
|
+
- **REGISTER** the features in \`src/server/index.ts\`
|
|
1029
|
+
4. **Install dependencies**: Remind user to run \`pnpm install\`
|
|
1030
|
+
5. **Report** the complete setup including any features added
|
|
1031
|
+
|
|
1028
1032
|
## Example Workflow:
|
|
1029
1033
|
1. Call \`list-boilerplates\` → See available templates
|
|
1030
1034
|
2. Ask user which template to use (or infer from request)
|
|
1031
1035
|
3. Collect required variables based on schema
|
|
1032
1036
|
4. Call \`use-boilerplate\` with boilerplateName and variables
|
|
1033
|
-
5.
|
|
1037
|
+
5. **Review if user requested specific features (tools, prompts, etc.)**
|
|
1038
|
+
6. **If features needed**: Add them using \`list-scaffolding-methods\` and \`use-scaffold-method\`
|
|
1039
|
+
7. **READ and IMPLEMENT** the scaffolded feature files with actual logic
|
|
1040
|
+
8. Report success and next steps to the user`
|
|
1034
1041
|
}
|
|
1035
1042
|
}];
|
|
1036
1043
|
}
|
|
@@ -1140,13 +1147,29 @@ Use the \`use-scaffold-method\` tool with:
|
|
|
1140
1147
|
- The tool will create files in the appropriate locations automatically
|
|
1141
1148
|
- After creation, inform the user what files were created
|
|
1142
1149
|
|
|
1150
|
+
## Step 5: Review and Implement Generated Files
|
|
1151
|
+
After scaffolding completes, **you MUST**:
|
|
1152
|
+
1. **READ** all generated files to understand their structure
|
|
1153
|
+
2. **IMPLEMENT** the actual business logic:
|
|
1154
|
+
- Replace TODO comments with real code
|
|
1155
|
+
- Replace template placeholders with actual implementation
|
|
1156
|
+
- Add the specific functionality described in the user's request
|
|
1157
|
+
3. **REGISTER** the feature in appropriate files:
|
|
1158
|
+
- Import and register tools in \`src/server/index.ts\`
|
|
1159
|
+
- Export new modules from \`index.ts\` files
|
|
1160
|
+
- Update any necessary configuration files
|
|
1161
|
+
4. **TEST** to ensure the implementation works correctly
|
|
1162
|
+
5. **DO NOT SKIP** this step - scaffolded files are templates that need actual code
|
|
1163
|
+
|
|
1143
1164
|
## Example Workflow:
|
|
1144
1165
|
1. Identify project path (provided or ask user)
|
|
1145
1166
|
2. Call \`list-scaffolding-methods\` → See available features for this project
|
|
1146
1167
|
3. Ask user which feature to add (or infer from request)
|
|
1147
1168
|
4. Collect required variables based on schema
|
|
1148
1169
|
5. Call \`use-scaffold-method\` with projectPath, scaffold_feature_name, and variables
|
|
1149
|
-
6.
|
|
1170
|
+
6. **READ the generated files and IMPLEMENT the actual logic**
|
|
1171
|
+
7. **REGISTER the feature in server/index.ts and other config files**
|
|
1172
|
+
8. Report success and list created files with implementation details`
|
|
1150
1173
|
}
|
|
1151
1174
|
}];
|
|
1152
1175
|
}
|
|
@@ -1233,24 +1256,23 @@ var BoilerplateGeneratorService = class {
|
|
|
1233
1256
|
message: `Boilerplate '${boilerplateName}' already exists in ${scaffoldYamlPath}`
|
|
1234
1257
|
};
|
|
1235
1258
|
const requiredVars = variables.filter((v) => v.required).map((v) => v.name);
|
|
1236
|
-
const variablesSchema = {
|
|
1237
|
-
type: "object",
|
|
1238
|
-
properties: variables.reduce((acc, v) => {
|
|
1239
|
-
acc[v.name] = {
|
|
1240
|
-
type: v.type,
|
|
1241
|
-
description: v.description
|
|
1242
|
-
};
|
|
1243
|
-
if (v.default !== void 0) acc[v.name].default = v.default;
|
|
1244
|
-
return acc;
|
|
1245
|
-
}, {}),
|
|
1246
|
-
required: requiredVars,
|
|
1247
|
-
additionalProperties: false
|
|
1248
|
-
};
|
|
1249
1259
|
const boilerplateDefinition = {
|
|
1250
1260
|
name: boilerplateName,
|
|
1251
1261
|
targetFolder,
|
|
1252
1262
|
description,
|
|
1253
|
-
variables_schema:
|
|
1263
|
+
variables_schema: {
|
|
1264
|
+
type: "object",
|
|
1265
|
+
properties: variables.reduce((acc, v) => {
|
|
1266
|
+
acc[v.name] = {
|
|
1267
|
+
type: v.type,
|
|
1268
|
+
description: v.description
|
|
1269
|
+
};
|
|
1270
|
+
if (v.default !== void 0) acc[v.name].default = v.default;
|
|
1271
|
+
return acc;
|
|
1272
|
+
}, {}),
|
|
1273
|
+
required: requiredVars,
|
|
1274
|
+
additionalProperties: false
|
|
1275
|
+
},
|
|
1254
1276
|
includes: includes.length > 0 ? includes : []
|
|
1255
1277
|
};
|
|
1256
1278
|
if (instruction) boilerplateDefinition.instruction = instruction;
|
|
@@ -1340,6 +1362,11 @@ This tool:
|
|
|
1340
1362
|
- Validates that the template directory exists
|
|
1341
1363
|
- Works for both boilerplate includes and feature scaffold includes
|
|
1342
1364
|
|
|
1365
|
+
IMPORTANT - Always add header comments:
|
|
1366
|
+
- For code files (*.ts, *.tsx, *.js, *.jsx), ALWAYS include a header parameter with design patterns, coding standards, and things to avoid
|
|
1367
|
+
- Headers help AI understand and follow established patterns when working with generated code
|
|
1368
|
+
- Use the header parameter to document the architectural decisions and best practices
|
|
1369
|
+
|
|
1343
1370
|
Use this after generate-boilerplate or generate-feature-scaffold to create the actual template files referenced in the includes array.`,
|
|
1344
1371
|
inputSchema: {
|
|
1345
1372
|
type: "object",
|
|
@@ -1354,7 +1381,55 @@ Use this after generate-boilerplate or generate-feature-scaffold to create the a
|
|
|
1354
1381
|
},
|
|
1355
1382
|
content: {
|
|
1356
1383
|
type: "string",
|
|
1357
|
-
description: `Content of the template file
|
|
1384
|
+
description: `Content of the template file using Liquid template syntax.
|
|
1385
|
+
|
|
1386
|
+
LIQUID SYNTAX:
|
|
1387
|
+
- Variables: {{ variableName }} - Replaced with actual values
|
|
1388
|
+
- Conditionals: {% if condition %}...{% endif %} - Conditional rendering
|
|
1389
|
+
- Else: {% if condition %}...{% else %}...{% endif %}
|
|
1390
|
+
- Elsif: {% if condition %}...{% elsif other %}...{% endif %}
|
|
1391
|
+
- Equality: {% if var == 'value' %}...{% endif %}
|
|
1392
|
+
|
|
1393
|
+
AVAILABLE FILTERS:
|
|
1394
|
+
You can transform variables using these filters with the pipe (|) syntax:
|
|
1395
|
+
|
|
1396
|
+
Case Conversion:
|
|
1397
|
+
- {{ name | camelCase }} - Convert to camelCase (myVariableName)
|
|
1398
|
+
- {{ name | pascalCase }} - Convert to PascalCase (MyVariableName)
|
|
1399
|
+
- {{ name | titleCase }} - Convert to TitleCase (alias for pascalCase)
|
|
1400
|
+
- {{ name | kebabCase }} - Convert to kebab-case (my-variable-name)
|
|
1401
|
+
- {{ name | snakeCase }} - Convert to snake_case (my_variable_name)
|
|
1402
|
+
- {{ name | upperCase }} - Convert to UPPER_CASE (MY_VARIABLE_NAME)
|
|
1403
|
+
- {{ name | lower }} or {{ name | downcase }} - Convert to lowercase
|
|
1404
|
+
- {{ name | upper }} or {{ name | upcase }} - Convert to UPPERCASE
|
|
1405
|
+
|
|
1406
|
+
String Manipulation:
|
|
1407
|
+
- {{ name | strip }} - Remove leading/trailing whitespace
|
|
1408
|
+
- {{ name | replace: "old", "new" }} - Replace text (e.g., replace: "Tool", "")
|
|
1409
|
+
- {{ name | pluralize }} - Add plural suffix (simple: book → books, class → classes)
|
|
1410
|
+
- {{ name | singularize }} - Remove plural suffix (simple: books → book)
|
|
1411
|
+
|
|
1412
|
+
Chaining Filters:
|
|
1413
|
+
- {{ toolName | downcase | replace: "tool", "" | strip }} - Combine multiple filters
|
|
1414
|
+
|
|
1415
|
+
Example with variables and conditionals:
|
|
1416
|
+
{
|
|
1417
|
+
"name": "{{ packageName }}",{% if withFeature %}
|
|
1418
|
+
"feature": "enabled",{% endif %}
|
|
1419
|
+
"dependencies": {
|
|
1420
|
+
"core": "1.0.0"{% if withOptional %},
|
|
1421
|
+
"optional": "2.0.0"{% endif %}
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
|
|
1425
|
+
Example with filters:
|
|
1426
|
+
export class {{ serviceName | pascalCase }} {
|
|
1427
|
+
private {{ serviceName | camelCase }}: string;
|
|
1428
|
+
|
|
1429
|
+
constructor() {
|
|
1430
|
+
this.{{ serviceName | camelCase }} = "{{ serviceName | kebabCase }}";
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1358
1433
|
|
|
1359
1434
|
IMPORTANT - Keep content minimal and business-agnostic:
|
|
1360
1435
|
- Focus on structure and patterns, not specific business logic
|
|
@@ -1733,23 +1808,22 @@ var ScaffoldGeneratorService = class {
|
|
|
1733
1808
|
message: `Feature '${featureName}' already exists in ${scaffoldYamlPath}`
|
|
1734
1809
|
};
|
|
1735
1810
|
const requiredVars = variables.filter((v) => v.required).map((v) => v.name);
|
|
1736
|
-
const variablesSchema = {
|
|
1737
|
-
type: "object",
|
|
1738
|
-
properties: variables.reduce((acc, v) => {
|
|
1739
|
-
acc[v.name] = {
|
|
1740
|
-
type: v.type,
|
|
1741
|
-
description: v.description
|
|
1742
|
-
};
|
|
1743
|
-
if (v.default !== void 0) acc[v.name].default = v.default;
|
|
1744
|
-
return acc;
|
|
1745
|
-
}, {}),
|
|
1746
|
-
required: requiredVars,
|
|
1747
|
-
additionalProperties: false
|
|
1748
|
-
};
|
|
1749
1811
|
const featureDefinition = {
|
|
1750
1812
|
name: featureName,
|
|
1751
1813
|
description,
|
|
1752
|
-
variables_schema:
|
|
1814
|
+
variables_schema: {
|
|
1815
|
+
type: "object",
|
|
1816
|
+
properties: variables.reduce((acc, v) => {
|
|
1817
|
+
acc[v.name] = {
|
|
1818
|
+
type: v.type,
|
|
1819
|
+
description: v.description
|
|
1820
|
+
};
|
|
1821
|
+
if (v.default !== void 0) acc[v.name].default = v.default;
|
|
1822
|
+
return acc;
|
|
1823
|
+
}, {}),
|
|
1824
|
+
required: requiredVars,
|
|
1825
|
+
additionalProperties: false
|
|
1826
|
+
},
|
|
1753
1827
|
includes: includes.length > 0 ? includes : []
|
|
1754
1828
|
};
|
|
1755
1829
|
if (instruction) featureDefinition.instruction = instruction;
|
|
@@ -2101,7 +2175,7 @@ var ScaffoldingMethodsService = class {
|
|
|
2101
2175
|
for (const boilerplate of architectConfig.boilerplate) if (boilerplate.name?.includes(sourceTemplate)) return templateDir;
|
|
2102
2176
|
}
|
|
2103
2177
|
} catch (error) {
|
|
2104
|
-
|
|
2178
|
+
require_logger.log.warn(`Failed to read scaffold.yaml at ${scaffoldYamlPath}:`, error);
|
|
2105
2179
|
}
|
|
2106
2180
|
}
|
|
2107
2181
|
return null;
|
|
@@ -2134,11 +2208,11 @@ var ScaffoldingMethodsService = class {
|
|
|
2134
2208
|
}
|
|
2135
2209
|
}
|
|
2136
2210
|
} catch (error) {
|
|
2137
|
-
|
|
2211
|
+
require_logger.log.warn(`Failed to read subdirectories in ${itemPath}:`, error);
|
|
2138
2212
|
}
|
|
2139
2213
|
}
|
|
2140
2214
|
} catch (error) {
|
|
2141
|
-
|
|
2215
|
+
require_logger.log.warn(`Failed to read templates root directory ${this.templatesRootPath}:`, error);
|
|
2142
2216
|
}
|
|
2143
2217
|
return templateDirs;
|
|
2144
2218
|
}
|
|
@@ -2150,10 +2224,10 @@ var ScaffoldingMethodsService = class {
|
|
|
2150
2224
|
const availableMethods = scaffoldingMethods.methods.map((m) => m.name).join(", ");
|
|
2151
2225
|
throw new Error(`Scaffold method '${scaffold_feature_name}' not found. Available methods: ${availableMethods}`);
|
|
2152
2226
|
}
|
|
2153
|
-
const ScaffoldService$1 = (await Promise.resolve().then(() => require("./ScaffoldService-
|
|
2154
|
-
const ScaffoldConfigLoader$1 = (await Promise.resolve().then(() => require("./ScaffoldConfigLoader-
|
|
2155
|
-
const VariableReplacementService$1 = (await Promise.resolve().then(() => require("./VariableReplacementService-
|
|
2156
|
-
const TemplateService$1 = (await Promise.resolve().then(() => require("./TemplateService-
|
|
2227
|
+
const ScaffoldService$1 = (await Promise.resolve().then(() => require("./ScaffoldService-Dp9yhqVI.js"))).ScaffoldService;
|
|
2228
|
+
const ScaffoldConfigLoader$1 = (await Promise.resolve().then(() => require("./ScaffoldConfigLoader-BhrrsLya.js"))).ScaffoldConfigLoader;
|
|
2229
|
+
const VariableReplacementService$1 = (await Promise.resolve().then(() => require("./VariableReplacementService-C0BdOUm6.js"))).VariableReplacementService;
|
|
2230
|
+
const TemplateService$1 = (await Promise.resolve().then(() => require("./TemplateService-lGQxhofk.js"))).TemplateService;
|
|
2157
2231
|
const templateService = new TemplateService$1();
|
|
2158
2232
|
const scaffoldConfigLoader = new ScaffoldConfigLoader$1(this.fileSystem, templateService);
|
|
2159
2233
|
const variableReplacer = new VariableReplacementService$1(this.fileSystem, templateService);
|
|
@@ -2312,7 +2386,16 @@ IMPORTANT:
|
|
|
2312
2386
|
};
|
|
2313
2387
|
return { content: [{
|
|
2314
2388
|
type: "text",
|
|
2315
|
-
text: (await this.boilerplateService.useBoilerplate(request)).message
|
|
2389
|
+
text: `${(await this.boilerplateService.useBoilerplate(request)).message}
|
|
2390
|
+
|
|
2391
|
+
IMPORTANT - Next Steps:
|
|
2392
|
+
1. READ the generated project files to understand their structure
|
|
2393
|
+
2. Review the boilerplate configuration and understand what was created
|
|
2394
|
+
3. If the project requires additional features, use list-scaffolding-methods to see available options
|
|
2395
|
+
4. Install dependencies (pnpm install) before testing or building
|
|
2396
|
+
5. Follow the project's README for setup instructions
|
|
2397
|
+
|
|
2398
|
+
The boilerplate provides a starting point - you may need to add features or customize the generated code based on the project requirements.`
|
|
2316
2399
|
}] };
|
|
2317
2400
|
} catch (error) {
|
|
2318
2401
|
return {
|
|
@@ -2393,11 +2476,20 @@ IMPORTANT:
|
|
|
2393
2476
|
if (!variables) throw new Error("Missing required parameter: variables");
|
|
2394
2477
|
return { content: [{
|
|
2395
2478
|
type: "text",
|
|
2396
|
-
text: (await this.scaffoldingMethodsService.useScaffoldMethod({
|
|
2479
|
+
text: `${(await this.scaffoldingMethodsService.useScaffoldMethod({
|
|
2397
2480
|
projectPath,
|
|
2398
2481
|
scaffold_feature_name,
|
|
2399
2482
|
variables
|
|
2400
|
-
})).message
|
|
2483
|
+
})).message}
|
|
2484
|
+
|
|
2485
|
+
IMPORTANT - Next Steps:
|
|
2486
|
+
1. READ the generated files to understand their structure and template placeholders
|
|
2487
|
+
2. IMPLEMENT the actual business logic according to the feature's purpose (replace TODOs and template variables)
|
|
2488
|
+
3. REGISTER the feature in the appropriate files (e.g., import and register tools in server/index.ts, export from index.ts)
|
|
2489
|
+
4. TEST the implementation to ensure it works correctly
|
|
2490
|
+
5. Only after completing the implementation should you move to other tasks
|
|
2491
|
+
|
|
2492
|
+
Do not skip the implementation step - the scaffolded files contain templates that need actual code.`
|
|
2401
2493
|
}] };
|
|
2402
2494
|
} catch (error) {
|
|
2403
2495
|
return {
|
|
@@ -2563,17 +2655,12 @@ Example workflow for feature:
|
|
|
2563
2655
|
}
|
|
2564
2656
|
});
|
|
2565
2657
|
server.setRequestHandler(__modelcontextprotocol_sdk_types_js.ListToolsRequestSchema, async () => {
|
|
2566
|
-
const listBoilerplateTool = listBoilerplatesTool.getDefinition();
|
|
2567
|
-
const useBoilerplateToolDef = useBoilerplateTool.getDefinition();
|
|
2568
|
-
const listScaffoldingMethodsToolDef = listScaffoldingMethodsTool.getDefinition();
|
|
2569
|
-
const useScaffoldMethodToolDef = useScaffoldMethodTool.getDefinition();
|
|
2570
|
-
const writeToFileToolDef = writeToFileTool.getDefinition();
|
|
2571
2658
|
const tools = [
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2659
|
+
listBoilerplatesTool.getDefinition(),
|
|
2660
|
+
useBoilerplateTool.getDefinition(),
|
|
2661
|
+
listScaffoldingMethodsTool.getDefinition(),
|
|
2662
|
+
useScaffoldMethodTool.getDefinition(),
|
|
2663
|
+
writeToFileTool.getDefinition()
|
|
2577
2664
|
];
|
|
2578
2665
|
if (adminEnabled) {
|
|
2579
2666
|
if (generateBoilerplateTool) tools.push(generateBoilerplateTool.getDefinition());
|
|
@@ -2993,27 +3080,18 @@ const mcpServeCommand = new commander.Command("mcp-serve").description("Start MC
|
|
|
2993
3080
|
try {
|
|
2994
3081
|
const transportType = options.type.toLowerCase();
|
|
2995
3082
|
const serverOptions = { adminEnabled: options.adminEnable };
|
|
2996
|
-
if (transportType === "stdio")
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
} else if (transportType === "sse") {
|
|
3009
|
-
const config = {
|
|
3010
|
-
mode: TransportMode.SSE,
|
|
3011
|
-
port: options.port || Number(process.env.MCP_PORT) || 3e3,
|
|
3012
|
-
host: options.host || process.env.MCP_HOST || "localhost"
|
|
3013
|
-
};
|
|
3014
|
-
const handler = new SseTransportHandler(() => createServer(serverOptions), config);
|
|
3015
|
-
await startServer(handler);
|
|
3016
|
-
} else {
|
|
3083
|
+
if (transportType === "stdio") await startServer(new StdioTransportHandler(createServer(serverOptions)));
|
|
3084
|
+
else if (transportType === "http") await startServer(new HttpTransportHandler(() => createServer(serverOptions), {
|
|
3085
|
+
mode: TransportMode.HTTP,
|
|
3086
|
+
port: options.port || Number(process.env.MCP_PORT) || 3e3,
|
|
3087
|
+
host: options.host || process.env.MCP_HOST || "localhost"
|
|
3088
|
+
}));
|
|
3089
|
+
else if (transportType === "sse") await startServer(new SseTransportHandler(() => createServer(serverOptions), {
|
|
3090
|
+
mode: TransportMode.SSE,
|
|
3091
|
+
port: options.port || Number(process.env.MCP_PORT) || 3e3,
|
|
3092
|
+
host: options.host || process.env.MCP_HOST || "localhost"
|
|
3093
|
+
}));
|
|
3094
|
+
else {
|
|
3017
3095
|
console.error(`Unknown transport type: ${transportType}. Use: stdio, http, or sse`);
|
|
3018
3096
|
process.exit(1);
|
|
3019
3097
|
}
|
|
@@ -3038,18 +3116,17 @@ scaffoldCommand.command("list <projectPath>").description("List available scaffo
|
|
|
3038
3116
|
process.exit(1);
|
|
3039
3117
|
}
|
|
3040
3118
|
const templatesDir = await require_ScaffoldService.TemplatesManager.findTemplatesPath();
|
|
3041
|
-
const
|
|
3042
|
-
const methods = (await new ScaffoldingMethodsService(fileSystemService, templatesDir).listScaffoldingMethods(absolutePath)).methods;
|
|
3119
|
+
const methods = (await new ScaffoldingMethodsService(new FileSystemService(), templatesDir).listScaffoldingMethods(absolutePath)).methods;
|
|
3043
3120
|
if (methods.length === 0) {
|
|
3044
3121
|
messages.warning("No scaffolding methods available for this project.");
|
|
3045
3122
|
return;
|
|
3046
3123
|
}
|
|
3047
|
-
|
|
3124
|
+
print.header(`\n${icons.wrench} Available Scaffolding Methods for ${projectPath}:\n`);
|
|
3048
3125
|
for (const method of methods) {
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
if (method.variables_schema.required && method.variables_schema.required.length > 0)
|
|
3052
|
-
|
|
3126
|
+
print.highlight(` ${method.name}`);
|
|
3127
|
+
print.debug(` ${method.instruction || method.description || "No description available"}`);
|
|
3128
|
+
if (method.variables_schema.required && method.variables_schema.required.length > 0) print.debug(` Required: ${method.variables_schema.required.join(", ")}`);
|
|
3129
|
+
print.newline();
|
|
3053
3130
|
}
|
|
3054
3131
|
} catch (error) {
|
|
3055
3132
|
messages.error("Error listing scaffolding methods:", error);
|
|
@@ -3073,14 +3150,13 @@ scaffoldCommand.command("add <featureName>").description("Add a feature to an ex
|
|
|
3073
3150
|
process.exit(1);
|
|
3074
3151
|
}
|
|
3075
3152
|
const templatesDir = await require_ScaffoldService.TemplatesManager.findTemplatesPath();
|
|
3076
|
-
const
|
|
3077
|
-
const scaffoldingMethodsService = new ScaffoldingMethodsService(fileSystemService, templatesDir);
|
|
3153
|
+
const scaffoldingMethodsService = new ScaffoldingMethodsService(new FileSystemService(), templatesDir);
|
|
3078
3154
|
const methods = (await scaffoldingMethodsService.listScaffoldingMethods(projectPath)).methods;
|
|
3079
3155
|
const method = methods.find((m) => m.name === featureName);
|
|
3080
3156
|
if (!method) {
|
|
3081
3157
|
messages.error(`Scaffold method '${featureName}' not found.`);
|
|
3082
|
-
|
|
3083
|
-
|
|
3158
|
+
print.warning(`Available methods: ${methods.map((m) => m.name).join(", ")}`);
|
|
3159
|
+
print.debug(`Run 'scaffold-mcp scaffold list ${options.project}' to see all available methods`);
|
|
3084
3160
|
process.exit(1);
|
|
3085
3161
|
}
|
|
3086
3162
|
const required = typeof method.variables_schema === "object" && method.variables_schema !== null && "required" in method.variables_schema ? method.variables_schema.required : [];
|
|
@@ -3092,15 +3168,15 @@ scaffoldCommand.command("add <featureName>").description("Add a feature to an ex
|
|
|
3092
3168
|
for (const key of required) if (key.includes("Name")) exampleVars[key] = "MyFeature";
|
|
3093
3169
|
else if (key === "description") exampleVars[key] = "Feature description";
|
|
3094
3170
|
else exampleVars[key] = `<${key}>`;
|
|
3095
|
-
|
|
3171
|
+
print.debug(`Example: scaffold-mcp scaffold add ${featureName} --project ${options.project} --vars '${JSON.stringify(exampleVars)}'`);
|
|
3096
3172
|
process.exit(1);
|
|
3097
3173
|
}
|
|
3098
3174
|
if (options.verbose) {
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3175
|
+
print.info(`🔧 Feature: ${featureName}`);
|
|
3176
|
+
print.info(`📊 Variables: ${JSON.stringify(variables, null, 2)}`);
|
|
3177
|
+
print.info(`📁 Project Path: ${projectPath}`);
|
|
3102
3178
|
}
|
|
3103
|
-
|
|
3179
|
+
print.info(`🚀 Adding '${featureName}' to project...`);
|
|
3104
3180
|
const result = await scaffoldingMethodsService.useScaffoldMethod({
|
|
3105
3181
|
projectPath,
|
|
3106
3182
|
scaffold_feature_name: featureName,
|
|
@@ -3110,17 +3186,17 @@ scaffoldCommand.command("add <featureName>").description("Add a feature to an ex
|
|
|
3110
3186
|
messages.success("✅ Feature added successfully!");
|
|
3111
3187
|
console.log(result.message);
|
|
3112
3188
|
if (result.createdFiles && result.createdFiles.length > 0) {
|
|
3113
|
-
|
|
3114
|
-
result.createdFiles.forEach((file) =>
|
|
3189
|
+
print.header("\n📁 Created files:");
|
|
3190
|
+
result.createdFiles.forEach((file) => print.debug(` - ${file}`));
|
|
3115
3191
|
}
|
|
3116
3192
|
if (result.warnings && result.warnings.length > 0) {
|
|
3117
3193
|
messages.warning("\n⚠️ Warnings:");
|
|
3118
|
-
result.warnings.forEach((warning) =>
|
|
3194
|
+
result.warnings.forEach((warning) => print.debug(` - ${warning}`));
|
|
3119
3195
|
}
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3196
|
+
print.header("\n📋 Next steps:");
|
|
3197
|
+
print.debug(" - Review the generated files");
|
|
3198
|
+
print.debug(" - Update imports if necessary");
|
|
3199
|
+
print.debug(" - Run tests to ensure everything works");
|
|
3124
3200
|
} else {
|
|
3125
3201
|
messages.error(`❌ Failed to add feature: ${result.message}`);
|
|
3126
3202
|
process.exit(1);
|
|
@@ -3139,23 +3215,22 @@ scaffoldCommand.command("info <featureName>").description("Show detailed informa
|
|
|
3139
3215
|
process.exit(1);
|
|
3140
3216
|
}
|
|
3141
3217
|
const templatesDir = await require_ScaffoldService.TemplatesManager.findTemplatesPath();
|
|
3142
|
-
const
|
|
3143
|
-
const method = (await new ScaffoldingMethodsService(fileSystemService, templatesDir).listScaffoldingMethods(projectPath)).methods.find((m) => m.name === featureName);
|
|
3218
|
+
const method = (await new ScaffoldingMethodsService(new FileSystemService(), templatesDir).listScaffoldingMethods(projectPath)).methods.find((m) => m.name === featureName);
|
|
3144
3219
|
if (!method) {
|
|
3145
3220
|
messages.error(`❌ Scaffold method '${featureName}' not found.`);
|
|
3146
3221
|
process.exit(1);
|
|
3147
3222
|
}
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3223
|
+
print.header(`\n🔧 Scaffold Method: ${method.name}\n`);
|
|
3224
|
+
print.debug(`Description: ${method.description}`);
|
|
3225
|
+
print.header("\n📝 Variables Schema:");
|
|
3151
3226
|
console.log(JSON.stringify(method.variables_schema, null, 2));
|
|
3152
3227
|
const includes = "includes" in method ? method.includes : [];
|
|
3153
3228
|
if (includes && includes.length > 0) {
|
|
3154
|
-
|
|
3229
|
+
print.header("\n📁 Files to be created:");
|
|
3155
3230
|
includes.forEach((include) => {
|
|
3156
3231
|
const parts = include.split(">>");
|
|
3157
|
-
if (parts.length === 2)
|
|
3158
|
-
else
|
|
3232
|
+
if (parts.length === 2) print.debug(` - ${parts[1].trim()}`);
|
|
3233
|
+
else print.debug(` - ${include}`);
|
|
3159
3234
|
});
|
|
3160
3235
|
}
|
|
3161
3236
|
} catch (error) {
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
const require_chunk = require('./chunk-nOFOJqeH.js');
|
|
2
|
+
let node_path = require("node:path");
|
|
3
|
+
node_path = require_chunk.__toESM(node_path);
|
|
4
|
+
let node_os = require("node:os");
|
|
5
|
+
node_os = require_chunk.__toESM(node_os);
|
|
6
|
+
let pino = require("pino");
|
|
7
|
+
pino = require_chunk.__toESM(pino);
|
|
8
|
+
|
|
9
|
+
//#region src/utils/logger.ts
|
|
10
|
+
const logsDir = node_path.join(node_os.tmpdir(), "scaffold-mcp-logs");
|
|
11
|
+
const logger = (0, pino.default)({
|
|
12
|
+
level: process.env.LOG_LEVEL || "debug",
|
|
13
|
+
timestamp: pino.default.stdTimeFunctions.isoTime
|
|
14
|
+
}, pino.default.destination({
|
|
15
|
+
dest: node_path.join(logsDir, "scaffold-mcp.log"),
|
|
16
|
+
mkdir: true,
|
|
17
|
+
sync: true
|
|
18
|
+
}));
|
|
19
|
+
const log = {
|
|
20
|
+
debug: (msg, ...args) => logger.debug({ args }, msg),
|
|
21
|
+
info: (msg, ...args) => logger.info({ args }, msg),
|
|
22
|
+
warn: (msg, ...args) => logger.warn({ args }, msg),
|
|
23
|
+
error: (msg, ...args) => logger.error({ args }, msg)
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
//#endregion
|
|
27
|
+
Object.defineProperty(exports, 'log', {
|
|
28
|
+
enumerable: true,
|
|
29
|
+
get: function () {
|
|
30
|
+
return log;
|
|
31
|
+
}
|
|
32
|
+
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agiflowai/scaffold-mcp",
|
|
3
3
|
"description": "MCP server for scaffolding applications with boilerplate templates",
|
|
4
|
-
"version": "0.3.
|
|
4
|
+
"version": "0.3.3",
|
|
5
5
|
"license": "AGPL-3.0",
|
|
6
6
|
"author": "AgiflowIO",
|
|
7
7
|
"repository": {
|
|
@@ -41,8 +41,10 @@
|
|
|
41
41
|
"fs-extra": "11.3.2",
|
|
42
42
|
"js-yaml": "4.1.0",
|
|
43
43
|
"liquidjs": "10.21.1",
|
|
44
|
+
"pino": "^10.0.0",
|
|
45
|
+
"pino-pretty": "^13.1.1",
|
|
44
46
|
"zod": "3.25.76",
|
|
45
|
-
"@agiflowai/scaffold-generator": "0.3.
|
|
47
|
+
"@agiflowai/scaffold-generator": "0.3.3"
|
|
46
48
|
},
|
|
47
49
|
"devDependencies": {
|
|
48
50
|
"@types/express": "^5.0.0",
|
|
@@ -58,7 +60,7 @@
|
|
|
58
60
|
"scripts": {
|
|
59
61
|
"dev": "node --loader ts-node/esm src/index.ts",
|
|
60
62
|
"build": "tsdown",
|
|
61
|
-
"test": "vitest",
|
|
63
|
+
"test": "vitest --run",
|
|
62
64
|
"typecheck": "tsc --noEmit"
|
|
63
65
|
}
|
|
64
66
|
}
|
|
File without changes
|