@agiflowai/scaffold-mcp 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/ScaffoldService-B3En_m4t.cjs +3 -0
- package/dist/{ScaffoldService-B-L4gwHt.cjs → ScaffoldService-BwDmXt83.cjs} +11 -8
- package/dist/ScaffoldService-CJ3vNmAj.js +3 -0
- package/dist/{ScaffoldService-QgQKHMM-.js → ScaffoldService-DB7-Cyod.js} +10 -7
- package/dist/{VariableReplacementService-D8C-IsP-.js → VariableReplacementService-BAwTGv_R.js} +1 -1
- package/dist/{VariableReplacementService-BrJ1PdKm.cjs → VariableReplacementService-CroHkMha.cjs} +1 -1
- package/dist/{VariableReplacementService-BL84vnKk.cjs → VariableReplacementService-D0QnWKUW.cjs} +2 -2
- package/dist/{VariableReplacementService-B3qARIC9.js → VariableReplacementService-DRxd9ILB.js} +1 -1
- package/dist/cli.cjs +147 -731
- package/dist/cli.js +146 -727
- package/dist/index.cjs +142 -8
- package/dist/index.d.cts +28 -12
- package/dist/index.d.ts +28 -12
- package/dist/index.js +133 -3
- package/dist/{stdio-Dmpwju2k.js → stdio-Bxn4A1IU.js} +455 -456
- package/dist/{stdio-Cz5aRdvr.cjs → stdio-TGsG8akc.cjs} +470 -502
- package/package.json +4 -3
- package/dist/ScaffoldService-Cx4ZonaT.cjs +0 -3
- package/dist/ScaffoldService-DVsusUh5.js +0 -3
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { ScaffoldConfigLoader } from "./ScaffoldConfigLoader-CI0T6zdG.js";
|
|
2
|
-
import { ScaffoldService } from "./ScaffoldService-
|
|
2
|
+
import { ScaffoldService } from "./ScaffoldService-DB7-Cyod.js";
|
|
3
3
|
import { TemplateService } from "./TemplateService-CiZJA06s.js";
|
|
4
|
-
import { VariableReplacementService } from "./VariableReplacementService-
|
|
4
|
+
import { VariableReplacementService } from "./VariableReplacementService-DRxd9ILB.js";
|
|
5
|
+
import { ProjectConfigResolver, log } from "@agiflowai/aicode-utils";
|
|
5
6
|
import * as path$1 from "node:path";
|
|
6
7
|
import path from "node:path";
|
|
7
|
-
import {
|
|
8
|
+
import { jsonSchemaToZod } from "@composio/json-schema-to-zod";
|
|
8
9
|
import * as fs$1 from "fs-extra";
|
|
9
10
|
import fs from "fs-extra";
|
|
10
|
-
import { execa } from "execa";
|
|
11
|
-
import { jsonSchemaToZod } from "@composio/json-schema-to-zod";
|
|
12
11
|
import * as yaml$1 from "js-yaml";
|
|
13
12
|
import yaml from "js-yaml";
|
|
14
13
|
import { z } from "zod";
|
|
@@ -19,133 +18,6 @@ import express from "express";
|
|
|
19
18
|
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
20
19
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
21
20
|
|
|
22
|
-
//#region src/utils/git.ts
|
|
23
|
-
/**
|
|
24
|
-
* Execute a git command safely using execa to prevent command injection
|
|
25
|
-
*/
|
|
26
|
-
async function execGit(args, cwd) {
|
|
27
|
-
try {
|
|
28
|
-
await execa("git", args, { cwd });
|
|
29
|
-
} catch (error) {
|
|
30
|
-
const execaError = error;
|
|
31
|
-
throw new Error(`Git command failed: ${execaError.stderr || execaError.message}`);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
/**
|
|
35
|
-
* Find the workspace root by searching upwards for .git folder
|
|
36
|
-
* Returns null if no .git folder is found (indicating a new project setup is needed)
|
|
37
|
-
*/
|
|
38
|
-
async function findWorkspaceRoot(startPath = process.cwd()) {
|
|
39
|
-
let currentPath = path.resolve(startPath);
|
|
40
|
-
const rootPath = path.parse(currentPath).root;
|
|
41
|
-
while (true) {
|
|
42
|
-
const gitPath = path.join(currentPath, ".git");
|
|
43
|
-
if (await fs$1.pathExists(gitPath)) return currentPath;
|
|
44
|
-
if (currentPath === rootPath) return null;
|
|
45
|
-
currentPath = path.dirname(currentPath);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* Parse GitHub URL to detect if it's a subdirectory
|
|
50
|
-
* Supports formats:
|
|
51
|
-
* - https://github.com/user/repo
|
|
52
|
-
* - https://github.com/user/repo/tree/branch/path/to/dir
|
|
53
|
-
* - https://github.com/user/repo/tree/main/path/to/dir
|
|
54
|
-
*/
|
|
55
|
-
function parseGitHubUrl(url) {
|
|
56
|
-
const treeMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)\/(.+)$/);
|
|
57
|
-
const blobMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+)\/blob\/([^/]+)\/(.+)$/);
|
|
58
|
-
const rootMatch = url.match(/^https?:\/\/github\.com\/([^/]+)\/([^/]+?)(?:\.git)?$/);
|
|
59
|
-
if (treeMatch || blobMatch) {
|
|
60
|
-
const match = treeMatch || blobMatch;
|
|
61
|
-
return {
|
|
62
|
-
owner: match[1],
|
|
63
|
-
repo: match[2],
|
|
64
|
-
repoUrl: `https://github.com/${match[1]}/${match[2]}.git`,
|
|
65
|
-
branch: match[3],
|
|
66
|
-
subdirectory: match[4],
|
|
67
|
-
isSubdirectory: true
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
if (rootMatch) return {
|
|
71
|
-
owner: rootMatch[1],
|
|
72
|
-
repo: rootMatch[2],
|
|
73
|
-
repoUrl: `https://github.com/${rootMatch[1]}/${rootMatch[2]}.git`,
|
|
74
|
-
isSubdirectory: false
|
|
75
|
-
};
|
|
76
|
-
return {
|
|
77
|
-
repoUrl: url,
|
|
78
|
-
isSubdirectory: false
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
/**
|
|
82
|
-
* Clone a subdirectory from a git repository using sparse checkout
|
|
83
|
-
*/
|
|
84
|
-
async function cloneSubdirectory(repoUrl, branch, subdirectory, targetFolder) {
|
|
85
|
-
const tempFolder = `${targetFolder}.tmp`;
|
|
86
|
-
try {
|
|
87
|
-
await execGit(["init", tempFolder]);
|
|
88
|
-
await execGit([
|
|
89
|
-
"remote",
|
|
90
|
-
"add",
|
|
91
|
-
"origin",
|
|
92
|
-
repoUrl
|
|
93
|
-
], tempFolder);
|
|
94
|
-
await execGit([
|
|
95
|
-
"config",
|
|
96
|
-
"core.sparseCheckout",
|
|
97
|
-
"true"
|
|
98
|
-
], tempFolder);
|
|
99
|
-
const sparseCheckoutFile = path.join(tempFolder, ".git", "info", "sparse-checkout");
|
|
100
|
-
await fs$1.writeFile(sparseCheckoutFile, `${subdirectory}\n`);
|
|
101
|
-
await execGit([
|
|
102
|
-
"pull",
|
|
103
|
-
"--depth=1",
|
|
104
|
-
"origin",
|
|
105
|
-
branch
|
|
106
|
-
], tempFolder);
|
|
107
|
-
const sourceDir = path.join(tempFolder, subdirectory);
|
|
108
|
-
if (!await fs$1.pathExists(sourceDir)) throw new Error(`Subdirectory '${subdirectory}' not found in repository at branch '${branch}'`);
|
|
109
|
-
if (await fs$1.pathExists(targetFolder)) throw new Error(`Target folder already exists: ${targetFolder}`);
|
|
110
|
-
await fs$1.move(sourceDir, targetFolder);
|
|
111
|
-
await fs$1.remove(tempFolder);
|
|
112
|
-
} catch (error) {
|
|
113
|
-
if (await fs$1.pathExists(tempFolder)) await fs$1.remove(tempFolder);
|
|
114
|
-
throw error;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* Clone entire repository
|
|
119
|
-
*/
|
|
120
|
-
async function cloneRepository(repoUrl, targetFolder) {
|
|
121
|
-
await execGit([
|
|
122
|
-
"clone",
|
|
123
|
-
repoUrl,
|
|
124
|
-
targetFolder
|
|
125
|
-
]);
|
|
126
|
-
const gitFolder = path.join(targetFolder, ".git");
|
|
127
|
-
if (await fs$1.pathExists(gitFolder)) await fs$1.remove(gitFolder);
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Fetch directory listing from GitHub API
|
|
131
|
-
*/
|
|
132
|
-
async function fetchGitHubDirectoryContents(owner, repo, path$2, branch = "main") {
|
|
133
|
-
const url = `https://api.github.com/repos/${owner}/${repo}/contents/${path$2}?ref=${branch}`;
|
|
134
|
-
const response = await fetch(url, { headers: {
|
|
135
|
-
Accept: "application/vnd.github.v3+json",
|
|
136
|
-
"User-Agent": "scaffold-mcp"
|
|
137
|
-
} });
|
|
138
|
-
if (!response.ok) throw new Error(`Failed to fetch directory contents: ${response.statusText}`);
|
|
139
|
-
const data = await response.json();
|
|
140
|
-
if (!Array.isArray(data)) throw new Error("Expected directory but got file");
|
|
141
|
-
return data.map((item) => ({
|
|
142
|
-
name: item.name,
|
|
143
|
-
type: item.type,
|
|
144
|
-
path: item.path
|
|
145
|
-
}));
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
//#endregion
|
|
149
21
|
//#region src/services/FileSystemService.ts
|
|
150
22
|
var FileSystemService = class {
|
|
151
23
|
async pathExists(path$2) {
|
|
@@ -242,7 +114,28 @@ var BoilerplateService = class {
|
|
|
242
114
|
* Executes a specific boilerplate with provided variables
|
|
243
115
|
*/
|
|
244
116
|
async useBoilerplate(request) {
|
|
245
|
-
|
|
117
|
+
let { boilerplateName, variables, monolith, targetFolderOverride } = request;
|
|
118
|
+
if (monolith === void 0) try {
|
|
119
|
+
const config = await ProjectConfigResolver.resolveProjectConfig(process.cwd());
|
|
120
|
+
monolith = config.type === "monolith";
|
|
121
|
+
log.info(`Auto-detected project type: ${config.type}`);
|
|
122
|
+
} catch (_error) {
|
|
123
|
+
monolith = false;
|
|
124
|
+
log.info("No project configuration found, defaulting to monorepo mode");
|
|
125
|
+
}
|
|
126
|
+
if (monolith && !boilerplateName) try {
|
|
127
|
+
boilerplateName = (await ProjectConfigResolver.resolveProjectConfig(process.cwd())).sourceTemplate;
|
|
128
|
+
log.info(`Using boilerplate from toolkit.yaml: ${boilerplateName}`);
|
|
129
|
+
} catch (error) {
|
|
130
|
+
return {
|
|
131
|
+
success: false,
|
|
132
|
+
message: `Failed to read boilerplate name from toolkit.yaml: ${error instanceof Error ? error.message : String(error)}`
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
if (!boilerplateName) return {
|
|
136
|
+
success: false,
|
|
137
|
+
message: "Missing required parameter: boilerplateName"
|
|
138
|
+
};
|
|
246
139
|
const boilerplateList = await this.listBoilerplates();
|
|
247
140
|
const boilerplate = boilerplateList.boilerplates.find((b) => b.name === boilerplateName);
|
|
248
141
|
if (!boilerplate) return {
|
|
@@ -261,9 +154,10 @@ var BoilerplateService = class {
|
|
|
261
154
|
};
|
|
262
155
|
const folderName = packageName.includes("/") ? packageName.split("/")[1] : packageName;
|
|
263
156
|
const targetFolder = targetFolderOverride || (monolith ? "." : boilerplate.target_folder);
|
|
157
|
+
const projectNameForPath = monolith ? "" : folderName;
|
|
264
158
|
try {
|
|
265
159
|
const result = await this.scaffoldService.useBoilerplate({
|
|
266
|
-
projectName:
|
|
160
|
+
projectName: projectNameForPath,
|
|
267
161
|
packageName,
|
|
268
162
|
targetFolder,
|
|
269
163
|
templateFolder: boilerplate.template_path,
|
|
@@ -509,44 +403,28 @@ var BoilerplateGeneratorService = class {
|
|
|
509
403
|
var GenerateBoilerplateFileTool = class GenerateBoilerplateFileTool {
|
|
510
404
|
static TOOL_NAME = "generate-boilerplate-file";
|
|
511
405
|
boilerplateGeneratorService;
|
|
512
|
-
|
|
406
|
+
isMonolith;
|
|
407
|
+
constructor(templatesPath, isMonolith = false) {
|
|
513
408
|
this.boilerplateGeneratorService = new BoilerplateGeneratorService(templatesPath);
|
|
409
|
+
this.isMonolith = isMonolith;
|
|
514
410
|
}
|
|
515
411
|
/**
|
|
516
412
|
* Get the tool definition for MCP
|
|
517
413
|
*/
|
|
518
414
|
getDefinition() {
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
- Headers help AI understand and follow established patterns when working with generated code
|
|
533
|
-
- Use the header parameter to document the architectural decisions and best practices
|
|
534
|
-
|
|
535
|
-
Use this after generate-boilerplate or generate-feature-scaffold to create the actual template files referenced in the includes array.`,
|
|
536
|
-
inputSchema: {
|
|
537
|
-
type: "object",
|
|
538
|
-
properties: {
|
|
539
|
-
templateName: {
|
|
540
|
-
type: "string",
|
|
541
|
-
description: "Name of the template folder (must already exist)"
|
|
542
|
-
},
|
|
543
|
-
filePath: {
|
|
544
|
-
type: "string",
|
|
545
|
-
description: "Path of the file to create within the template (e.g., \"package.json\", \"src/app/page.tsx\")"
|
|
546
|
-
},
|
|
547
|
-
content: {
|
|
548
|
-
type: "string",
|
|
549
|
-
description: `Content of the template file using Liquid template syntax.
|
|
415
|
+
const properties = {};
|
|
416
|
+
if (!this.isMonolith) properties.templateName = {
|
|
417
|
+
type: "string",
|
|
418
|
+
description: "Name of the template folder (must already exist)"
|
|
419
|
+
};
|
|
420
|
+
Object.assign(properties, {
|
|
421
|
+
filePath: {
|
|
422
|
+
type: "string",
|
|
423
|
+
description: "Path of the file to create within the template (e.g., \"package.json\", \"src/app/page.tsx\")"
|
|
424
|
+
},
|
|
425
|
+
content: {
|
|
426
|
+
type: "string",
|
|
427
|
+
description: `Content of the template file using Liquid template syntax.
|
|
550
428
|
|
|
551
429
|
LIQUID SYNTAX:
|
|
552
430
|
- Variables: {{ variableName }} - Replaced with actual values
|
|
@@ -615,14 +493,14 @@ export function calculateTax(income: number) {
|
|
|
615
493
|
const stateRate = 0.05;
|
|
616
494
|
return income * (federalRate + stateRate);
|
|
617
495
|
}`
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
496
|
+
},
|
|
497
|
+
sourceFile: {
|
|
498
|
+
type: "string",
|
|
499
|
+
description: "Optional: Path to a source file to copy and convert to a template"
|
|
500
|
+
},
|
|
501
|
+
header: {
|
|
502
|
+
type: "string",
|
|
503
|
+
description: `Optional: Header comment to add at the top of the file to provide AI hints about design patterns, coding standards, and best practices.
|
|
626
504
|
|
|
627
505
|
Example format for TypeScript/JavaScript files:
|
|
628
506
|
/**
|
|
@@ -642,9 +520,31 @@ Example format for TypeScript/JavaScript files:
|
|
|
642
520
|
*/
|
|
643
521
|
|
|
644
522
|
The header helps AI understand and follow established patterns when working with generated code.`
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
const required = ["filePath"];
|
|
526
|
+
if (!this.isMonolith) required.unshift("templateName");
|
|
527
|
+
return {
|
|
528
|
+
name: GenerateBoilerplateFileTool.TOOL_NAME,
|
|
529
|
+
description: `Create or update template files for boilerplates or features in the specified template directory.
|
|
530
|
+
|
|
531
|
+
This tool:
|
|
532
|
+
- Creates template files with .liquid extension for variable substitution
|
|
533
|
+
- Supports creating nested directory structures
|
|
534
|
+
- Can create files from source files (copying and converting to templates)
|
|
535
|
+
- Validates that the template directory exists
|
|
536
|
+
- Works for both boilerplate includes and feature scaffold includes
|
|
537
|
+
|
|
538
|
+
IMPORTANT - Always add header comments:
|
|
539
|
+
- For code files (*.ts, *.tsx, *.js, *.jsx), ALWAYS include a header parameter with design patterns, coding standards, and things to avoid
|
|
540
|
+
- Headers help AI understand and follow established patterns when working with generated code
|
|
541
|
+
- Use the header parameter to document the architectural decisions and best practices
|
|
542
|
+
|
|
543
|
+
Use this after generate-boilerplate or generate-feature-scaffold to create the actual template files referenced in the includes array.`,
|
|
544
|
+
inputSchema: {
|
|
545
|
+
type: "object",
|
|
546
|
+
properties,
|
|
547
|
+
required,
|
|
648
548
|
additionalProperties: false
|
|
649
549
|
}
|
|
650
550
|
};
|
|
@@ -654,7 +554,29 @@ The header helps AI understand and follow established patterns when working with
|
|
|
654
554
|
*/
|
|
655
555
|
async execute(args) {
|
|
656
556
|
try {
|
|
657
|
-
|
|
557
|
+
let { templateName } = args;
|
|
558
|
+
if (this.isMonolith && !templateName) try {
|
|
559
|
+
templateName = (await ProjectConfigResolver.resolveProjectConfig(process.cwd())).sourceTemplate;
|
|
560
|
+
} catch (error) {
|
|
561
|
+
return {
|
|
562
|
+
content: [{
|
|
563
|
+
type: "text",
|
|
564
|
+
text: `Failed to read template name from configuration: ${error instanceof Error ? error.message : String(error)}`
|
|
565
|
+
}],
|
|
566
|
+
isError: true
|
|
567
|
+
};
|
|
568
|
+
}
|
|
569
|
+
if (!templateName) return {
|
|
570
|
+
content: [{
|
|
571
|
+
type: "text",
|
|
572
|
+
text: "Missing required parameter: templateName"
|
|
573
|
+
}],
|
|
574
|
+
isError: true
|
|
575
|
+
};
|
|
576
|
+
const result = await this.boilerplateGeneratorService.createTemplateFile({
|
|
577
|
+
...args,
|
|
578
|
+
templateName
|
|
579
|
+
});
|
|
658
580
|
if (!result.success) return {
|
|
659
581
|
content: [{
|
|
660
582
|
type: "text",
|
|
@@ -692,42 +614,32 @@ The header helps AI understand and follow established patterns when working with
|
|
|
692
614
|
var GenerateBoilerplateTool = class GenerateBoilerplateTool {
|
|
693
615
|
static TOOL_NAME = "generate-boilerplate";
|
|
694
616
|
boilerplateGeneratorService;
|
|
695
|
-
|
|
617
|
+
isMonolith;
|
|
618
|
+
constructor(templatesPath, isMonolith = false) {
|
|
696
619
|
this.boilerplateGeneratorService = new BoilerplateGeneratorService(templatesPath);
|
|
620
|
+
this.isMonolith = isMonolith;
|
|
697
621
|
}
|
|
698
622
|
/**
|
|
699
623
|
* Get the tool definition for MCP
|
|
700
624
|
*/
|
|
701
625
|
getDefinition() {
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
},
|
|
720
|
-
boilerplateName: {
|
|
721
|
-
type: "string",
|
|
722
|
-
description: "Name of the boilerplate (kebab-case, e.g., \"scaffold-my-app\")"
|
|
723
|
-
},
|
|
724
|
-
targetFolder: {
|
|
725
|
-
type: "string",
|
|
726
|
-
description: "Target folder where projects will be created (e.g., \"apps\", \"packages\")"
|
|
727
|
-
},
|
|
728
|
-
description: {
|
|
729
|
-
type: "string",
|
|
730
|
-
description: `Detailed description of what this boilerplate creates and its key features.
|
|
626
|
+
const properties = {};
|
|
627
|
+
if (!this.isMonolith) properties.templateName = {
|
|
628
|
+
type: "string",
|
|
629
|
+
description: "Name of the template folder (kebab-case, e.g., \"my-framework\")"
|
|
630
|
+
};
|
|
631
|
+
Object.assign(properties, {
|
|
632
|
+
boilerplateName: {
|
|
633
|
+
type: "string",
|
|
634
|
+
description: "Name of the boilerplate (kebab-case, e.g., \"scaffold-my-app\")"
|
|
635
|
+
},
|
|
636
|
+
targetFolder: {
|
|
637
|
+
type: "string",
|
|
638
|
+
description: "Target folder where projects will be created (e.g., \"apps\", \"packages\")"
|
|
639
|
+
},
|
|
640
|
+
description: {
|
|
641
|
+
type: "string",
|
|
642
|
+
description: `Detailed description of what this boilerplate creates and its key features.
|
|
731
643
|
|
|
732
644
|
STRUCTURE (3-5 sentences in multiple paragraphs):
|
|
733
645
|
- Paragraph 1: Core technology stack and primary value proposition
|
|
@@ -738,10 +650,10 @@ Example: "A modern React SPA template powered by Vite for lightning-fast HMR, fe
|
|
|
738
650
|
Perfect for building data-driven dashboards, admin panels, and interactive web applications requiring client-side routing and real-time data synchronization.
|
|
739
651
|
|
|
740
652
|
Includes Agiflow Config Management System integration with systematic environment variable naming (VITE_{CATEGORY}_{SUBCATEGORY}_{PROPERTY}) and auto-generated configuration templates for cloud deployment."`
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
653
|
+
},
|
|
654
|
+
instruction: {
|
|
655
|
+
type: "string",
|
|
656
|
+
description: `Optional detailed instructions about the generated files, their purposes, and how to work with them.
|
|
745
657
|
|
|
746
658
|
STRUCTURE (Multi-section guide):
|
|
747
659
|
|
|
@@ -785,47 +697,47 @@ Design patterns to follow:
|
|
|
785
697
|
- Type-safe Routes: Leverage [framework] type inference for params
|
|
786
698
|
- State Management: Use [library] for server state, [library] for client state
|
|
787
699
|
[... list key patterns with explanations ...]"`
|
|
700
|
+
},
|
|
701
|
+
variables: {
|
|
702
|
+
type: "array",
|
|
703
|
+
description: "Array of variable definitions for the boilerplate",
|
|
704
|
+
items: {
|
|
705
|
+
type: "object",
|
|
706
|
+
properties: {
|
|
707
|
+
name: {
|
|
708
|
+
type: "string",
|
|
709
|
+
description: "Variable name (camelCase)"
|
|
710
|
+
},
|
|
711
|
+
description: {
|
|
712
|
+
type: "string",
|
|
713
|
+
description: "Variable description"
|
|
714
|
+
},
|
|
715
|
+
type: {
|
|
716
|
+
type: "string",
|
|
717
|
+
enum: [
|
|
718
|
+
"string",
|
|
719
|
+
"number",
|
|
720
|
+
"boolean"
|
|
721
|
+
],
|
|
722
|
+
description: "Variable type"
|
|
723
|
+
},
|
|
724
|
+
required: {
|
|
725
|
+
type: "boolean",
|
|
726
|
+
description: "Whether this variable is required"
|
|
727
|
+
},
|
|
728
|
+
default: { description: "Optional default value for the variable" }
|
|
788
729
|
},
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
description
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
type: "string",
|
|
801
|
-
description: "Variable description"
|
|
802
|
-
},
|
|
803
|
-
type: {
|
|
804
|
-
type: "string",
|
|
805
|
-
enum: [
|
|
806
|
-
"string",
|
|
807
|
-
"number",
|
|
808
|
-
"boolean"
|
|
809
|
-
],
|
|
810
|
-
description: "Variable type"
|
|
811
|
-
},
|
|
812
|
-
required: {
|
|
813
|
-
type: "boolean",
|
|
814
|
-
description: "Whether this variable is required"
|
|
815
|
-
},
|
|
816
|
-
default: { description: "Optional default value for the variable" }
|
|
817
|
-
},
|
|
818
|
-
required: [
|
|
819
|
-
"name",
|
|
820
|
-
"description",
|
|
821
|
-
"type",
|
|
822
|
-
"required"
|
|
823
|
-
]
|
|
824
|
-
}
|
|
825
|
-
},
|
|
826
|
-
includes: {
|
|
827
|
-
type: "array",
|
|
828
|
-
description: `Array of specific file paths to include in the boilerplate (highly recommended to list explicitly).
|
|
730
|
+
required: [
|
|
731
|
+
"name",
|
|
732
|
+
"description",
|
|
733
|
+
"type",
|
|
734
|
+
"required"
|
|
735
|
+
]
|
|
736
|
+
}
|
|
737
|
+
},
|
|
738
|
+
includes: {
|
|
739
|
+
type: "array",
|
|
740
|
+
description: `Array of specific file paths to include in the boilerplate (highly recommended to list explicitly).
|
|
829
741
|
|
|
830
742
|
Examples:
|
|
831
743
|
- ["package.json", "tsconfig.json", "src/index.ts"] - Explicit file list (recommended)
|
|
@@ -839,16 +751,33 @@ Best practices:
|
|
|
839
751
|
- Avoid wildcards unless you have a good reason
|
|
840
752
|
|
|
841
753
|
See templates/nextjs-15/scaffold.yaml for a good example of explicit file listing.`,
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
754
|
+
items: { type: "string" }
|
|
755
|
+
}
|
|
756
|
+
});
|
|
757
|
+
const required = [
|
|
758
|
+
"boilerplateName",
|
|
759
|
+
"description",
|
|
760
|
+
"variables"
|
|
761
|
+
];
|
|
762
|
+
if (!this.isMonolith) {
|
|
763
|
+
required.unshift("templateName");
|
|
764
|
+
required.push("targetFolder");
|
|
765
|
+
}
|
|
766
|
+
return {
|
|
767
|
+
name: GenerateBoilerplateTool.TOOL_NAME,
|
|
768
|
+
description: `Add a new boilerplate configuration to a template's scaffold.yaml file.
|
|
769
|
+
|
|
770
|
+
This tool:
|
|
771
|
+
- Creates or updates scaffold.yaml in the specified template directory
|
|
772
|
+
- Adds a boilerplate entry with proper schema following the nextjs-15 pattern
|
|
773
|
+
- Validates the boilerplate name doesn't already exist
|
|
774
|
+
- Creates the template directory if it doesn't exist
|
|
775
|
+
|
|
776
|
+
Use this to add custom boilerplate configurations for frameworks not yet supported or for your specific project needs.`,
|
|
777
|
+
inputSchema: {
|
|
778
|
+
type: "object",
|
|
779
|
+
properties,
|
|
780
|
+
required,
|
|
852
781
|
additionalProperties: false
|
|
853
782
|
}
|
|
854
783
|
};
|
|
@@ -858,7 +787,38 @@ See templates/nextjs-15/scaffold.yaml for a good example of explicit file listin
|
|
|
858
787
|
*/
|
|
859
788
|
async execute(args) {
|
|
860
789
|
try {
|
|
861
|
-
|
|
790
|
+
let { templateName, targetFolder } = args;
|
|
791
|
+
if (this.isMonolith && !templateName) try {
|
|
792
|
+
templateName = (await ProjectConfigResolver.resolveProjectConfig(process.cwd())).sourceTemplate;
|
|
793
|
+
} catch (error) {
|
|
794
|
+
return {
|
|
795
|
+
content: [{
|
|
796
|
+
type: "text",
|
|
797
|
+
text: `Failed to read template name from configuration: ${error instanceof Error ? error.message : String(error)}`
|
|
798
|
+
}],
|
|
799
|
+
isError: true
|
|
800
|
+
};
|
|
801
|
+
}
|
|
802
|
+
if (this.isMonolith && !targetFolder) targetFolder = ".";
|
|
803
|
+
if (!templateName) return {
|
|
804
|
+
content: [{
|
|
805
|
+
type: "text",
|
|
806
|
+
text: "Missing required parameter: templateName"
|
|
807
|
+
}],
|
|
808
|
+
isError: true
|
|
809
|
+
};
|
|
810
|
+
if (!targetFolder) return {
|
|
811
|
+
content: [{
|
|
812
|
+
type: "text",
|
|
813
|
+
text: "Missing required parameter: targetFolder"
|
|
814
|
+
}],
|
|
815
|
+
isError: true
|
|
816
|
+
};
|
|
817
|
+
const result = await this.boilerplateGeneratorService.generateBoilerplate({
|
|
818
|
+
...args,
|
|
819
|
+
templateName,
|
|
820
|
+
targetFolder
|
|
821
|
+
});
|
|
862
822
|
if (!result.success) return {
|
|
863
823
|
content: [{
|
|
864
824
|
type: "text",
|
|
@@ -1026,38 +986,28 @@ var ScaffoldGeneratorService = class {
|
|
|
1026
986
|
var GenerateFeatureScaffoldTool = class GenerateFeatureScaffoldTool {
|
|
1027
987
|
static TOOL_NAME = "generate-feature-scaffold";
|
|
1028
988
|
scaffoldGeneratorService;
|
|
1029
|
-
|
|
989
|
+
isMonolith;
|
|
990
|
+
constructor(templatesPath, isMonolith = false) {
|
|
1030
991
|
this.scaffoldGeneratorService = new ScaffoldGeneratorService(templatesPath);
|
|
992
|
+
this.isMonolith = isMonolith;
|
|
1031
993
|
}
|
|
1032
994
|
/**
|
|
1033
995
|
* Get the tool definition for MCP
|
|
1034
996
|
*/
|
|
1035
997
|
getDefinition() {
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
properties: {
|
|
1050
|
-
templateName: {
|
|
1051
|
-
type: "string",
|
|
1052
|
-
description: "Name of the template folder (kebab-case, e.g., \"nextjs-15\")"
|
|
1053
|
-
},
|
|
1054
|
-
featureName: {
|
|
1055
|
-
type: "string",
|
|
1056
|
-
description: "Name of the feature (kebab-case, e.g., \"scaffold-nextjs-page\")"
|
|
1057
|
-
},
|
|
1058
|
-
description: {
|
|
1059
|
-
type: "string",
|
|
1060
|
-
description: `Detailed description of what this feature creates and its key capabilities.
|
|
998
|
+
const properties = {};
|
|
999
|
+
if (!this.isMonolith) properties.templateName = {
|
|
1000
|
+
type: "string",
|
|
1001
|
+
description: "Name of the template folder (kebab-case, e.g., \"nextjs-15\")"
|
|
1002
|
+
};
|
|
1003
|
+
Object.assign(properties, {
|
|
1004
|
+
featureName: {
|
|
1005
|
+
type: "string",
|
|
1006
|
+
description: "Name of the feature (kebab-case, e.g., \"scaffold-nextjs-page\")"
|
|
1007
|
+
},
|
|
1008
|
+
description: {
|
|
1009
|
+
type: "string",
|
|
1010
|
+
description: `Detailed description of what this feature creates and its key capabilities.
|
|
1061
1011
|
|
|
1062
1012
|
STRUCTURE (2-3 sentences):
|
|
1063
1013
|
- Sentence 1: What type of code it generates (component, page, service, etc.)
|
|
@@ -1065,10 +1015,10 @@ STRUCTURE (2-3 sentences):
|
|
|
1065
1015
|
- Sentence 3: Primary use cases or when to use it
|
|
1066
1016
|
|
|
1067
1017
|
Example: "Generate a new service class for TypeScript libraries following best practices. Creates a service class with interface, implementation, and unit tests. Perfect for creating reusable service modules with dependency injection patterns."`
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1018
|
+
},
|
|
1019
|
+
instruction: {
|
|
1020
|
+
type: "string",
|
|
1021
|
+
description: `Optional detailed instructions about the generated files, their purposes, and how to work with them.
|
|
1072
1022
|
|
|
1073
1023
|
STRUCTURE (Concise multi-aspect guide):
|
|
1074
1024
|
|
|
@@ -1079,47 +1029,47 @@ STRUCTURE (Concise multi-aspect guide):
|
|
|
1079
1029
|
5. **Testing approach**: How to test the feature
|
|
1080
1030
|
|
|
1081
1031
|
Example: "Services follow a class-based pattern with optional interface separation. The service class implements business logic and can be dependency injected. Place services in src/services/ directory. For services with interfaces, define the interface in src/types/interfaces/ for better separation of concerns. Service names should be PascalCase and end with 'Service' suffix. Write comprehensive unit tests for all public methods."`
|
|
1032
|
+
},
|
|
1033
|
+
variables: {
|
|
1034
|
+
type: "array",
|
|
1035
|
+
description: "Array of variable definitions for the feature",
|
|
1036
|
+
items: {
|
|
1037
|
+
type: "object",
|
|
1038
|
+
properties: {
|
|
1039
|
+
name: {
|
|
1040
|
+
type: "string",
|
|
1041
|
+
description: "Variable name (camelCase)"
|
|
1042
|
+
},
|
|
1043
|
+
description: {
|
|
1044
|
+
type: "string",
|
|
1045
|
+
description: "Variable description"
|
|
1046
|
+
},
|
|
1047
|
+
type: {
|
|
1048
|
+
type: "string",
|
|
1049
|
+
enum: [
|
|
1050
|
+
"string",
|
|
1051
|
+
"number",
|
|
1052
|
+
"boolean"
|
|
1053
|
+
],
|
|
1054
|
+
description: "Variable type"
|
|
1055
|
+
},
|
|
1056
|
+
required: {
|
|
1057
|
+
type: "boolean",
|
|
1058
|
+
description: "Whether this variable is required"
|
|
1059
|
+
},
|
|
1060
|
+
default: { description: "Optional default value for the variable" }
|
|
1082
1061
|
},
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
description
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
type: "string",
|
|
1095
|
-
description: "Variable description"
|
|
1096
|
-
},
|
|
1097
|
-
type: {
|
|
1098
|
-
type: "string",
|
|
1099
|
-
enum: [
|
|
1100
|
-
"string",
|
|
1101
|
-
"number",
|
|
1102
|
-
"boolean"
|
|
1103
|
-
],
|
|
1104
|
-
description: "Variable type"
|
|
1105
|
-
},
|
|
1106
|
-
required: {
|
|
1107
|
-
type: "boolean",
|
|
1108
|
-
description: "Whether this variable is required"
|
|
1109
|
-
},
|
|
1110
|
-
default: { description: "Optional default value for the variable" }
|
|
1111
|
-
},
|
|
1112
|
-
required: [
|
|
1113
|
-
"name",
|
|
1114
|
-
"description",
|
|
1115
|
-
"type",
|
|
1116
|
-
"required"
|
|
1117
|
-
]
|
|
1118
|
-
}
|
|
1119
|
-
},
|
|
1120
|
-
includes: {
|
|
1121
|
-
type: "array",
|
|
1122
|
-
description: `Array of specific file paths to include in the feature (highly recommended to list explicitly).
|
|
1062
|
+
required: [
|
|
1063
|
+
"name",
|
|
1064
|
+
"description",
|
|
1065
|
+
"type",
|
|
1066
|
+
"required"
|
|
1067
|
+
]
|
|
1068
|
+
}
|
|
1069
|
+
},
|
|
1070
|
+
includes: {
|
|
1071
|
+
type: "array",
|
|
1072
|
+
description: `Array of specific file paths to include in the feature (highly recommended to list explicitly).
|
|
1123
1073
|
|
|
1124
1074
|
Supports advanced syntax:
|
|
1125
1075
|
- Basic: "src/app/page/page.tsx" - Always included
|
|
@@ -1140,11 +1090,11 @@ Best practices:
|
|
|
1140
1090
|
- Use path mapping with -> when source and target paths differ
|
|
1141
1091
|
- Use {{ variableName }} in target paths for dynamic file placement
|
|
1142
1092
|
- Avoid wildcards unless you have a good reason`,
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1093
|
+
items: { type: "string" }
|
|
1094
|
+
},
|
|
1095
|
+
patterns: {
|
|
1096
|
+
type: "array",
|
|
1097
|
+
description: `Optional array of glob patterns to match existing files that this feature works with.
|
|
1148
1098
|
|
|
1149
1099
|
Used to help identify where this feature can be applied in a project.
|
|
1150
1100
|
|
|
@@ -1157,15 +1107,30 @@ Best practices:
|
|
|
1157
1107
|
- Use glob patterns that match the file types this feature works with
|
|
1158
1108
|
- Keep patterns specific enough to be meaningful but broad enough to be useful
|
|
1159
1109
|
- Consider both the feature's output and input files`,
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1110
|
+
items: { type: "string" }
|
|
1111
|
+
}
|
|
1112
|
+
});
|
|
1113
|
+
const required = [
|
|
1114
|
+
"featureName",
|
|
1115
|
+
"description",
|
|
1116
|
+
"variables"
|
|
1117
|
+
];
|
|
1118
|
+
if (!this.isMonolith) required.unshift("templateName");
|
|
1119
|
+
return {
|
|
1120
|
+
name: GenerateFeatureScaffoldTool.TOOL_NAME,
|
|
1121
|
+
description: `Add a new feature scaffold configuration to a template's scaffold.yaml file.
|
|
1122
|
+
|
|
1123
|
+
This tool:
|
|
1124
|
+
- Creates or updates scaffold.yaml in the specified template directory
|
|
1125
|
+
- Adds a feature entry with proper schema following the nextjs-15 pattern
|
|
1126
|
+
- Validates the feature name doesn't already exist
|
|
1127
|
+
- Creates the template directory if it doesn't exist
|
|
1128
|
+
|
|
1129
|
+
Use this to add custom feature scaffolds (pages, components, services, etc.) for frameworks not yet supported or for your specific project needs.`,
|
|
1130
|
+
inputSchema: {
|
|
1131
|
+
type: "object",
|
|
1132
|
+
properties,
|
|
1133
|
+
required,
|
|
1169
1134
|
additionalProperties: false
|
|
1170
1135
|
}
|
|
1171
1136
|
};
|
|
@@ -1175,7 +1140,29 @@ Best practices:
|
|
|
1175
1140
|
*/
|
|
1176
1141
|
async execute(args) {
|
|
1177
1142
|
try {
|
|
1178
|
-
|
|
1143
|
+
let { templateName } = args;
|
|
1144
|
+
if (this.isMonolith && !templateName) try {
|
|
1145
|
+
templateName = (await ProjectConfigResolver.resolveProjectConfig(process.cwd())).sourceTemplate;
|
|
1146
|
+
} catch (error) {
|
|
1147
|
+
return {
|
|
1148
|
+
content: [{
|
|
1149
|
+
type: "text",
|
|
1150
|
+
text: `Failed to read template name from configuration: ${error instanceof Error ? error.message : String(error)}`
|
|
1151
|
+
}],
|
|
1152
|
+
isError: true
|
|
1153
|
+
};
|
|
1154
|
+
}
|
|
1155
|
+
if (!templateName) return {
|
|
1156
|
+
content: [{
|
|
1157
|
+
type: "text",
|
|
1158
|
+
text: "Missing required parameter: templateName"
|
|
1159
|
+
}],
|
|
1160
|
+
isError: true
|
|
1161
|
+
};
|
|
1162
|
+
const result = await this.scaffoldGeneratorService.generateFeatureScaffold({
|
|
1163
|
+
...args,
|
|
1164
|
+
templateName
|
|
1165
|
+
});
|
|
1179
1166
|
if (!result.success) return {
|
|
1180
1167
|
content: [{
|
|
1181
1168
|
type: "text",
|
|
@@ -1210,29 +1197,30 @@ Best practices:
|
|
|
1210
1197
|
}
|
|
1211
1198
|
};
|
|
1212
1199
|
|
|
1200
|
+
//#endregion
|
|
1201
|
+
//#region src/instructions/tools/list-boilerplates/description.md?raw
|
|
1202
|
+
var description_default$2 = "{% if isMonolith %}\nNot available for monolith projects. Monolith uses a single template defined in `toolkit.yaml`.\n\nUse `list-scaffolding-methods` for available features instead.\n{% else %}\nLists all available project boilerplates for creating new applications, APIs, or packages in the monorepo.\n\nEach boilerplate includes:\n- Complete project template with starter files\n- Variable schema for customization\n- Target directory information (e.g., apps/, packages/)\n- Required and optional configuration options\n\nUse this FIRST when creating new projects to understand available templates and their requirements.\n{% endif %}\n";
|
|
1203
|
+
|
|
1213
1204
|
//#endregion
|
|
1214
1205
|
//#region src/tools/ListBoilerplatesTool.ts
|
|
1215
1206
|
var ListBoilerplatesTool = class ListBoilerplatesTool {
|
|
1216
1207
|
static TOOL_NAME = "list-boilerplates";
|
|
1217
1208
|
boilerplateService;
|
|
1218
|
-
|
|
1209
|
+
templateService;
|
|
1210
|
+
isMonolith;
|
|
1211
|
+
constructor(templatesPath, isMonolith = false) {
|
|
1219
1212
|
this.boilerplateService = new BoilerplateService(templatesPath);
|
|
1213
|
+
this.templateService = new TemplateService();
|
|
1214
|
+
this.isMonolith = isMonolith;
|
|
1220
1215
|
}
|
|
1221
1216
|
/**
|
|
1222
1217
|
* Get the tool definition for MCP
|
|
1223
1218
|
*/
|
|
1224
1219
|
getDefinition() {
|
|
1220
|
+
const description = this.templateService.renderString(description_default$2, { isMonolith: this.isMonolith });
|
|
1225
1221
|
return {
|
|
1226
1222
|
name: ListBoilerplatesTool.TOOL_NAME,
|
|
1227
|
-
description:
|
|
1228
|
-
|
|
1229
|
-
Each boilerplate includes:
|
|
1230
|
-
- Complete project template with starter files
|
|
1231
|
-
- Variable schema for customization
|
|
1232
|
-
- Target directory information
|
|
1233
|
-
- Required and optional configuration options
|
|
1234
|
-
|
|
1235
|
-
Use this FIRST when creating new projects to understand available templates and their requirements.`,
|
|
1223
|
+
description: description.trim(),
|
|
1236
1224
|
inputSchema: {
|
|
1237
1225
|
type: "object",
|
|
1238
1226
|
properties: {},
|
|
@@ -1262,6 +1250,10 @@ Use this FIRST when creating new projects to understand available templates and
|
|
|
1262
1250
|
}
|
|
1263
1251
|
};
|
|
1264
1252
|
|
|
1253
|
+
//#endregion
|
|
1254
|
+
//#region src/instructions/tools/list-scaffolding-methods/description.md?raw
|
|
1255
|
+
var description_default$1 = "Lists all available scaffolding methods (features) that can be added to an existing project{% if not isMonolith %} or for a specific template{% endif %}.\n\nThis tool:\n{% if isMonolith %}\n- Reads your project's sourceTemplate from toolkit.yaml at workspace root\n{% else %}\n- Reads the project's sourceTemplate from project.json (monorepo) or toolkit.yaml (monolith), OR\n- Directly uses the provided templateName to list available features\n{% endif %}\n- Returns available features for that template type\n- Provides variable schemas for each scaffolding method\n- Shows descriptions of what each method creates\n\nUse this FIRST when adding features to understand:\n- What scaffolding methods are available\n- What variables each method requires\n- What files/features will be generated\n\nExample methods might include:\n- Adding new React routes (for React apps)\n- Creating API endpoints (for backend projects)\n- Adding new components (for frontend projects)\n- Setting up database models (for API projects)\n";
|
|
1256
|
+
|
|
1265
1257
|
//#endregion
|
|
1266
1258
|
//#region src/services/ScaffoldingMethodsService.ts
|
|
1267
1259
|
var ScaffoldingMethodsService = class {
|
|
@@ -1274,8 +1266,11 @@ var ScaffoldingMethodsService = class {
|
|
|
1274
1266
|
async listScaffoldingMethods(projectPath) {
|
|
1275
1267
|
const absoluteProjectPath = path.resolve(projectPath);
|
|
1276
1268
|
const sourceTemplate = (await ProjectConfigResolver.resolveProjectConfig(absoluteProjectPath)).sourceTemplate;
|
|
1277
|
-
|
|
1278
|
-
|
|
1269
|
+
return this.listScaffoldingMethodsByTemplate(sourceTemplate);
|
|
1270
|
+
}
|
|
1271
|
+
async listScaffoldingMethodsByTemplate(templateName) {
|
|
1272
|
+
const templatePath = await this.findTemplatePath(templateName);
|
|
1273
|
+
if (!templatePath) throw new Error(`Template not found for sourceTemplate: ${templateName}`);
|
|
1279
1274
|
const fullTemplatePath = path.join(this.templatesRootPath, templatePath);
|
|
1280
1275
|
const scaffoldYamlPath = path.join(fullTemplatePath, "scaffold.yaml");
|
|
1281
1276
|
if (!await this.fileSystem.pathExists(scaffoldYamlPath)) throw new Error(`scaffold.yaml not found at ${scaffoldYamlPath}`);
|
|
@@ -1283,8 +1278,9 @@ var ScaffoldingMethodsService = class {
|
|
|
1283
1278
|
const architectConfig = yaml.load(scaffoldContent);
|
|
1284
1279
|
const methods = [];
|
|
1285
1280
|
if (architectConfig.features && Array.isArray(architectConfig.features)) architectConfig.features.forEach((feature) => {
|
|
1286
|
-
|
|
1287
|
-
|
|
1281
|
+
const featureName = feature.name || `scaffold-${templateName}`;
|
|
1282
|
+
methods.push({
|
|
1283
|
+
name: featureName,
|
|
1288
1284
|
description: feature.description || "",
|
|
1289
1285
|
instruction: feature.instruction || "",
|
|
1290
1286
|
variables_schema: feature.variables_schema || {
|
|
@@ -1297,7 +1293,7 @@ var ScaffoldingMethodsService = class {
|
|
|
1297
1293
|
});
|
|
1298
1294
|
});
|
|
1299
1295
|
return {
|
|
1300
|
-
sourceTemplate,
|
|
1296
|
+
sourceTemplate: templateName,
|
|
1301
1297
|
templatePath,
|
|
1302
1298
|
methods
|
|
1303
1299
|
};
|
|
@@ -1342,6 +1338,14 @@ var ScaffoldingMethodsService = class {
|
|
|
1342
1338
|
return null;
|
|
1343
1339
|
}
|
|
1344
1340
|
/**
|
|
1341
|
+
* Resolves the project path, handling both monorepo and monolith cases
|
|
1342
|
+
* Uses ProjectConfigResolver to find the correct workspace/project root
|
|
1343
|
+
*/
|
|
1344
|
+
async resolveProjectPath(projectPath) {
|
|
1345
|
+
const absolutePath = path.resolve(projectPath);
|
|
1346
|
+
return (await ProjectConfigResolver.resolveProjectConfig(absolutePath)).workspaceRoot || absolutePath;
|
|
1347
|
+
}
|
|
1348
|
+
/**
|
|
1345
1349
|
* Dynamically discovers all template directories
|
|
1346
1350
|
* Supports both flat structure (templates/nextjs-15) and nested structure (templates/apps/nextjs-15)
|
|
1347
1351
|
**/
|
|
@@ -1379,21 +1383,21 @@ var ScaffoldingMethodsService = class {
|
|
|
1379
1383
|
}
|
|
1380
1384
|
async useScaffoldMethod(request) {
|
|
1381
1385
|
const { projectPath, scaffold_feature_name, variables } = request;
|
|
1382
|
-
const
|
|
1386
|
+
const absoluteProjectPath = await this.resolveProjectPath(projectPath);
|
|
1387
|
+
const scaffoldingMethods = await this.listScaffoldingMethods(absoluteProjectPath);
|
|
1383
1388
|
const method = scaffoldingMethods.methods.find((m) => m.name === scaffold_feature_name);
|
|
1384
1389
|
if (!method) {
|
|
1385
1390
|
const availableMethods = scaffoldingMethods.methods.map((m) => m.name).join(", ");
|
|
1386
1391
|
throw new Error(`Scaffold method '${scaffold_feature_name}' not found. Available methods: ${availableMethods}`);
|
|
1387
1392
|
}
|
|
1388
|
-
const ScaffoldService$1 = (await import("./ScaffoldService-
|
|
1393
|
+
const ScaffoldService$1 = (await import("./ScaffoldService-CJ3vNmAj.js")).ScaffoldService;
|
|
1389
1394
|
const ScaffoldConfigLoader$1 = (await import("./ScaffoldConfigLoader-DhthV6xq.js")).ScaffoldConfigLoader;
|
|
1390
|
-
const VariableReplacementService$1 = (await import("./VariableReplacementService-
|
|
1395
|
+
const VariableReplacementService$1 = (await import("./VariableReplacementService-BAwTGv_R.js")).VariableReplacementService;
|
|
1391
1396
|
const TemplateService$1 = (await import("./TemplateService-DropYdp8.js")).TemplateService;
|
|
1392
1397
|
const templateService = new TemplateService$1();
|
|
1393
1398
|
const scaffoldConfigLoader = new ScaffoldConfigLoader$1(this.fileSystem, templateService);
|
|
1394
1399
|
const variableReplacer = new VariableReplacementService$1(this.fileSystem, templateService);
|
|
1395
1400
|
const scaffoldService = new ScaffoldService$1(this.fileSystem, scaffoldConfigLoader, variableReplacer, this.templatesRootPath);
|
|
1396
|
-
const absoluteProjectPath = path.resolve(projectPath);
|
|
1397
1401
|
const projectName = path.basename(absoluteProjectPath);
|
|
1398
1402
|
const result = await scaffoldService.useFeature({
|
|
1399
1403
|
projectPath: absoluteProjectPath,
|
|
@@ -1426,41 +1430,36 @@ var ListScaffoldingMethodsTool = class ListScaffoldingMethodsTool {
|
|
|
1426
1430
|
static TOOL_NAME = "list-scaffolding-methods";
|
|
1427
1431
|
fileSystemService;
|
|
1428
1432
|
scaffoldingMethodsService;
|
|
1429
|
-
|
|
1433
|
+
templateService;
|
|
1434
|
+
isMonolith;
|
|
1435
|
+
constructor(templatesPath, isMonolith = false) {
|
|
1430
1436
|
this.fileSystemService = new FileSystemService();
|
|
1431
1437
|
this.scaffoldingMethodsService = new ScaffoldingMethodsService(this.fileSystemService, templatesPath);
|
|
1438
|
+
this.templateService = new TemplateService();
|
|
1439
|
+
this.isMonolith = isMonolith;
|
|
1432
1440
|
}
|
|
1433
1441
|
/**
|
|
1434
1442
|
* Get the tool definition for MCP
|
|
1435
1443
|
*/
|
|
1436
1444
|
getDefinition() {
|
|
1445
|
+
const description = this.templateService.renderString(description_default$1, { isMonolith: this.isMonolith });
|
|
1446
|
+
const properties = {};
|
|
1447
|
+
if (!this.isMonolith) {
|
|
1448
|
+
properties.projectPath = {
|
|
1449
|
+
type: "string",
|
|
1450
|
+
description: "Absolute path to the project directory (for monorepo: containing project.json; for monolith: workspace root with toolkit.yaml). Either projectPath or templateName is required."
|
|
1451
|
+
};
|
|
1452
|
+
properties.templateName = {
|
|
1453
|
+
type: "string",
|
|
1454
|
+
description: "Name of the template to list scaffolding methods for (e.g., \"nextjs-15\", \"typescript-mcp-package\"). Either projectPath or templateName is required."
|
|
1455
|
+
};
|
|
1456
|
+
}
|
|
1437
1457
|
return {
|
|
1438
1458
|
name: ListScaffoldingMethodsTool.TOOL_NAME,
|
|
1439
|
-
description:
|
|
1440
|
-
|
|
1441
|
-
This tool:
|
|
1442
|
-
- Reads the project's sourceTemplate from project.json (monorepo) or toolkit.yaml (monolith)
|
|
1443
|
-
- Returns available features for that template type
|
|
1444
|
-
- Provides variable schemas for each scaffolding method
|
|
1445
|
-
- Shows descriptions of what each method creates
|
|
1446
|
-
|
|
1447
|
-
Use this FIRST when adding features to existing projects to understand:
|
|
1448
|
-
- What scaffolding methods are available
|
|
1449
|
-
- What variables each method requires
|
|
1450
|
-
- What files/features will be generated
|
|
1451
|
-
|
|
1452
|
-
Example methods might include:
|
|
1453
|
-
- Adding new React routes (for React apps)
|
|
1454
|
-
- Creating API endpoints (for backend projects)
|
|
1455
|
-
- Adding new components (for frontend projects)
|
|
1456
|
-
- Setting up database models (for API projects)`,
|
|
1459
|
+
description: description.trim(),
|
|
1457
1460
|
inputSchema: {
|
|
1458
1461
|
type: "object",
|
|
1459
|
-
properties
|
|
1460
|
-
type: "string",
|
|
1461
|
-
description: "Absolute path to the project directory (for monorepo: containing project.json; for monolith: workspace root with toolkit.yaml)"
|
|
1462
|
-
} },
|
|
1463
|
-
required: ["projectPath"],
|
|
1462
|
+
properties,
|
|
1464
1463
|
additionalProperties: false
|
|
1465
1464
|
}
|
|
1466
1465
|
};
|
|
@@ -1470,9 +1469,19 @@ Example methods might include:
|
|
|
1470
1469
|
*/
|
|
1471
1470
|
async execute(args) {
|
|
1472
1471
|
try {
|
|
1473
|
-
const { projectPath } = args;
|
|
1474
|
-
|
|
1475
|
-
|
|
1472
|
+
const { projectPath, templateName } = args;
|
|
1473
|
+
let result;
|
|
1474
|
+
if (this.isMonolith) try {
|
|
1475
|
+
const resolvedTemplateName = (await ProjectConfigResolver.resolveProjectConfig(process.cwd())).sourceTemplate;
|
|
1476
|
+
result = await this.scaffoldingMethodsService.listScaffoldingMethodsByTemplate(resolvedTemplateName);
|
|
1477
|
+
} catch (error) {
|
|
1478
|
+
throw new Error(`Failed to read template name from configuration: ${error instanceof Error ? error.message : String(error)}`);
|
|
1479
|
+
}
|
|
1480
|
+
else {
|
|
1481
|
+
if (!projectPath && !templateName) throw new Error("Either projectPath or templateName must be provided");
|
|
1482
|
+
if (projectPath) result = await this.scaffoldingMethodsService.listScaffoldingMethods(projectPath);
|
|
1483
|
+
else result = await this.scaffoldingMethodsService.listScaffoldingMethodsByTemplate(templateName);
|
|
1484
|
+
}
|
|
1476
1485
|
return { content: [{
|
|
1477
1486
|
type: "text",
|
|
1478
1487
|
text: JSON.stringify(result, null, 2)
|
|
@@ -1489,57 +1498,48 @@ Example methods might include:
|
|
|
1489
1498
|
}
|
|
1490
1499
|
};
|
|
1491
1500
|
|
|
1501
|
+
//#endregion
|
|
1502
|
+
//#region src/instructions/tools/use-boilerplate/description.md?raw
|
|
1503
|
+
var description_default = "{% if isMonolith %}\nThis tool is not available for monolith projects.\n\nMonolith projects use a single template specified in `toolkit.yaml` (sourceTemplate field). The template cannot be changed through this tool - it's determined by the workspace configuration.\n\nUse `list-scaffolding-methods` and `use-scaffold-method` to add features to your monolith project instead.\n{% else %}\nCreates a new project from a boilerplate template with the specified variables.\n\n**For Monorepo Projects Only:**\nThis tool creates new sub-projects (apps, packages) in your monorepo. Each project can use a different template.\n\nThis tool will:\n- Generate all necessary files from the selected boilerplate template\n- Replace template variables with provided values\n- Create the project in targetFolder/projectName (e.g., apps/my-new-app)\n- Set up initial configuration files (package.json, tsconfig.json, etc.)\n- Create project.json with sourceTemplate reference\n\nIMPORTANT:\n- Always call `list-boilerplates` first to get the exact variable schema\n- Follow the schema exactly - required fields must be provided\n- Use kebab-case for project names (e.g., \"my-new-app\", not \"MyNewApp\")\n- The tool will validate all variables against the schema before proceeding\n- Each new project can use a different boilerplate template\n{% endif %}\n";
|
|
1504
|
+
|
|
1492
1505
|
//#endregion
|
|
1493
1506
|
//#region src/tools/UseBoilerplateTool.ts
|
|
1494
1507
|
var UseBoilerplateTool = class UseBoilerplateTool {
|
|
1495
1508
|
static TOOL_NAME = "use-boilerplate";
|
|
1496
1509
|
boilerplateService;
|
|
1497
|
-
|
|
1510
|
+
templateService;
|
|
1511
|
+
isMonolith;
|
|
1512
|
+
constructor(templatesPath, isMonolith = false) {
|
|
1498
1513
|
this.boilerplateService = new BoilerplateService(templatesPath);
|
|
1514
|
+
this.templateService = new TemplateService();
|
|
1515
|
+
this.isMonolith = isMonolith;
|
|
1499
1516
|
}
|
|
1500
1517
|
/**
|
|
1501
1518
|
* Get the tool definition for MCP
|
|
1502
1519
|
*/
|
|
1503
1520
|
getDefinition() {
|
|
1521
|
+
const description = this.templateService.renderString(description_default, { isMonolith: this.isMonolith });
|
|
1522
|
+
const properties = { variables: {
|
|
1523
|
+
type: "object",
|
|
1524
|
+
description: "Variables object matching the boilerplate's variables_schema exactly"
|
|
1525
|
+
} };
|
|
1526
|
+
if (!this.isMonolith) {
|
|
1527
|
+
properties.boilerplateName = {
|
|
1528
|
+
type: "string",
|
|
1529
|
+
description: "Exact name of the boilerplate to use (from list-boilerplates response)"
|
|
1530
|
+
};
|
|
1531
|
+
properties.targetFolderOverride = {
|
|
1532
|
+
type: "string",
|
|
1533
|
+
description: "Optional override for target folder. If not provided, uses boilerplate targetFolder (monorepo) or workspace root (monolith)"
|
|
1534
|
+
};
|
|
1535
|
+
}
|
|
1504
1536
|
return {
|
|
1505
1537
|
name: UseBoilerplateTool.TOOL_NAME,
|
|
1506
|
-
description:
|
|
1507
|
-
|
|
1508
|
-
This tool will:
|
|
1509
|
-
- Generate all necessary files from the template
|
|
1510
|
-
- Replace template variables with provided values
|
|
1511
|
-
- Create the project in the appropriate directory (monorepo or monolith)
|
|
1512
|
-
- Set up initial configuration files (package.json, tsconfig.json, etc.)
|
|
1513
|
-
- Create toolkit.yaml (monolith) or project.json (monorepo) with sourceTemplate
|
|
1514
|
-
|
|
1515
|
-
IMPORTANT:
|
|
1516
|
-
- Always call \`list-boilerplates\` first to get the exact variable schema
|
|
1517
|
-
- Follow the schema exactly - required fields must be provided
|
|
1518
|
-
- Use kebab-case for project names (e.g., "my-new-app", not "MyNewApp")
|
|
1519
|
-
- The tool will validate all variables against the schema before proceeding
|
|
1520
|
-
- For monolith projects, use monolith: true to create at workspace root
|
|
1521
|
-
- For monorepo projects, files are created in targetFolder/projectName`,
|
|
1538
|
+
description: description.trim(),
|
|
1522
1539
|
inputSchema: {
|
|
1523
1540
|
type: "object",
|
|
1524
|
-
properties
|
|
1525
|
-
|
|
1526
|
-
type: "string",
|
|
1527
|
-
description: "Exact name of the boilerplate to use (from list-boilerplates response)"
|
|
1528
|
-
},
|
|
1529
|
-
variables: {
|
|
1530
|
-
type: "object",
|
|
1531
|
-
description: "Variables object matching the boilerplate's variables_schema exactly"
|
|
1532
|
-
},
|
|
1533
|
-
monolith: {
|
|
1534
|
-
type: "boolean",
|
|
1535
|
-
description: "If true, creates project at workspace root with toolkit.yaml. If false or omitted, creates in targetFolder/projectName with project.json (monorepo mode)"
|
|
1536
|
-
},
|
|
1537
|
-
targetFolderOverride: {
|
|
1538
|
-
type: "string",
|
|
1539
|
-
description: "Optional override for target folder. If not provided, uses boilerplate targetFolder (monorepo) or workspace root (monolith)"
|
|
1540
|
-
}
|
|
1541
|
-
},
|
|
1542
|
-
required: ["boilerplateName", "variables"],
|
|
1541
|
+
properties,
|
|
1542
|
+
required: this.isMonolith ? ["variables"] : ["boilerplateName", "variables"],
|
|
1543
1543
|
additionalProperties: false
|
|
1544
1544
|
}
|
|
1545
1545
|
};
|
|
@@ -1549,14 +1549,12 @@ IMPORTANT:
|
|
|
1549
1549
|
*/
|
|
1550
1550
|
async execute(args) {
|
|
1551
1551
|
try {
|
|
1552
|
-
const { boilerplateName, variables,
|
|
1553
|
-
if (!boilerplateName) throw new Error("Missing required parameter: boilerplateName");
|
|
1554
|
-
if (!variables) throw new Error("Missing required parameter: variables");
|
|
1552
|
+
const { boilerplateName, variables, targetFolderOverride } = args;
|
|
1555
1553
|
const request = {
|
|
1556
1554
|
boilerplateName,
|
|
1557
1555
|
variables,
|
|
1558
|
-
|
|
1559
|
-
|
|
1556
|
+
targetFolderOverride,
|
|
1557
|
+
monolith: this.isMonolith
|
|
1560
1558
|
};
|
|
1561
1559
|
return { content: [{
|
|
1562
1560
|
type: "text",
|
|
@@ -1589,14 +1587,30 @@ var UseScaffoldMethodTool = class UseScaffoldMethodTool {
|
|
|
1589
1587
|
static TOOL_NAME = "use-scaffold-method";
|
|
1590
1588
|
fileSystemService;
|
|
1591
1589
|
scaffoldingMethodsService;
|
|
1592
|
-
|
|
1590
|
+
isMonolith;
|
|
1591
|
+
constructor(templatesPath, isMonolith = false) {
|
|
1593
1592
|
this.fileSystemService = new FileSystemService();
|
|
1594
1593
|
this.scaffoldingMethodsService = new ScaffoldingMethodsService(this.fileSystemService, templatesPath);
|
|
1594
|
+
this.isMonolith = isMonolith;
|
|
1595
1595
|
}
|
|
1596
1596
|
/**
|
|
1597
1597
|
* Get the tool definition for MCP
|
|
1598
1598
|
*/
|
|
1599
1599
|
getDefinition() {
|
|
1600
|
+
const properties = {
|
|
1601
|
+
scaffold_feature_name: {
|
|
1602
|
+
type: "string",
|
|
1603
|
+
description: "Exact name of the scaffold method to use (from list-scaffolding-methods response)"
|
|
1604
|
+
},
|
|
1605
|
+
variables: {
|
|
1606
|
+
type: "object",
|
|
1607
|
+
description: "Variables object matching the scaffold method's variables_schema exactly"
|
|
1608
|
+
}
|
|
1609
|
+
};
|
|
1610
|
+
if (!this.isMonolith) properties.projectPath = {
|
|
1611
|
+
type: "string",
|
|
1612
|
+
description: "Absolute path to the project directory (for monorepo: containing project.json; for monolith: workspace root with toolkit.yaml)"
|
|
1613
|
+
};
|
|
1600
1614
|
return {
|
|
1601
1615
|
name: UseScaffoldMethodTool.TOOL_NAME,
|
|
1602
1616
|
description: `Generates and adds a specific feature to an existing project using a scaffolding method.
|
|
@@ -1616,21 +1630,8 @@ IMPORTANT:
|
|
|
1616
1630
|
`,
|
|
1617
1631
|
inputSchema: {
|
|
1618
1632
|
type: "object",
|
|
1619
|
-
properties
|
|
1620
|
-
|
|
1621
|
-
type: "string",
|
|
1622
|
-
description: "Absolute path to the project directory (for monorepo: containing project.json; for monolith: workspace root with toolkit.yaml)"
|
|
1623
|
-
},
|
|
1624
|
-
scaffold_feature_name: {
|
|
1625
|
-
type: "string",
|
|
1626
|
-
description: "Exact name of the scaffold method to use (from list-scaffolding-methods response)"
|
|
1627
|
-
},
|
|
1628
|
-
variables: {
|
|
1629
|
-
type: "object",
|
|
1630
|
-
description: "Variables object matching the scaffold method's variables_schema exactly"
|
|
1631
|
-
}
|
|
1632
|
-
},
|
|
1633
|
-
required: [
|
|
1633
|
+
properties,
|
|
1634
|
+
required: this.isMonolith ? ["scaffold_feature_name", "variables"] : [
|
|
1634
1635
|
"projectPath",
|
|
1635
1636
|
"scaffold_feature_name",
|
|
1636
1637
|
"variables"
|
|
@@ -1645,13 +1646,11 @@ IMPORTANT:
|
|
|
1645
1646
|
async execute(args) {
|
|
1646
1647
|
try {
|
|
1647
1648
|
const { projectPath, scaffold_feature_name, variables } = args;
|
|
1648
|
-
|
|
1649
|
-
if (!scaffold_feature_name) throw new Error("Missing required parameter: scaffold_feature_name");
|
|
1650
|
-
if (!variables) throw new Error("Missing required parameter: variables");
|
|
1649
|
+
const resolvedProjectPath = this.isMonolith ? process.cwd() : projectPath;
|
|
1651
1650
|
return { content: [{
|
|
1652
1651
|
type: "text",
|
|
1653
1652
|
text: `${(await this.scaffoldingMethodsService.useScaffoldMethod({
|
|
1654
|
-
projectPath,
|
|
1653
|
+
projectPath: resolvedProjectPath,
|
|
1655
1654
|
scaffold_feature_name,
|
|
1656
1655
|
variables
|
|
1657
1656
|
})).message}
|
|
@@ -2071,4 +2070,4 @@ var StdioTransportHandler = class {
|
|
|
2071
2070
|
};
|
|
2072
2071
|
|
|
2073
2072
|
//#endregion
|
|
2074
|
-
export { BoilerplateGeneratorService, BoilerplateService, FileSystemService, GenerateBoilerplateFileTool, GenerateBoilerplateTool, GenerateFeatureScaffoldTool, HttpTransportHandler, ListBoilerplatesTool, ListScaffoldingMethodsTool, ScaffoldGeneratorService, ScaffoldingMethodsService, SseTransportHandler, StdioTransportHandler, UseBoilerplateTool, UseScaffoldMethodTool, WriteToFileTool
|
|
2073
|
+
export { BoilerplateGeneratorService, BoilerplateService, FileSystemService, GenerateBoilerplateFileTool, GenerateBoilerplateTool, GenerateFeatureScaffoldTool, HttpTransportHandler, ListBoilerplatesTool, ListScaffoldingMethodsTool, ScaffoldGeneratorService, ScaffoldingMethodsService, SseTransportHandler, StdioTransportHandler, UseBoilerplateTool, UseScaffoldMethodTool, WriteToFileTool };
|