@agiflowai/scaffold-mcp 0.3.1 → 0.3.2

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.
@@ -1,3 +1,3 @@
1
- const require_ScaffoldConfigLoader = require('./ScaffoldConfigLoader-yDhzLQpC.js');
1
+ const require_ScaffoldConfigLoader = require('./ScaffoldConfigLoader-CvIJEFcI.js');
2
2
 
3
3
  exports.ScaffoldConfigLoader = require_ScaffoldConfigLoader.ScaffoldConfigLoader;
@@ -0,0 +1,4 @@
1
+ require('./logger-Dno88AK9.js');
2
+ const require_ScaffoldService = require('./ScaffoldService-N6X24Vw0.js');
3
+
4
+ exports.ScaffoldService = require_ScaffoldService.ScaffoldService;
@@ -1,4 +1,5 @@
1
1
  const require_chunk = require('./chunk-nOFOJqeH.js');
2
+ const require_logger = require('./logger-Dno88AK9.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
- console.warn(`Cannot read directory ${dirPath}: ${error}`);
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
- console.warn(`Cannot stat ${itemPath}: ${error}`);
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
- console.warn(`Cannot read directory ${dirPath}: ${error}`);
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
- console.warn(`Cannot stat ${itemPath}: ${error}`);
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
- console.log("Config generator:", config.generator);
341
- console.log("Config:", JSON.stringify(config, null, 2));
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
- console.log("Using custom generator:", config.generator);
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-Dno88AK9.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
- return this.liquid.parseAndRenderSync(template, variables);
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
- console.warn(`LiquidJS rendering error: ${error}`);
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
  }
@@ -0,0 +1,4 @@
1
+ require('./logger-Dno88AK9.js');
2
+ const require_TemplateService = require('./TemplateService-Em2i9bb7.js');
3
+
4
+ exports.TemplateService = require_TemplateService.TemplateService;
@@ -1,4 +1,5 @@
1
1
  const require_chunk = require('./chunk-nOFOJqeH.js');
2
+ const require_logger = require('./logger-Dno88AK9.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
- console.warn(`Skipping directory ${dirPath}: ${error}`);
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
- console.warn(`Skipping item ${itemPath}: ${error}`);
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
- console.warn(`Skipping file ${filePath}: ${error}`);
58
+ require_logger.log.warn(`Skipping file ${filePath}: ${error}`);
58
59
  }
59
60
  }
60
61
  isBinaryFile(filePath) {
@@ -1,3 +1,4 @@
1
- const require_VariableReplacementService = require('./VariableReplacementService-DJqXiBC2.js');
1
+ require('./logger-Dno88AK9.js');
2
+ const require_VariableReplacementService = require('./VariableReplacementService-BGmF2DVE.js');
2
3
 
3
4
  exports.VariableReplacementService = require_VariableReplacementService.VariableReplacementService;
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 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');
3
+ const require_logger = require('./logger-Dno88AK9.js');
4
+ const require_ScaffoldConfigLoader = require('./ScaffoldConfigLoader-CvIJEFcI.js');
5
+ const require_ScaffoldService = require('./ScaffoldService-N6X24Vw0.js');
6
+ const require_TemplateService = require('./TemplateService-Em2i9bb7.js');
7
+ const require_VariableReplacementService = require('./VariableReplacementService-BGmF2DVE.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/console.ts
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 logger = {
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
- logger.info(`${icons.info} ${message}`);
191
+ print.info(`${icons.info} ${message}`);
107
192
  },
108
193
  success: (message) => {
109
- logger.success(`${icons.check} ${message}`);
194
+ print.success(`${icons.check} ${message}`);
110
195
  },
111
196
  error: (message, error) => {
112
- logger.error(`${icons.cross} ${message}`, error);
197
+ print.error(`${icons.cross} ${message}`, error);
113
198
  },
114
199
  warning: (message) => {
115
- logger.warning(`${icons.warning} ${message}`);
200
+ print.warning(`${icons.warning} ${message}`);
116
201
  },
117
202
  hint: (message) => {
118
- logger.warning(`${icons.bulb} ${message}`);
203
+ print.warning(`${icons.bulb} ${message}`);
119
204
  },
120
205
  loading: (message) => {
121
- logger.info(`${icons.rocket} ${message}`);
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
- logger.newline();
130
- logger.header(`${title}`);
131
- logger.newline();
214
+ print.newline();
215
+ print.header(`${title}`);
216
+ print.newline();
132
217
  },
133
218
  list: (title, items) => {
134
- logger.header(`\n${title}\n`);
135
- items.forEach((item) => logger.item(item));
219
+ print.header(`\n${title}\n`);
220
+ items.forEach((item) => print.item(item));
136
221
  },
137
222
  nextSteps: (steps) => {
138
- logger.header(`\n${icons.clipboard} Next steps:`);
139
- steps.forEach((step) => logger.indent(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
- logger.header(`\n${icons.folder} Created files:`);
143
- files.slice(0, maxShow).forEach((file) => logger.item(file));
144
- if (files.length > maxShow) logger.indent(`... and ${files.length - maxShow} more files`);
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
- logger.warning(`\n${icons.warning} Warnings:`);
148
- warnings.forEach((warning) => logger.item(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
- logger.info(`${icons.download} Downloading template '${templateName}' from ${templateUrl}...`);
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
- logger.info(`${icons.folder} Detected subdirectory: ${parsedUrl.subdirectory} (branch: ${parsedUrl.branch})`);
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
- logger.header(`\n${icons.folder} Template location:`);
266
- logger.indent(targetFolder);
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
- logger.header(`\n${icons.config} Configuration file found:`);
271
- logger.indent(node_path.default.basename(configFile));
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
- logger.indent("You may need to create one manually.");
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
- 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);
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
- console.warn(`Skipping boilerplate '${boilerplate.name}' in ${templatePath}: targetFolder is required in scaffold.yaml`);
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
- console.warn(`Failed to load scaffold.yaml for ${templatePath}:`, error);
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
- console.warn(`Failed to update project.json with sourceTemplate: ${error}`);
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 templatesDir = await require_ScaffoldService.TemplatesManager.findTemplatesPath();
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
- logger.header(`\n${icons.package} Available Boilerplate Templates:\n`);
520
+ print.header(`\n${icons.package} Available Boilerplate Templates:\n`);
526
521
  for (const bp of boilerplates) {
527
- logger.highlight(` ${bp.name}`);
528
- logger.debug(` ${bp.description}`);
529
- logger.debug(` Target: ${bp.target_folder}`);
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) logger.debug(` Required: ${required.join(", ")}`);
532
- logger.newline();
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 templatesDir = await require_ScaffoldService.TemplatesManager.findTemplatesPath();
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
- logger.warning(`Available boilerplates: ${boilerplates.map((b) => b.name).join(", ")}`);
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
- logger.debug(`Example: scaffold-mcp boilerplate create ${boilerplateName} --vars '${JSON.stringify(exampleVars)}'`);
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
- logger.info(`${icons.wrench} Boilerplate: ${boilerplateName}`);
572
- logger.info(`${icons.chart} Variables: ${JSON.stringify(variables, null, 2)}`);
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
- logger.info(result.message);
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 templatesDir = await require_ScaffoldService.TemplatesManager.findTemplatesPath();
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
- logger.header(`\n${icons.package} Boilerplate: ${bp.name}\n`);
608
- logger.debug(`Description: ${bp.description}`);
609
- logger.debug(`Template Path: ${bp.template_path}`);
610
- logger.debug(`Target Folder: ${bp.target_folder}`);
611
- logger.header(`\n${icons.config} Variables Schema:`);
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
- logger.info(`${icons.download} Fetching templates from ${DEFAULT_TEMPLATE_REPO.owner}/${DEFAULT_TEMPLATE_REPO.repo}...`);
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
- logger.info(`${icons.folder} Found ${templateDirs.length} template(s)`);
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
- logger.info(`${icons.skip} Skipping ${template.name} (already exists)`);
649
+ print.info(`${icons.skip} Skipping ${template.name} (already exists)`);
657
650
  continue;
658
651
  }
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}`);
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
- logger.success(`\n${icons.check} All templates downloaded successfully!`);
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
- logger.info(`${icons.rocket} Initializing templates folder at: ${templatesPath}`);
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
- logger.success(`${icons.check} Templates folder created!`);
704
+ print.success(`${icons.check} Templates folder created!`);
713
705
  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);
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. Report success and next steps to the user`
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. Report success and list created files`
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: variablesSchema,
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 (use {{ variableName }} for Liquid placeholders).
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: variablesSchema,
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
- console.warn(`Failed to read scaffold.yaml at ${scaffoldYamlPath}:`, error);
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
- console.warn(`Failed to read subdirectories in ${itemPath}:`, error);
2211
+ require_logger.log.warn(`Failed to read subdirectories in ${itemPath}:`, error);
2138
2212
  }
2139
2213
  }
2140
2214
  } catch (error) {
2141
- console.warn(`Failed to read templates root directory ${this.templatesRootPath}:`, error);
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-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;
2227
+ const ScaffoldService$1 = (await Promise.resolve().then(() => require("./ScaffoldService-CEJt8Yw4.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-BLwdHUSz.js"))).VariableReplacementService;
2230
+ const TemplateService$1 = (await Promise.resolve().then(() => require("./TemplateService-Z2SW_58N.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
- listBoilerplateTool,
2573
- useBoilerplateToolDef,
2574
- listScaffoldingMethodsToolDef,
2575
- useScaffoldMethodToolDef,
2576
- writeToFileToolDef
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
- const server = createServer(serverOptions);
2998
- const handler = new StdioTransportHandler(server);
2999
- await startServer(handler);
3000
- } else if (transportType === "http") {
3001
- const config = {
3002
- mode: TransportMode.HTTP,
3003
- port: options.port || Number(process.env.MCP_PORT) || 3e3,
3004
- host: options.host || process.env.MCP_HOST || "localhost"
3005
- };
3006
- const handler = new HttpTransportHandler(() => createServer(serverOptions), config);
3007
- await startServer(handler);
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 fileSystemService = new FileSystemService();
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
- logger.header(`\n${icons.wrench} Available Scaffolding Methods for ${projectPath}:\n`);
3124
+ print.header(`\n${icons.wrench} Available Scaffolding Methods for ${projectPath}:\n`);
3048
3125
  for (const method of methods) {
3049
- logger.highlight(` ${method.name}`);
3050
- logger.debug(` ${method.instruction || method.description || "No description available"}`);
3051
- if (method.variables_schema.required && method.variables_schema.required.length > 0) logger.debug(` Required: ${method.variables_schema.required.join(", ")}`);
3052
- logger.newline();
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 fileSystemService = new FileSystemService();
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
- logger.warning(`Available methods: ${methods.map((m) => m.name).join(", ")}`);
3083
- logger.debug(`Run 'scaffold-mcp scaffold list ${options.project}' to see all available methods`);
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
- logger.debug(`Example: scaffold-mcp scaffold add ${featureName} --project ${options.project} --vars '${JSON.stringify(exampleVars)}'`);
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
- logger.info(`🔧 Feature: ${featureName}`);
3100
- logger.info(`📊 Variables: ${JSON.stringify(variables, null, 2)}`);
3101
- logger.info(`📁 Project Path: ${projectPath}`);
3175
+ print.info(`🔧 Feature: ${featureName}`);
3176
+ print.info(`📊 Variables: ${JSON.stringify(variables, null, 2)}`);
3177
+ print.info(`📁 Project Path: ${projectPath}`);
3102
3178
  }
3103
- logger.info(`🚀 Adding '${featureName}' to project...`);
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
- logger.header("\n📁 Created files:");
3114
- result.createdFiles.forEach((file) => logger.debug(` - ${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) => logger.debug(` - ${warning}`));
3194
+ result.warnings.forEach((warning) => print.debug(` - ${warning}`));
3119
3195
  }
3120
- logger.header("\n📋 Next steps:");
3121
- logger.debug(" - Review the generated files");
3122
- logger.debug(" - Update imports if necessary");
3123
- logger.debug(" - Run tests to ensure everything works");
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 fileSystemService = new FileSystemService();
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
- logger.header(`\n🔧 Scaffold Method: ${method.name}\n`);
3149
- logger.debug(`Description: ${method.description}`);
3150
- logger.header("\n📝 Variables Schema:");
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
- logger.header("\n📁 Files to be created:");
3229
+ print.header("\n📁 Files to be created:");
3155
3230
  includes.forEach((include) => {
3156
3231
  const parts = include.split(">>");
3157
- if (parts.length === 2) logger.debug(` - ${parts[1].trim()}`);
3158
- else logger.debug(` - ${include}`);
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: false
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.1",
4
+ "version": "0.3.2",
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.1"
47
+ "@agiflowai/scaffold-generator": "0.3.2"
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
  }
@@ -1,3 +0,0 @@
1
- const require_ScaffoldService = require('./ScaffoldService-B8-dPa7L.js');
2
-
3
- exports.ScaffoldService = require_ScaffoldService.ScaffoldService;
@@ -1,3 +0,0 @@
1
- const require_TemplateService = require('./TemplateService-DvKjDjQE.js');
2
-
3
- exports.TemplateService = require_TemplateService.TemplateService;