@agiflowai/scaffold-mcp 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ScaffoldConfigLoader-DQMCLVGD.cjs → ScaffoldConfigLoader-B-NLy6VP.cjs} +1 -1
- package/dist/{ScaffoldConfigLoader-CI0T6zdG.js → ScaffoldConfigLoader-BDMJNI1o.mjs} +1 -1
- package/dist/ScaffoldConfigLoader-SHk-KEje.mjs +3 -0
- package/dist/{ScaffoldConfigLoader-BrmvENTo.cjs → ScaffoldConfigLoader-Y_SBLPg7.cjs} +0 -1
- package/dist/ScaffoldService-BNOyoqSb.cjs +3 -0
- package/dist/ScaffoldService-BNdfC21Z.mjs +3 -0
- package/dist/{ScaffoldService-DB7-Cyod.js → ScaffoldService-BNuN00Fm.mjs} +8 -8
- package/dist/{ScaffoldService-BwDmXt83.cjs → ScaffoldService-ChzxM0Yc.cjs} +1 -3
- package/dist/TemplateService-BRfzfaZs.mjs +3 -0
- package/dist/{TemplateService-CiZJA06s.js → TemplateService-Cg5QV29n.mjs} +1 -1
- package/dist/{TemplateService-DRubcvS9.cjs → TemplateService-D3ydJR_R.cjs} +0 -2
- package/dist/TemplateService-DqieT1Tq.cjs +3 -0
- package/dist/VariableReplacementService-BWCd-z7X.mjs +3 -0
- package/dist/{VariableReplacementService-D0QnWKUW.cjs → VariableReplacementService-CAjesAYq.cjs} +1 -2
- package/dist/{VariableReplacementService-DRxd9ILB.js → VariableReplacementService-DHIINRnJ.mjs} +5 -5
- package/dist/{VariableReplacementService-CroHkMha.cjs → VariableReplacementService-DKaF2C9l.cjs} +1 -1
- package/dist/cli.cjs +74 -138
- package/dist/{cli.js → cli.mjs} +74 -134
- package/dist/index.cjs +14 -18
- package/dist/index.d.cts +20 -6
- package/dist/{index.d.ts → index.d.mts} +21 -7
- package/dist/{index.js → index.mjs} +14 -16
- package/dist/{stdio-TGsG8akc.cjs → stdio-BGj_FLky.cjs} +471 -414
- package/dist/{stdio-Bxn4A1IU.js → stdio-wAlpLC6l.mjs} +474 -409
- package/package.json +6 -8
- package/dist/ScaffoldConfigLoader-DhthV6xq.js +0 -3
- package/dist/ScaffoldService-B3En_m4t.cjs +0 -3
- package/dist/ScaffoldService-CJ3vNmAj.js +0 -3
- package/dist/TemplateService-BZRt3NI8.cjs +0 -3
- package/dist/TemplateService-DropYdp8.js +0 -3
- package/dist/VariableReplacementService-BAwTGv_R.js +0 -3
- /package/dist/{cli.d.ts → cli.d.mts} +0 -0
|
@@ -1,58 +1,258 @@
|
|
|
1
1
|
const require_chunk = require('./chunk-CUT6urMc.cjs');
|
|
2
|
-
const require_ScaffoldConfigLoader = require('./ScaffoldConfigLoader-
|
|
3
|
-
const require_ScaffoldService = require('./ScaffoldService-
|
|
4
|
-
const require_TemplateService = require('./TemplateService-
|
|
5
|
-
const require_VariableReplacementService = require('./VariableReplacementService-
|
|
6
|
-
let __agiflowai_aicode_utils = require("@agiflowai/aicode-utils");
|
|
7
|
-
__agiflowai_aicode_utils = require_chunk.__toESM(__agiflowai_aicode_utils);
|
|
2
|
+
const require_ScaffoldConfigLoader = require('./ScaffoldConfigLoader-Y_SBLPg7.cjs');
|
|
3
|
+
const require_ScaffoldService = require('./ScaffoldService-ChzxM0Yc.cjs');
|
|
4
|
+
const require_TemplateService = require('./TemplateService-D3ydJR_R.cjs');
|
|
5
|
+
const require_VariableReplacementService = require('./VariableReplacementService-CAjesAYq.cjs');
|
|
8
6
|
let node_path = require("node:path");
|
|
9
7
|
node_path = require_chunk.__toESM(node_path);
|
|
10
|
-
let
|
|
11
|
-
__composio_json_schema_to_zod = require_chunk.__toESM(__composio_json_schema_to_zod);
|
|
12
|
-
let fs_extra = require("fs-extra");
|
|
13
|
-
fs_extra = require_chunk.__toESM(fs_extra);
|
|
8
|
+
let __agiflowai_aicode_utils = require("@agiflowai/aicode-utils");
|
|
14
9
|
let js_yaml = require("js-yaml");
|
|
15
10
|
js_yaml = require_chunk.__toESM(js_yaml);
|
|
11
|
+
let node_fs = require("node:fs");
|
|
12
|
+
let __composio_json_schema_to_zod = require("@composio/json-schema-to-zod");
|
|
16
13
|
let zod = require("zod");
|
|
17
|
-
zod = require_chunk.__toESM(zod);
|
|
18
|
-
let __modelcontextprotocol_sdk_types_js = require("@modelcontextprotocol/sdk/types.js");
|
|
19
|
-
__modelcontextprotocol_sdk_types_js = require_chunk.__toESM(__modelcontextprotocol_sdk_types_js);
|
|
20
14
|
let node_crypto = require("node:crypto");
|
|
21
|
-
node_crypto = require_chunk.__toESM(node_crypto);
|
|
22
15
|
let __modelcontextprotocol_sdk_server_streamableHttp_js = require("@modelcontextprotocol/sdk/server/streamableHttp.js");
|
|
23
|
-
|
|
16
|
+
let __modelcontextprotocol_sdk_types_js = require("@modelcontextprotocol/sdk/types.js");
|
|
24
17
|
let express = require("express");
|
|
25
18
|
express = require_chunk.__toESM(express);
|
|
26
19
|
let __modelcontextprotocol_sdk_server_sse_js = require("@modelcontextprotocol/sdk/server/sse.js");
|
|
27
|
-
__modelcontextprotocol_sdk_server_sse_js = require_chunk.__toESM(__modelcontextprotocol_sdk_server_sse_js);
|
|
28
20
|
let __modelcontextprotocol_sdk_server_stdio_js = require("@modelcontextprotocol/sdk/server/stdio.js");
|
|
29
|
-
__modelcontextprotocol_sdk_server_stdio_js = require_chunk.__toESM(__modelcontextprotocol_sdk_server_stdio_js);
|
|
30
21
|
|
|
22
|
+
//#region src/services/BoilerplateGeneratorService.ts
|
|
23
|
+
/**
|
|
24
|
+
* Service for generating boilerplate configurations in scaffold.yaml files
|
|
25
|
+
*/
|
|
26
|
+
var BoilerplateGeneratorService = class {
|
|
27
|
+
templatesPath;
|
|
28
|
+
constructor(templatesPath) {
|
|
29
|
+
this.templatesPath = templatesPath;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Custom YAML dumper that forces literal block style (|) for description and instruction fields
|
|
33
|
+
*/
|
|
34
|
+
dumpYamlWithLiteralBlocks(config) {
|
|
35
|
+
const LiteralBlockType = new js_yaml.Type("tag:yaml.org,2002:str", {
|
|
36
|
+
kind: "scalar",
|
|
37
|
+
construct: (data) => data,
|
|
38
|
+
represent: (data) => {
|
|
39
|
+
return data;
|
|
40
|
+
},
|
|
41
|
+
defaultStyle: "|"
|
|
42
|
+
});
|
|
43
|
+
const LITERAL_SCHEMA = js_yaml.DEFAULT_SCHEMA.extend([LiteralBlockType]);
|
|
44
|
+
const processedConfig = this.processConfigForLiteralBlocks(config);
|
|
45
|
+
return js_yaml.dump(processedConfig, {
|
|
46
|
+
schema: LITERAL_SCHEMA,
|
|
47
|
+
indent: 2,
|
|
48
|
+
lineWidth: -1,
|
|
49
|
+
noRefs: true,
|
|
50
|
+
sortKeys: false,
|
|
51
|
+
styles: { "!!str": "literal" },
|
|
52
|
+
replacer: (key, value) => {
|
|
53
|
+
if ((key === "description" || key === "instruction") && typeof value === "string") return value;
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Process config to ensure description and instruction use literal block style
|
|
60
|
+
*/
|
|
61
|
+
processConfigForLiteralBlocks(config) {
|
|
62
|
+
const processed = JSON.parse(JSON.stringify(config));
|
|
63
|
+
if (processed.boilerplate) processed.boilerplate = processed.boilerplate.map((bp) => {
|
|
64
|
+
const newBp = { ...bp };
|
|
65
|
+
if (newBp.description && typeof newBp.description === "string") newBp.description = this.ensureMultilineFormat(newBp.description);
|
|
66
|
+
if (newBp.instruction && typeof newBp.instruction === "string") newBp.instruction = this.ensureMultilineFormat(newBp.instruction);
|
|
67
|
+
return newBp;
|
|
68
|
+
});
|
|
69
|
+
if (processed.features) processed.features = processed.features.map((feature) => {
|
|
70
|
+
const newFeature = { ...feature };
|
|
71
|
+
if (newFeature.description && typeof newFeature.description === "string") newFeature.description = this.ensureMultilineFormat(newFeature.description);
|
|
72
|
+
if (newFeature.instruction && typeof newFeature.instruction === "string") newFeature.instruction = this.ensureMultilineFormat(newFeature.instruction);
|
|
73
|
+
return newFeature;
|
|
74
|
+
});
|
|
75
|
+
return processed;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Ensure string is properly formatted for YAML literal blocks
|
|
79
|
+
*/
|
|
80
|
+
ensureMultilineFormat(text) {
|
|
81
|
+
return text.trim();
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Generate or update a boilerplate configuration in scaffold.yaml
|
|
85
|
+
*/
|
|
86
|
+
async generateBoilerplate(options) {
|
|
87
|
+
const { templateName, boilerplateName, description, instruction, targetFolder, variables, includes = [] } = options;
|
|
88
|
+
const templatePath = node_path.join(this.templatesPath, templateName);
|
|
89
|
+
await (0, __agiflowai_aicode_utils.ensureDir)(templatePath);
|
|
90
|
+
const scaffoldYamlPath = node_path.join(templatePath, "scaffold.yaml");
|
|
91
|
+
let scaffoldConfig = {};
|
|
92
|
+
if (await (0, __agiflowai_aicode_utils.pathExists)(scaffoldYamlPath)) {
|
|
93
|
+
const yamlContent = await (0, __agiflowai_aicode_utils.readFile)(scaffoldYamlPath, "utf-8");
|
|
94
|
+
scaffoldConfig = js_yaml.load(yamlContent);
|
|
95
|
+
}
|
|
96
|
+
if (!scaffoldConfig.boilerplate) scaffoldConfig.boilerplate = [];
|
|
97
|
+
if (scaffoldConfig.boilerplate.findIndex((b) => b.name === boilerplateName) !== -1) return {
|
|
98
|
+
success: false,
|
|
99
|
+
message: `Boilerplate '${boilerplateName}' already exists in ${scaffoldYamlPath}`
|
|
100
|
+
};
|
|
101
|
+
const requiredVars = variables.filter((v) => v.required).map((v) => v.name);
|
|
102
|
+
const boilerplateDefinition = {
|
|
103
|
+
name: boilerplateName,
|
|
104
|
+
targetFolder,
|
|
105
|
+
description,
|
|
106
|
+
variables_schema: {
|
|
107
|
+
type: "object",
|
|
108
|
+
properties: variables.reduce((acc, v) => {
|
|
109
|
+
acc[v.name] = {
|
|
110
|
+
type: v.type,
|
|
111
|
+
description: v.description
|
|
112
|
+
};
|
|
113
|
+
if (v.default !== void 0) acc[v.name].default = v.default;
|
|
114
|
+
return acc;
|
|
115
|
+
}, {}),
|
|
116
|
+
required: requiredVars,
|
|
117
|
+
additionalProperties: false
|
|
118
|
+
},
|
|
119
|
+
includes: includes.length > 0 ? includes : []
|
|
120
|
+
};
|
|
121
|
+
if (instruction) boilerplateDefinition.instruction = instruction;
|
|
122
|
+
scaffoldConfig.boilerplate.push(boilerplateDefinition);
|
|
123
|
+
await (0, __agiflowai_aicode_utils.writeFile)(scaffoldYamlPath, this.dumpYamlWithLiteralBlocks(scaffoldConfig), "utf-8");
|
|
124
|
+
return {
|
|
125
|
+
success: true,
|
|
126
|
+
message: `Boilerplate '${boilerplateName}' added to ${scaffoldYamlPath}`,
|
|
127
|
+
templatePath,
|
|
128
|
+
scaffoldYamlPath
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* List all templates (directories in templates folder)
|
|
133
|
+
*/
|
|
134
|
+
async listTemplates() {
|
|
135
|
+
return (await (0, __agiflowai_aicode_utils.readdir)(this.templatesPath, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Check if a template exists
|
|
139
|
+
*/
|
|
140
|
+
async templateExists(templateName) {
|
|
141
|
+
return (0, __agiflowai_aicode_utils.pathExists)(node_path.join(this.templatesPath, templateName));
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Create or update a template file for a boilerplate
|
|
145
|
+
*/
|
|
146
|
+
async createTemplateFile(options) {
|
|
147
|
+
const { templateName, filePath, content, sourceFile, header } = options;
|
|
148
|
+
const templatePath = node_path.join(this.templatesPath, templateName);
|
|
149
|
+
if (!await (0, __agiflowai_aicode_utils.pathExists)(templatePath)) return {
|
|
150
|
+
success: false,
|
|
151
|
+
message: `Template directory '${templateName}' does not exist at ${templatePath}`
|
|
152
|
+
};
|
|
153
|
+
let fileContent = content || "";
|
|
154
|
+
if (sourceFile) {
|
|
155
|
+
if (!await (0, __agiflowai_aicode_utils.pathExists)(sourceFile)) return {
|
|
156
|
+
success: false,
|
|
157
|
+
message: `Source file '${sourceFile}' does not exist`
|
|
158
|
+
};
|
|
159
|
+
fileContent = await (0, __agiflowai_aicode_utils.readFile)(sourceFile, "utf-8");
|
|
160
|
+
}
|
|
161
|
+
if (!fileContent && !sourceFile) return {
|
|
162
|
+
success: false,
|
|
163
|
+
message: "Either content or sourceFile must be provided"
|
|
164
|
+
};
|
|
165
|
+
const templateFilePath = filePath.endsWith(".liquid") ? filePath : `${filePath}.liquid`;
|
|
166
|
+
const fullPath = node_path.join(templatePath, templateFilePath);
|
|
167
|
+
await (0, __agiflowai_aicode_utils.ensureDir)(node_path.dirname(fullPath));
|
|
168
|
+
let finalContent = fileContent;
|
|
169
|
+
if (header) finalContent = `${header}\n\n${fileContent}`;
|
|
170
|
+
await (0, __agiflowai_aicode_utils.writeFile)(fullPath, finalContent, "utf-8");
|
|
171
|
+
return {
|
|
172
|
+
success: true,
|
|
173
|
+
message: "Template file created successfully",
|
|
174
|
+
filePath: templateFilePath,
|
|
175
|
+
fullPath
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
//#endregion
|
|
181
|
+
//#region src/utils/pagination.ts
|
|
182
|
+
var PaginationHelper = class PaginationHelper {
|
|
183
|
+
/**
|
|
184
|
+
* Default page size for pagination
|
|
185
|
+
*/
|
|
186
|
+
static DEFAULT_PAGE_SIZE = 10;
|
|
187
|
+
/**
|
|
188
|
+
* Decodes a cursor string to extract the start index
|
|
189
|
+
* @param cursor - String representing the start index (e.g., "10")
|
|
190
|
+
* @returns Start index or 0 if invalid/undefined
|
|
191
|
+
*/
|
|
192
|
+
static decodeCursor(cursor) {
|
|
193
|
+
if (!cursor) return 0;
|
|
194
|
+
const index = Number.parseInt(cursor, 10);
|
|
195
|
+
if (Number.isNaN(index) || index < 0) return 0;
|
|
196
|
+
return index;
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Encodes an index into a cursor string
|
|
200
|
+
* @param index - Start index to encode
|
|
201
|
+
* @returns Cursor string (e.g., "10")
|
|
202
|
+
*/
|
|
203
|
+
static encodeCursor(index) {
|
|
204
|
+
return index.toString();
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Paginates an array of items
|
|
208
|
+
* @param items - All items to paginate
|
|
209
|
+
* @param cursor - Optional cursor representing the start index
|
|
210
|
+
* @param pageSize - Number of items per page (default: 10)
|
|
211
|
+
* @param includeMeta - Whether to include metadata in response (default: true)
|
|
212
|
+
* @returns Paginated result with items and optional nextCursor
|
|
213
|
+
*/
|
|
214
|
+
static paginate(items, cursor, pageSize = PaginationHelper.DEFAULT_PAGE_SIZE, includeMeta = true) {
|
|
215
|
+
const startIndex = PaginationHelper.decodeCursor(cursor);
|
|
216
|
+
const endIndex = startIndex + pageSize;
|
|
217
|
+
const result = {
|
|
218
|
+
items: items.slice(startIndex, endIndex),
|
|
219
|
+
nextCursor: endIndex < items.length ? PaginationHelper.encodeCursor(endIndex) : void 0
|
|
220
|
+
};
|
|
221
|
+
if (includeMeta) result._meta = {
|
|
222
|
+
total: items.length,
|
|
223
|
+
offset: startIndex,
|
|
224
|
+
limit: pageSize
|
|
225
|
+
};
|
|
226
|
+
return result;
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
//#endregion
|
|
31
231
|
//#region src/services/FileSystemService.ts
|
|
32
232
|
var FileSystemService = class {
|
|
33
233
|
async pathExists(path$2) {
|
|
34
|
-
return
|
|
234
|
+
return (0, __agiflowai_aicode_utils.pathExists)(path$2);
|
|
35
235
|
}
|
|
36
236
|
async readFile(path$2, encoding = "utf8") {
|
|
37
|
-
return
|
|
237
|
+
return (0, __agiflowai_aicode_utils.readFile)(path$2, encoding);
|
|
38
238
|
}
|
|
39
239
|
async readJson(path$2) {
|
|
40
|
-
return
|
|
240
|
+
return (0, __agiflowai_aicode_utils.readJson)(path$2);
|
|
41
241
|
}
|
|
42
242
|
async writeFile(path$2, content, encoding = "utf8") {
|
|
43
|
-
return
|
|
243
|
+
return (0, __agiflowai_aicode_utils.writeFile)(path$2, content, encoding);
|
|
44
244
|
}
|
|
45
245
|
async ensureDir(path$2) {
|
|
46
|
-
return
|
|
246
|
+
return (0, __agiflowai_aicode_utils.ensureDir)(path$2);
|
|
47
247
|
}
|
|
48
248
|
async copy(src, dest) {
|
|
49
|
-
return
|
|
249
|
+
return (0, __agiflowai_aicode_utils.copy)(src, dest);
|
|
50
250
|
}
|
|
51
251
|
async readdir(path$2) {
|
|
52
|
-
return
|
|
252
|
+
return (0, __agiflowai_aicode_utils.readdir)(path$2);
|
|
53
253
|
}
|
|
54
254
|
async stat(path$2) {
|
|
55
|
-
return
|
|
255
|
+
return (0, __agiflowai_aicode_utils.stat)(path$2);
|
|
56
256
|
}
|
|
57
257
|
};
|
|
58
258
|
|
|
@@ -69,15 +269,17 @@ var BoilerplateService = class {
|
|
|
69
269
|
this.scaffoldService = new require_ScaffoldService.ScaffoldService(fileSystemService, new require_ScaffoldConfigLoader.ScaffoldConfigLoader(fileSystemService, this.templateService), new require_VariableReplacementService.VariableReplacementService(fileSystemService, this.templateService), templatesPath);
|
|
70
270
|
}
|
|
71
271
|
/**
|
|
72
|
-
* Scans all scaffold.yaml files and returns available boilerplates
|
|
272
|
+
* Scans all scaffold.yaml files and returns available boilerplates with pagination
|
|
273
|
+
* @param cursor - Optional pagination cursor
|
|
274
|
+
* @returns Paginated list of boilerplates
|
|
73
275
|
*/
|
|
74
|
-
async listBoilerplates() {
|
|
276
|
+
async listBoilerplates(cursor) {
|
|
75
277
|
const boilerplates = [];
|
|
76
278
|
const templateDirs = await this.discoverTemplateDirectories();
|
|
77
279
|
for (const templatePath of templateDirs) {
|
|
78
280
|
const scaffoldYamlPath = node_path.join(this.templatesPath, templatePath, "scaffold.yaml");
|
|
79
|
-
if (
|
|
80
|
-
const scaffoldContent =
|
|
281
|
+
if ((0, __agiflowai_aicode_utils.pathExistsSync)(scaffoldYamlPath)) try {
|
|
282
|
+
const scaffoldContent = (0, __agiflowai_aicode_utils.readFileSync)(scaffoldYamlPath, "utf8");
|
|
81
283
|
const scaffoldConfig = js_yaml.load(scaffoldContent);
|
|
82
284
|
if (scaffoldConfig.boilerplate) for (const boilerplate of scaffoldConfig.boilerplate) {
|
|
83
285
|
if (!boilerplate.targetFolder) {
|
|
@@ -98,7 +300,12 @@ var BoilerplateService = class {
|
|
|
98
300
|
__agiflowai_aicode_utils.log.warn(`Failed to load scaffold.yaml for ${templatePath}:`, error);
|
|
99
301
|
}
|
|
100
302
|
}
|
|
101
|
-
|
|
303
|
+
const paginatedResult = PaginationHelper.paginate(boilerplates, cursor);
|
|
304
|
+
return {
|
|
305
|
+
boilerplates: paginatedResult.items,
|
|
306
|
+
nextCursor: paginatedResult.nextCursor,
|
|
307
|
+
_meta: paginatedResult._meta
|
|
308
|
+
};
|
|
102
309
|
}
|
|
103
310
|
/**
|
|
104
311
|
* Dynamically discovers template directories by finding all directories
|
|
@@ -107,14 +314,14 @@ var BoilerplateService = class {
|
|
|
107
314
|
async discoverTemplateDirectories() {
|
|
108
315
|
const templateDirs = [];
|
|
109
316
|
const findTemplates = (dir, baseDir = "") => {
|
|
110
|
-
if (!
|
|
111
|
-
const items =
|
|
317
|
+
if (!(0, __agiflowai_aicode_utils.pathExistsSync)(dir)) return;
|
|
318
|
+
const items = (0, node_fs.readdirSync)(dir);
|
|
112
319
|
const hasPackageJson = items.includes("package.json") || items.includes("package.json.liquid");
|
|
113
320
|
const hasScaffoldYaml = items.includes("scaffold.yaml");
|
|
114
321
|
if (hasPackageJson && hasScaffoldYaml) templateDirs.push(baseDir);
|
|
115
322
|
for (const item of items) {
|
|
116
323
|
const itemPath = node_path.join(dir, item);
|
|
117
|
-
if (
|
|
324
|
+
if ((0, __agiflowai_aicode_utils.statSync)(itemPath).isDirectory() && !item.startsWith(".") && item !== "node_modules") findTemplates(itemPath, baseDir ? node_path.join(baseDir, item) : item);
|
|
118
325
|
}
|
|
119
326
|
};
|
|
120
327
|
findTemplates(this.templatesPath);
|
|
@@ -185,9 +392,12 @@ var BoilerplateService = class {
|
|
|
185
392
|
const projectPath = node_path.join(targetFolder, folderName);
|
|
186
393
|
await __agiflowai_aicode_utils.ProjectConfigResolver.createProjectJson(projectPath, folderName, boilerplate.template_path);
|
|
187
394
|
}
|
|
395
|
+
const processedInstruction = boilerplate.instruction ? this.processBoilerplateInstruction(boilerplate.instruction, variables) : "";
|
|
396
|
+
let enhancedMessage = result.message;
|
|
397
|
+
if (processedInstruction) enhancedMessage += `\n\nPlease follow this **instruction**:\n${processedInstruction}`;
|
|
188
398
|
return {
|
|
189
399
|
success: result.success,
|
|
190
|
-
message:
|
|
400
|
+
message: enhancedMessage,
|
|
191
401
|
warnings: result.warnings,
|
|
192
402
|
createdFiles: result.createdFiles,
|
|
193
403
|
existingFiles: result.existingFiles
|
|
@@ -245,11 +455,11 @@ var BoilerplateService = class {
|
|
|
245
455
|
};
|
|
246
456
|
|
|
247
457
|
//#endregion
|
|
248
|
-
//#region src/services/
|
|
458
|
+
//#region src/services/ScaffoldGeneratorService.ts
|
|
249
459
|
/**
|
|
250
|
-
* Service for generating
|
|
460
|
+
* Service for generating feature scaffold configurations in scaffold.yaml files
|
|
251
461
|
*/
|
|
252
|
-
var
|
|
462
|
+
var ScaffoldGeneratorService = class {
|
|
253
463
|
templatesPath;
|
|
254
464
|
constructor(templatesPath) {
|
|
255
465
|
this.templatesPath = templatesPath;
|
|
@@ -307,27 +517,26 @@ var BoilerplateGeneratorService = class {
|
|
|
307
517
|
return text.trim();
|
|
308
518
|
}
|
|
309
519
|
/**
|
|
310
|
-
* Generate or update a
|
|
520
|
+
* Generate or update a feature configuration in scaffold.yaml
|
|
311
521
|
*/
|
|
312
|
-
async
|
|
313
|
-
const { templateName,
|
|
522
|
+
async generateFeatureScaffold(options) {
|
|
523
|
+
const { templateName, featureName, description, instruction, variables, includes = [], patterns = [] } = options;
|
|
314
524
|
const templatePath = node_path.join(this.templatesPath, templateName);
|
|
315
|
-
await
|
|
525
|
+
await (0, __agiflowai_aicode_utils.ensureDir)(templatePath);
|
|
316
526
|
const scaffoldYamlPath = node_path.join(templatePath, "scaffold.yaml");
|
|
317
527
|
let scaffoldConfig = {};
|
|
318
|
-
if (await
|
|
319
|
-
const yamlContent
|
|
320
|
-
scaffoldConfig = js_yaml.load(yamlContent
|
|
528
|
+
if (await (0, __agiflowai_aicode_utils.pathExists)(scaffoldYamlPath)) {
|
|
529
|
+
const yamlContent = await (0, __agiflowai_aicode_utils.readFile)(scaffoldYamlPath, "utf-8");
|
|
530
|
+
scaffoldConfig = js_yaml.load(yamlContent);
|
|
321
531
|
}
|
|
322
|
-
if (!scaffoldConfig.
|
|
323
|
-
if (scaffoldConfig.
|
|
532
|
+
if (!scaffoldConfig.features) scaffoldConfig.features = [];
|
|
533
|
+
if (scaffoldConfig.features.findIndex((f) => f.name === featureName) !== -1) return {
|
|
324
534
|
success: false,
|
|
325
|
-
message: `
|
|
535
|
+
message: `Feature '${featureName}' already exists in ${scaffoldYamlPath}`
|
|
326
536
|
};
|
|
327
537
|
const requiredVars = variables.filter((v) => v.required).map((v) => v.name);
|
|
328
|
-
const
|
|
329
|
-
name:
|
|
330
|
-
targetFolder,
|
|
538
|
+
const featureDefinition = {
|
|
539
|
+
name: featureName,
|
|
331
540
|
description,
|
|
332
541
|
variables_schema: {
|
|
333
542
|
type: "object",
|
|
@@ -344,13 +553,13 @@ var BoilerplateGeneratorService = class {
|
|
|
344
553
|
},
|
|
345
554
|
includes: includes.length > 0 ? includes : []
|
|
346
555
|
};
|
|
347
|
-
if (instruction)
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
await
|
|
556
|
+
if (instruction) featureDefinition.instruction = instruction;
|
|
557
|
+
if (patterns && patterns.length > 0) featureDefinition.patterns = patterns;
|
|
558
|
+
scaffoldConfig.features.push(featureDefinition);
|
|
559
|
+
await (0, __agiflowai_aicode_utils.writeFile)(scaffoldYamlPath, this.dumpYamlWithLiteralBlocks(scaffoldConfig), "utf-8");
|
|
351
560
|
return {
|
|
352
561
|
success: true,
|
|
353
|
-
message: `
|
|
562
|
+
message: `Feature '${featureName}' added to ${scaffoldYamlPath}`,
|
|
354
563
|
templatePath,
|
|
355
564
|
scaffoldYamlPath
|
|
356
565
|
};
|
|
@@ -359,71 +568,208 @@ var BoilerplateGeneratorService = class {
|
|
|
359
568
|
* List all templates (directories in templates folder)
|
|
360
569
|
*/
|
|
361
570
|
async listTemplates() {
|
|
362
|
-
return (await
|
|
571
|
+
return (await (0, __agiflowai_aicode_utils.readdir)(this.templatesPath, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
363
572
|
}
|
|
364
573
|
/**
|
|
365
574
|
* Check if a template exists
|
|
366
575
|
*/
|
|
367
576
|
async templateExists(templateName) {
|
|
368
|
-
|
|
369
|
-
return fs_extra.pathExists(templatePath);
|
|
370
|
-
}
|
|
371
|
-
/**
|
|
372
|
-
* Create or update a template file for a boilerplate
|
|
373
|
-
*/
|
|
374
|
-
async createTemplateFile(options) {
|
|
375
|
-
const { templateName, filePath, content, sourceFile, header } = options;
|
|
376
|
-
const templatePath = node_path.join(this.templatesPath, templateName);
|
|
377
|
-
if (!await fs_extra.pathExists(templatePath)) return {
|
|
378
|
-
success: false,
|
|
379
|
-
message: `Template directory '${templateName}' does not exist at ${templatePath}`
|
|
380
|
-
};
|
|
381
|
-
let fileContent = content || "";
|
|
382
|
-
if (sourceFile) {
|
|
383
|
-
if (!await fs_extra.pathExists(sourceFile)) return {
|
|
384
|
-
success: false,
|
|
385
|
-
message: `Source file '${sourceFile}' does not exist`
|
|
386
|
-
};
|
|
387
|
-
fileContent = await fs_extra.readFile(sourceFile, "utf-8");
|
|
388
|
-
}
|
|
389
|
-
if (!fileContent && !sourceFile) return {
|
|
390
|
-
success: false,
|
|
391
|
-
message: "Either content or sourceFile must be provided"
|
|
392
|
-
};
|
|
393
|
-
const templateFilePath = filePath.endsWith(".liquid") ? filePath : `${filePath}.liquid`;
|
|
394
|
-
const fullPath = node_path.join(templatePath, templateFilePath);
|
|
395
|
-
await fs_extra.ensureDir(node_path.dirname(fullPath));
|
|
396
|
-
let finalContent = fileContent;
|
|
397
|
-
if (header) finalContent = `${header}\n\n${fileContent}`;
|
|
398
|
-
await fs_extra.writeFile(fullPath, finalContent, "utf-8");
|
|
399
|
-
return {
|
|
400
|
-
success: true,
|
|
401
|
-
message: "Template file created successfully",
|
|
402
|
-
filePath: templateFilePath,
|
|
403
|
-
fullPath
|
|
404
|
-
};
|
|
577
|
+
return (0, __agiflowai_aicode_utils.pathExists)(node_path.join(this.templatesPath, templateName));
|
|
405
578
|
}
|
|
406
579
|
};
|
|
407
580
|
|
|
408
581
|
//#endregion
|
|
409
|
-
//#region src/
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
isMonolith;
|
|
417
|
-
constructor(templatesPath, isMonolith = false) {
|
|
418
|
-
this.boilerplateGeneratorService = new BoilerplateGeneratorService(templatesPath);
|
|
419
|
-
this.isMonolith = isMonolith;
|
|
582
|
+
//#region src/services/ScaffoldingMethodsService.ts
|
|
583
|
+
var ScaffoldingMethodsService = class {
|
|
584
|
+
templateService;
|
|
585
|
+
constructor(fileSystem, templatesRootPath) {
|
|
586
|
+
this.fileSystem = fileSystem;
|
|
587
|
+
this.templatesRootPath = templatesRootPath;
|
|
588
|
+
this.templateService = new require_TemplateService.TemplateService();
|
|
420
589
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
590
|
+
async listScaffoldingMethods(projectPath, cursor) {
|
|
591
|
+
const absoluteProjectPath = node_path.default.resolve(projectPath);
|
|
592
|
+
const sourceTemplate = (await __agiflowai_aicode_utils.ProjectConfigResolver.resolveProjectConfig(absoluteProjectPath)).sourceTemplate;
|
|
593
|
+
return this.listScaffoldingMethodsByTemplate(sourceTemplate, cursor);
|
|
594
|
+
}
|
|
595
|
+
async listScaffoldingMethodsByTemplate(templateName, cursor) {
|
|
596
|
+
const templatePath = await this.findTemplatePath(templateName);
|
|
597
|
+
if (!templatePath) throw new Error(`Template not found for sourceTemplate: ${templateName}`);
|
|
598
|
+
const fullTemplatePath = node_path.default.join(this.templatesRootPath, templatePath);
|
|
599
|
+
const scaffoldYamlPath = node_path.default.join(fullTemplatePath, "scaffold.yaml");
|
|
600
|
+
if (!await this.fileSystem.pathExists(scaffoldYamlPath)) throw new Error(`scaffold.yaml not found at ${scaffoldYamlPath}`);
|
|
601
|
+
const scaffoldContent = await this.fileSystem.readFile(scaffoldYamlPath, "utf8");
|
|
602
|
+
const architectConfig = js_yaml.default.load(scaffoldContent);
|
|
603
|
+
const methods = [];
|
|
604
|
+
if (architectConfig.features && Array.isArray(architectConfig.features)) architectConfig.features.forEach((feature) => {
|
|
605
|
+
const featureName = feature.name || `scaffold-${templateName}`;
|
|
606
|
+
methods.push({
|
|
607
|
+
name: featureName,
|
|
608
|
+
description: feature.description || "",
|
|
609
|
+
instruction: feature.instruction || "",
|
|
610
|
+
variables_schema: feature.variables_schema || {
|
|
611
|
+
type: "object",
|
|
612
|
+
properties: {},
|
|
613
|
+
required: [],
|
|
614
|
+
additionalProperties: false
|
|
615
|
+
},
|
|
616
|
+
generator: feature.generator
|
|
617
|
+
});
|
|
618
|
+
});
|
|
619
|
+
const paginatedResult = PaginationHelper.paginate(methods, cursor);
|
|
620
|
+
return {
|
|
621
|
+
sourceTemplate: templateName,
|
|
622
|
+
templatePath,
|
|
623
|
+
methods: paginatedResult.items,
|
|
624
|
+
nextCursor: paginatedResult.nextCursor,
|
|
625
|
+
_meta: paginatedResult._meta
|
|
626
|
+
};
|
|
627
|
+
}
|
|
628
|
+
/**
|
|
629
|
+
* Gets scaffolding methods with instructions rendered using provided variables
|
|
630
|
+
*/
|
|
631
|
+
async listScaffoldingMethodsWithVariables(projectPath, variables, cursor) {
|
|
632
|
+
const result = await this.listScaffoldingMethods(projectPath, cursor);
|
|
633
|
+
const processedMethods = result.methods.map((method) => ({
|
|
634
|
+
...method,
|
|
635
|
+
instruction: method.instruction ? this.processScaffoldInstruction(method.instruction, variables) : void 0
|
|
636
|
+
}));
|
|
637
|
+
return {
|
|
638
|
+
...result,
|
|
639
|
+
methods: processedMethods
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
/**
|
|
643
|
+
* Processes scaffold instruction with template service
|
|
644
|
+
*/
|
|
645
|
+
processScaffoldInstruction(instruction, variables) {
|
|
646
|
+
if (this.templateService.containsTemplateVariables(instruction)) return this.templateService.renderString(instruction, variables);
|
|
647
|
+
return instruction;
|
|
648
|
+
}
|
|
649
|
+
async findTemplatePath(sourceTemplate) {
|
|
650
|
+
const templateDirs = await this.discoverTemplateDirs();
|
|
651
|
+
if (templateDirs.includes(sourceTemplate)) return sourceTemplate;
|
|
652
|
+
for (const templateDir of templateDirs) {
|
|
653
|
+
const templatePath = node_path.default.join(this.templatesRootPath, templateDir);
|
|
654
|
+
const scaffoldYamlPath = node_path.default.join(templatePath, "scaffold.yaml");
|
|
655
|
+
if (await this.fileSystem.pathExists(scaffoldYamlPath)) try {
|
|
656
|
+
const scaffoldContent = await this.fileSystem.readFile(scaffoldYamlPath, "utf8");
|
|
657
|
+
const architectConfig = js_yaml.default.load(scaffoldContent);
|
|
658
|
+
if (architectConfig.boilerplate && Array.isArray(architectConfig.boilerplate)) {
|
|
659
|
+
for (const boilerplate of architectConfig.boilerplate) if (boilerplate.name?.includes(sourceTemplate)) return templateDir;
|
|
660
|
+
}
|
|
661
|
+
} catch (error) {
|
|
662
|
+
__agiflowai_aicode_utils.log.warn(`Failed to read scaffold.yaml at ${scaffoldYamlPath}:`, error);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
return null;
|
|
666
|
+
}
|
|
667
|
+
/**
|
|
668
|
+
* Resolves the project path, handling both monorepo and monolith cases
|
|
669
|
+
* Uses ProjectConfigResolver to find the correct workspace/project root
|
|
670
|
+
*/
|
|
671
|
+
async resolveProjectPath(projectPath) {
|
|
672
|
+
const absolutePath = node_path.default.resolve(projectPath);
|
|
673
|
+
return (await __agiflowai_aicode_utils.ProjectConfigResolver.resolveProjectConfig(absolutePath)).workspaceRoot || absolutePath;
|
|
674
|
+
}
|
|
675
|
+
/**
|
|
676
|
+
* Dynamically discovers all template directories
|
|
677
|
+
* Supports both flat structure (templates/nextjs-15) and nested structure (templates/apps/nextjs-15)
|
|
678
|
+
**/
|
|
679
|
+
async discoverTemplateDirs() {
|
|
680
|
+
const templateDirs = [];
|
|
681
|
+
try {
|
|
682
|
+
const items = await this.fileSystem.readdir(this.templatesRootPath);
|
|
683
|
+
for (const item of items) {
|
|
684
|
+
const itemPath = node_path.default.join(this.templatesRootPath, item);
|
|
685
|
+
if (!(await this.fileSystem.stat(itemPath)).isDirectory()) continue;
|
|
686
|
+
const scaffoldYamlPath = node_path.default.join(itemPath, "scaffold.yaml");
|
|
687
|
+
if (await this.fileSystem.pathExists(scaffoldYamlPath)) {
|
|
688
|
+
templateDirs.push(item);
|
|
689
|
+
continue;
|
|
690
|
+
}
|
|
691
|
+
try {
|
|
692
|
+
const subItems = await this.fileSystem.readdir(itemPath);
|
|
693
|
+
for (const subItem of subItems) {
|
|
694
|
+
const subItemPath = node_path.default.join(itemPath, subItem);
|
|
695
|
+
if (!(await this.fileSystem.stat(subItemPath)).isDirectory()) continue;
|
|
696
|
+
const subScaffoldYamlPath = node_path.default.join(subItemPath, "scaffold.yaml");
|
|
697
|
+
if (await this.fileSystem.pathExists(subScaffoldYamlPath)) {
|
|
698
|
+
const relativePath = node_path.default.join(item, subItem);
|
|
699
|
+
templateDirs.push(relativePath);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
} catch (error) {
|
|
703
|
+
__agiflowai_aicode_utils.log.warn(`Failed to read subdirectories in ${itemPath}:`, error);
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
} catch (error) {
|
|
707
|
+
__agiflowai_aicode_utils.log.warn(`Failed to read templates root directory ${this.templatesRootPath}:`, error);
|
|
708
|
+
}
|
|
709
|
+
return templateDirs;
|
|
710
|
+
}
|
|
711
|
+
async useScaffoldMethod(request) {
|
|
712
|
+
const { projectPath, scaffold_feature_name, variables } = request;
|
|
713
|
+
const absoluteProjectPath = await this.resolveProjectPath(projectPath);
|
|
714
|
+
const scaffoldingMethods = await this.listScaffoldingMethods(absoluteProjectPath);
|
|
715
|
+
const method = scaffoldingMethods.methods.find((m) => m.name === scaffold_feature_name);
|
|
716
|
+
if (!method) {
|
|
717
|
+
const availableMethods = scaffoldingMethods.methods.map((m) => m.name).join(", ");
|
|
718
|
+
throw new Error(`Scaffold method '${scaffold_feature_name}' not found. Available methods: ${availableMethods}`);
|
|
719
|
+
}
|
|
720
|
+
const ScaffoldService$1 = (await Promise.resolve().then(() => require("./ScaffoldService-BNOyoqSb.cjs"))).ScaffoldService;
|
|
721
|
+
const ScaffoldConfigLoader$1 = (await Promise.resolve().then(() => require("./ScaffoldConfigLoader-B-NLy6VP.cjs"))).ScaffoldConfigLoader;
|
|
722
|
+
const VariableReplacementService$1 = (await Promise.resolve().then(() => require("./VariableReplacementService-DKaF2C9l.cjs"))).VariableReplacementService;
|
|
723
|
+
const TemplateService$1 = (await Promise.resolve().then(() => require("./TemplateService-DqieT1Tq.cjs"))).TemplateService;
|
|
724
|
+
const templateService = new TemplateService$1();
|
|
725
|
+
const scaffoldConfigLoader = new ScaffoldConfigLoader$1(this.fileSystem, templateService);
|
|
726
|
+
const variableReplacer = new VariableReplacementService$1(this.fileSystem, templateService);
|
|
727
|
+
const scaffoldService = new ScaffoldService$1(this.fileSystem, scaffoldConfigLoader, variableReplacer, this.templatesRootPath);
|
|
728
|
+
const projectName = node_path.default.basename(absoluteProjectPath);
|
|
729
|
+
const result = await scaffoldService.useFeature({
|
|
730
|
+
projectPath: absoluteProjectPath,
|
|
731
|
+
templateFolder: scaffoldingMethods.templatePath,
|
|
732
|
+
featureName: scaffold_feature_name,
|
|
733
|
+
variables: {
|
|
734
|
+
...variables,
|
|
735
|
+
appPath: absoluteProjectPath,
|
|
736
|
+
appName: projectName
|
|
737
|
+
}
|
|
738
|
+
});
|
|
739
|
+
if (!result.success) throw new Error(result.message);
|
|
740
|
+
return {
|
|
741
|
+
success: true,
|
|
742
|
+
message: `
|
|
743
|
+
Successfully scaffolded ${scaffold_feature_name} in ${projectPath}.
|
|
744
|
+
Please follow this **instruction**: \n ${method.instruction ? this.processScaffoldInstruction(method.instruction, variables) : ""}.
|
|
745
|
+
-> Create or update the plan based on the instruction.
|
|
746
|
+
`,
|
|
747
|
+
warnings: result.warnings,
|
|
748
|
+
createdFiles: result.createdFiles,
|
|
749
|
+
existingFiles: result.existingFiles
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
};
|
|
753
|
+
|
|
754
|
+
//#endregion
|
|
755
|
+
//#region src/tools/GenerateBoilerplateFileTool.ts
|
|
756
|
+
/**
|
|
757
|
+
* Tool to generate template files for boilerplates and features
|
|
758
|
+
*/
|
|
759
|
+
var GenerateBoilerplateFileTool = class GenerateBoilerplateFileTool {
|
|
760
|
+
static TOOL_NAME = "generate-boilerplate-file";
|
|
761
|
+
boilerplateGeneratorService;
|
|
762
|
+
isMonolith;
|
|
763
|
+
constructor(templatesPath, isMonolith = false) {
|
|
764
|
+
this.boilerplateGeneratorService = new BoilerplateGeneratorService(templatesPath);
|
|
765
|
+
this.isMonolith = isMonolith;
|
|
766
|
+
}
|
|
767
|
+
/**
|
|
768
|
+
* Get the tool definition for MCP
|
|
769
|
+
*/
|
|
770
|
+
getDefinition() {
|
|
771
|
+
const properties = {};
|
|
772
|
+
if (!this.isMonolith) properties.templateName = {
|
|
427
773
|
type: "string",
|
|
428
774
|
description: "Name of the template folder (must already exist)"
|
|
429
775
|
};
|
|
@@ -862,132 +1208,6 @@ Use this to add custom boilerplate configurations for frameworks not yet support
|
|
|
862
1208
|
}
|
|
863
1209
|
};
|
|
864
1210
|
|
|
865
|
-
//#endregion
|
|
866
|
-
//#region src/services/ScaffoldGeneratorService.ts
|
|
867
|
-
/**
|
|
868
|
-
* Service for generating feature scaffold configurations in scaffold.yaml files
|
|
869
|
-
*/
|
|
870
|
-
var ScaffoldGeneratorService = class {
|
|
871
|
-
templatesPath;
|
|
872
|
-
constructor(templatesPath) {
|
|
873
|
-
this.templatesPath = templatesPath;
|
|
874
|
-
}
|
|
875
|
-
/**
|
|
876
|
-
* Custom YAML dumper that forces literal block style (|) for description and instruction fields
|
|
877
|
-
*/
|
|
878
|
-
dumpYamlWithLiteralBlocks(config) {
|
|
879
|
-
const LiteralBlockType = new js_yaml.Type("tag:yaml.org,2002:str", {
|
|
880
|
-
kind: "scalar",
|
|
881
|
-
construct: (data) => data,
|
|
882
|
-
represent: (data) => {
|
|
883
|
-
return data;
|
|
884
|
-
},
|
|
885
|
-
defaultStyle: "|"
|
|
886
|
-
});
|
|
887
|
-
const LITERAL_SCHEMA = js_yaml.DEFAULT_SCHEMA.extend([LiteralBlockType]);
|
|
888
|
-
const processedConfig = this.processConfigForLiteralBlocks(config);
|
|
889
|
-
return js_yaml.dump(processedConfig, {
|
|
890
|
-
schema: LITERAL_SCHEMA,
|
|
891
|
-
indent: 2,
|
|
892
|
-
lineWidth: -1,
|
|
893
|
-
noRefs: true,
|
|
894
|
-
sortKeys: false,
|
|
895
|
-
styles: { "!!str": "literal" },
|
|
896
|
-
replacer: (key, value) => {
|
|
897
|
-
if ((key === "description" || key === "instruction") && typeof value === "string") return value;
|
|
898
|
-
return value;
|
|
899
|
-
}
|
|
900
|
-
});
|
|
901
|
-
}
|
|
902
|
-
/**
|
|
903
|
-
* Process config to ensure description and instruction use literal block style
|
|
904
|
-
*/
|
|
905
|
-
processConfigForLiteralBlocks(config) {
|
|
906
|
-
const processed = JSON.parse(JSON.stringify(config));
|
|
907
|
-
if (processed.boilerplate) processed.boilerplate = processed.boilerplate.map((bp) => {
|
|
908
|
-
const newBp = { ...bp };
|
|
909
|
-
if (newBp.description && typeof newBp.description === "string") newBp.description = this.ensureMultilineFormat(newBp.description);
|
|
910
|
-
if (newBp.instruction && typeof newBp.instruction === "string") newBp.instruction = this.ensureMultilineFormat(newBp.instruction);
|
|
911
|
-
return newBp;
|
|
912
|
-
});
|
|
913
|
-
if (processed.features) processed.features = processed.features.map((feature) => {
|
|
914
|
-
const newFeature = { ...feature };
|
|
915
|
-
if (newFeature.description && typeof newFeature.description === "string") newFeature.description = this.ensureMultilineFormat(newFeature.description);
|
|
916
|
-
if (newFeature.instruction && typeof newFeature.instruction === "string") newFeature.instruction = this.ensureMultilineFormat(newFeature.instruction);
|
|
917
|
-
return newFeature;
|
|
918
|
-
});
|
|
919
|
-
return processed;
|
|
920
|
-
}
|
|
921
|
-
/**
|
|
922
|
-
* Ensure string is properly formatted for YAML literal blocks
|
|
923
|
-
*/
|
|
924
|
-
ensureMultilineFormat(text) {
|
|
925
|
-
return text.trim();
|
|
926
|
-
}
|
|
927
|
-
/**
|
|
928
|
-
* Generate or update a feature configuration in scaffold.yaml
|
|
929
|
-
*/
|
|
930
|
-
async generateFeatureScaffold(options) {
|
|
931
|
-
const { templateName, featureName, description, instruction, variables, includes = [], patterns = [] } = options;
|
|
932
|
-
const templatePath = node_path.join(this.templatesPath, templateName);
|
|
933
|
-
await fs_extra.ensureDir(templatePath);
|
|
934
|
-
const scaffoldYamlPath = node_path.join(templatePath, "scaffold.yaml");
|
|
935
|
-
let scaffoldConfig = {};
|
|
936
|
-
if (await fs_extra.pathExists(scaffoldYamlPath)) {
|
|
937
|
-
const yamlContent$1 = await fs_extra.readFile(scaffoldYamlPath, "utf-8");
|
|
938
|
-
scaffoldConfig = js_yaml.load(yamlContent$1);
|
|
939
|
-
}
|
|
940
|
-
if (!scaffoldConfig.features) scaffoldConfig.features = [];
|
|
941
|
-
if (scaffoldConfig.features.findIndex((f) => f.name === featureName) !== -1) return {
|
|
942
|
-
success: false,
|
|
943
|
-
message: `Feature '${featureName}' already exists in ${scaffoldYamlPath}`
|
|
944
|
-
};
|
|
945
|
-
const requiredVars = variables.filter((v) => v.required).map((v) => v.name);
|
|
946
|
-
const featureDefinition = {
|
|
947
|
-
name: featureName,
|
|
948
|
-
description,
|
|
949
|
-
variables_schema: {
|
|
950
|
-
type: "object",
|
|
951
|
-
properties: variables.reduce((acc, v) => {
|
|
952
|
-
acc[v.name] = {
|
|
953
|
-
type: v.type,
|
|
954
|
-
description: v.description
|
|
955
|
-
};
|
|
956
|
-
if (v.default !== void 0) acc[v.name].default = v.default;
|
|
957
|
-
return acc;
|
|
958
|
-
}, {}),
|
|
959
|
-
required: requiredVars,
|
|
960
|
-
additionalProperties: false
|
|
961
|
-
},
|
|
962
|
-
includes: includes.length > 0 ? includes : []
|
|
963
|
-
};
|
|
964
|
-
if (instruction) featureDefinition.instruction = instruction;
|
|
965
|
-
if (patterns && patterns.length > 0) featureDefinition.patterns = patterns;
|
|
966
|
-
scaffoldConfig.features.push(featureDefinition);
|
|
967
|
-
const yamlContent = this.dumpYamlWithLiteralBlocks(scaffoldConfig);
|
|
968
|
-
await fs_extra.writeFile(scaffoldYamlPath, yamlContent, "utf-8");
|
|
969
|
-
return {
|
|
970
|
-
success: true,
|
|
971
|
-
message: `Feature '${featureName}' added to ${scaffoldYamlPath}`,
|
|
972
|
-
templatePath,
|
|
973
|
-
scaffoldYamlPath
|
|
974
|
-
};
|
|
975
|
-
}
|
|
976
|
-
/**
|
|
977
|
-
* List all templates (directories in templates folder)
|
|
978
|
-
*/
|
|
979
|
-
async listTemplates() {
|
|
980
|
-
return (await fs_extra.readdir(this.templatesPath, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
981
|
-
}
|
|
982
|
-
/**
|
|
983
|
-
* Check if a template exists
|
|
984
|
-
*/
|
|
985
|
-
async templateExists(templateName) {
|
|
986
|
-
const templatePath = node_path.join(this.templatesPath, templateName);
|
|
987
|
-
return fs_extra.pathExists(templatePath);
|
|
988
|
-
}
|
|
989
|
-
};
|
|
990
|
-
|
|
991
1211
|
//#endregion
|
|
992
1212
|
//#region src/tools/GenerateFeatureScaffoldTool.ts
|
|
993
1213
|
/**
|
|
@@ -1233,7 +1453,10 @@ var ListBoilerplatesTool = class ListBoilerplatesTool {
|
|
|
1233
1453
|
description: description.trim(),
|
|
1234
1454
|
inputSchema: {
|
|
1235
1455
|
type: "object",
|
|
1236
|
-
properties: {
|
|
1456
|
+
properties: { cursor: {
|
|
1457
|
+
type: "string",
|
|
1458
|
+
description: "Optional pagination cursor to fetch the next page of results. Omit to fetch the first page."
|
|
1459
|
+
} },
|
|
1237
1460
|
additionalProperties: false
|
|
1238
1461
|
}
|
|
1239
1462
|
};
|
|
@@ -1241,9 +1464,10 @@ var ListBoilerplatesTool = class ListBoilerplatesTool {
|
|
|
1241
1464
|
/**
|
|
1242
1465
|
* Execute the tool
|
|
1243
1466
|
*/
|
|
1244
|
-
async execute(
|
|
1467
|
+
async execute(args = {}) {
|
|
1245
1468
|
try {
|
|
1246
|
-
const
|
|
1469
|
+
const { cursor } = args;
|
|
1470
|
+
const result = await this.boilerplateService.listBoilerplates(cursor);
|
|
1247
1471
|
return { content: [{
|
|
1248
1472
|
type: "text",
|
|
1249
1473
|
text: JSON.stringify(result, null, 2)
|
|
@@ -1264,176 +1488,6 @@ var ListBoilerplatesTool = class ListBoilerplatesTool {
|
|
|
1264
1488
|
//#region src/instructions/tools/list-scaffolding-methods/description.md?raw
|
|
1265
1489
|
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";
|
|
1266
1490
|
|
|
1267
|
-
//#endregion
|
|
1268
|
-
//#region src/services/ScaffoldingMethodsService.ts
|
|
1269
|
-
var ScaffoldingMethodsService = class {
|
|
1270
|
-
templateService;
|
|
1271
|
-
constructor(fileSystem, templatesRootPath) {
|
|
1272
|
-
this.fileSystem = fileSystem;
|
|
1273
|
-
this.templatesRootPath = templatesRootPath;
|
|
1274
|
-
this.templateService = new require_TemplateService.TemplateService();
|
|
1275
|
-
}
|
|
1276
|
-
async listScaffoldingMethods(projectPath) {
|
|
1277
|
-
const absoluteProjectPath = node_path.default.resolve(projectPath);
|
|
1278
|
-
const sourceTemplate = (await __agiflowai_aicode_utils.ProjectConfigResolver.resolveProjectConfig(absoluteProjectPath)).sourceTemplate;
|
|
1279
|
-
return this.listScaffoldingMethodsByTemplate(sourceTemplate);
|
|
1280
|
-
}
|
|
1281
|
-
async listScaffoldingMethodsByTemplate(templateName) {
|
|
1282
|
-
const templatePath = await this.findTemplatePath(templateName);
|
|
1283
|
-
if (!templatePath) throw new Error(`Template not found for sourceTemplate: ${templateName}`);
|
|
1284
|
-
const fullTemplatePath = node_path.default.join(this.templatesRootPath, templatePath);
|
|
1285
|
-
const scaffoldYamlPath = node_path.default.join(fullTemplatePath, "scaffold.yaml");
|
|
1286
|
-
if (!await this.fileSystem.pathExists(scaffoldYamlPath)) throw new Error(`scaffold.yaml not found at ${scaffoldYamlPath}`);
|
|
1287
|
-
const scaffoldContent = await this.fileSystem.readFile(scaffoldYamlPath, "utf8");
|
|
1288
|
-
const architectConfig = js_yaml.default.load(scaffoldContent);
|
|
1289
|
-
const methods = [];
|
|
1290
|
-
if (architectConfig.features && Array.isArray(architectConfig.features)) architectConfig.features.forEach((feature) => {
|
|
1291
|
-
const featureName = feature.name || `scaffold-${templateName}`;
|
|
1292
|
-
methods.push({
|
|
1293
|
-
name: featureName,
|
|
1294
|
-
description: feature.description || "",
|
|
1295
|
-
instruction: feature.instruction || "",
|
|
1296
|
-
variables_schema: feature.variables_schema || {
|
|
1297
|
-
type: "object",
|
|
1298
|
-
properties: {},
|
|
1299
|
-
required: [],
|
|
1300
|
-
additionalProperties: false
|
|
1301
|
-
},
|
|
1302
|
-
generator: feature.generator
|
|
1303
|
-
});
|
|
1304
|
-
});
|
|
1305
|
-
return {
|
|
1306
|
-
sourceTemplate: templateName,
|
|
1307
|
-
templatePath,
|
|
1308
|
-
methods
|
|
1309
|
-
};
|
|
1310
|
-
}
|
|
1311
|
-
/**
|
|
1312
|
-
* Gets scaffolding methods with instructions rendered using provided variables
|
|
1313
|
-
*/
|
|
1314
|
-
async listScaffoldingMethodsWithVariables(projectPath, variables) {
|
|
1315
|
-
const result = await this.listScaffoldingMethods(projectPath);
|
|
1316
|
-
const processedMethods = result.methods.map((method) => ({
|
|
1317
|
-
...method,
|
|
1318
|
-
instruction: method.instruction ? this.processScaffoldInstruction(method.instruction, variables) : void 0
|
|
1319
|
-
}));
|
|
1320
|
-
return {
|
|
1321
|
-
...result,
|
|
1322
|
-
methods: processedMethods
|
|
1323
|
-
};
|
|
1324
|
-
}
|
|
1325
|
-
/**
|
|
1326
|
-
* Processes scaffold instruction with template service
|
|
1327
|
-
*/
|
|
1328
|
-
processScaffoldInstruction(instruction, variables) {
|
|
1329
|
-
if (this.templateService.containsTemplateVariables(instruction)) return this.templateService.renderString(instruction, variables);
|
|
1330
|
-
return instruction;
|
|
1331
|
-
}
|
|
1332
|
-
async findTemplatePath(sourceTemplate) {
|
|
1333
|
-
const templateDirs = await this.discoverTemplateDirs();
|
|
1334
|
-
if (templateDirs.includes(sourceTemplate)) return sourceTemplate;
|
|
1335
|
-
for (const templateDir of templateDirs) {
|
|
1336
|
-
const templatePath = node_path.default.join(this.templatesRootPath, templateDir);
|
|
1337
|
-
const scaffoldYamlPath = node_path.default.join(templatePath, "scaffold.yaml");
|
|
1338
|
-
if (await this.fileSystem.pathExists(scaffoldYamlPath)) try {
|
|
1339
|
-
const scaffoldContent = await this.fileSystem.readFile(scaffoldYamlPath, "utf8");
|
|
1340
|
-
const architectConfig = js_yaml.default.load(scaffoldContent);
|
|
1341
|
-
if (architectConfig.boilerplate && Array.isArray(architectConfig.boilerplate)) {
|
|
1342
|
-
for (const boilerplate of architectConfig.boilerplate) if (boilerplate.name?.includes(sourceTemplate)) return templateDir;
|
|
1343
|
-
}
|
|
1344
|
-
} catch (error) {
|
|
1345
|
-
__agiflowai_aicode_utils.log.warn(`Failed to read scaffold.yaml at ${scaffoldYamlPath}:`, error);
|
|
1346
|
-
}
|
|
1347
|
-
}
|
|
1348
|
-
return null;
|
|
1349
|
-
}
|
|
1350
|
-
/**
|
|
1351
|
-
* Resolves the project path, handling both monorepo and monolith cases
|
|
1352
|
-
* Uses ProjectConfigResolver to find the correct workspace/project root
|
|
1353
|
-
*/
|
|
1354
|
-
async resolveProjectPath(projectPath) {
|
|
1355
|
-
const absolutePath = node_path.default.resolve(projectPath);
|
|
1356
|
-
return (await __agiflowai_aicode_utils.ProjectConfigResolver.resolveProjectConfig(absolutePath)).workspaceRoot || absolutePath;
|
|
1357
|
-
}
|
|
1358
|
-
/**
|
|
1359
|
-
* Dynamically discovers all template directories
|
|
1360
|
-
* Supports both flat structure (templates/nextjs-15) and nested structure (templates/apps/nextjs-15)
|
|
1361
|
-
**/
|
|
1362
|
-
async discoverTemplateDirs() {
|
|
1363
|
-
const templateDirs = [];
|
|
1364
|
-
try {
|
|
1365
|
-
const items = await this.fileSystem.readdir(this.templatesRootPath);
|
|
1366
|
-
for (const item of items) {
|
|
1367
|
-
const itemPath = node_path.default.join(this.templatesRootPath, item);
|
|
1368
|
-
if (!(await this.fileSystem.stat(itemPath)).isDirectory()) continue;
|
|
1369
|
-
const scaffoldYamlPath = node_path.default.join(itemPath, "scaffold.yaml");
|
|
1370
|
-
if (await this.fileSystem.pathExists(scaffoldYamlPath)) {
|
|
1371
|
-
templateDirs.push(item);
|
|
1372
|
-
continue;
|
|
1373
|
-
}
|
|
1374
|
-
try {
|
|
1375
|
-
const subItems = await this.fileSystem.readdir(itemPath);
|
|
1376
|
-
for (const subItem of subItems) {
|
|
1377
|
-
const subItemPath = node_path.default.join(itemPath, subItem);
|
|
1378
|
-
if (!(await this.fileSystem.stat(subItemPath)).isDirectory()) continue;
|
|
1379
|
-
const subScaffoldYamlPath = node_path.default.join(subItemPath, "scaffold.yaml");
|
|
1380
|
-
if (await this.fileSystem.pathExists(subScaffoldYamlPath)) {
|
|
1381
|
-
const relativePath = node_path.default.join(item, subItem);
|
|
1382
|
-
templateDirs.push(relativePath);
|
|
1383
|
-
}
|
|
1384
|
-
}
|
|
1385
|
-
} catch (error) {
|
|
1386
|
-
__agiflowai_aicode_utils.log.warn(`Failed to read subdirectories in ${itemPath}:`, error);
|
|
1387
|
-
}
|
|
1388
|
-
}
|
|
1389
|
-
} catch (error) {
|
|
1390
|
-
__agiflowai_aicode_utils.log.warn(`Failed to read templates root directory ${this.templatesRootPath}:`, error);
|
|
1391
|
-
}
|
|
1392
|
-
return templateDirs;
|
|
1393
|
-
}
|
|
1394
|
-
async useScaffoldMethod(request) {
|
|
1395
|
-
const { projectPath, scaffold_feature_name, variables } = request;
|
|
1396
|
-
const absoluteProjectPath = await this.resolveProjectPath(projectPath);
|
|
1397
|
-
const scaffoldingMethods = await this.listScaffoldingMethods(absoluteProjectPath);
|
|
1398
|
-
const method = scaffoldingMethods.methods.find((m) => m.name === scaffold_feature_name);
|
|
1399
|
-
if (!method) {
|
|
1400
|
-
const availableMethods = scaffoldingMethods.methods.map((m) => m.name).join(", ");
|
|
1401
|
-
throw new Error(`Scaffold method '${scaffold_feature_name}' not found. Available methods: ${availableMethods}`);
|
|
1402
|
-
}
|
|
1403
|
-
const ScaffoldService$1 = (await Promise.resolve().then(() => require("./ScaffoldService-B3En_m4t.cjs"))).ScaffoldService;
|
|
1404
|
-
const ScaffoldConfigLoader$1 = (await Promise.resolve().then(() => require("./ScaffoldConfigLoader-DQMCLVGD.cjs"))).ScaffoldConfigLoader;
|
|
1405
|
-
const VariableReplacementService$1 = (await Promise.resolve().then(() => require("./VariableReplacementService-CroHkMha.cjs"))).VariableReplacementService;
|
|
1406
|
-
const TemplateService$1 = (await Promise.resolve().then(() => require("./TemplateService-BZRt3NI8.cjs"))).TemplateService;
|
|
1407
|
-
const templateService = new TemplateService$1();
|
|
1408
|
-
const scaffoldConfigLoader = new ScaffoldConfigLoader$1(this.fileSystem, templateService);
|
|
1409
|
-
const variableReplacer = new VariableReplacementService$1(this.fileSystem, templateService);
|
|
1410
|
-
const scaffoldService = new ScaffoldService$1(this.fileSystem, scaffoldConfigLoader, variableReplacer, this.templatesRootPath);
|
|
1411
|
-
const projectName = node_path.default.basename(absoluteProjectPath);
|
|
1412
|
-
const result = await scaffoldService.useFeature({
|
|
1413
|
-
projectPath: absoluteProjectPath,
|
|
1414
|
-
templateFolder: scaffoldingMethods.templatePath,
|
|
1415
|
-
featureName: scaffold_feature_name,
|
|
1416
|
-
variables: {
|
|
1417
|
-
...variables,
|
|
1418
|
-
appPath: absoluteProjectPath,
|
|
1419
|
-
appName: projectName
|
|
1420
|
-
}
|
|
1421
|
-
});
|
|
1422
|
-
if (!result.success) throw new Error(result.message);
|
|
1423
|
-
return {
|
|
1424
|
-
success: true,
|
|
1425
|
-
message: `
|
|
1426
|
-
Successfully scaffolded ${scaffold_feature_name} in ${projectPath}.
|
|
1427
|
-
Please follow this **instruction**: \n ${method.instruction}.
|
|
1428
|
-
-> Create or update the plan based on the instruction.
|
|
1429
|
-
`,
|
|
1430
|
-
warnings: result.warnings,
|
|
1431
|
-
createdFiles: result.createdFiles,
|
|
1432
|
-
existingFiles: result.existingFiles
|
|
1433
|
-
};
|
|
1434
|
-
}
|
|
1435
|
-
};
|
|
1436
|
-
|
|
1437
1491
|
//#endregion
|
|
1438
1492
|
//#region src/tools/ListScaffoldingMethodsTool.ts
|
|
1439
1493
|
var ListScaffoldingMethodsTool = class ListScaffoldingMethodsTool {
|
|
@@ -1453,7 +1507,10 @@ var ListScaffoldingMethodsTool = class ListScaffoldingMethodsTool {
|
|
|
1453
1507
|
*/
|
|
1454
1508
|
getDefinition() {
|
|
1455
1509
|
const description = this.templateService.renderString(description_default$1, { isMonolith: this.isMonolith });
|
|
1456
|
-
const properties = {
|
|
1510
|
+
const properties = { cursor: {
|
|
1511
|
+
type: "string",
|
|
1512
|
+
description: "Optional pagination cursor to fetch the next page of results. Omit to fetch the first page."
|
|
1513
|
+
} };
|
|
1457
1514
|
if (!this.isMonolith) {
|
|
1458
1515
|
properties.projectPath = {
|
|
1459
1516
|
type: "string",
|
|
@@ -1479,18 +1536,18 @@ var ListScaffoldingMethodsTool = class ListScaffoldingMethodsTool {
|
|
|
1479
1536
|
*/
|
|
1480
1537
|
async execute(args) {
|
|
1481
1538
|
try {
|
|
1482
|
-
const { projectPath, templateName } = args;
|
|
1539
|
+
const { projectPath, templateName, cursor } = args;
|
|
1483
1540
|
let result;
|
|
1484
1541
|
if (this.isMonolith) try {
|
|
1485
1542
|
const resolvedTemplateName = (await __agiflowai_aicode_utils.ProjectConfigResolver.resolveProjectConfig(process.cwd())).sourceTemplate;
|
|
1486
|
-
result = await this.scaffoldingMethodsService.listScaffoldingMethodsByTemplate(resolvedTemplateName);
|
|
1543
|
+
result = await this.scaffoldingMethodsService.listScaffoldingMethodsByTemplate(resolvedTemplateName, cursor);
|
|
1487
1544
|
} catch (error) {
|
|
1488
1545
|
throw new Error(`Failed to read template name from configuration: ${error instanceof Error ? error.message : String(error)}`);
|
|
1489
1546
|
}
|
|
1490
1547
|
else {
|
|
1491
1548
|
if (!projectPath && !templateName) throw new Error("Either projectPath or templateName must be provided");
|
|
1492
|
-
if (projectPath) result = await this.scaffoldingMethodsService.listScaffoldingMethods(projectPath);
|
|
1493
|
-
else result = await this.scaffoldingMethodsService.listScaffoldingMethodsByTemplate(templateName);
|
|
1549
|
+
if (projectPath) result = await this.scaffoldingMethodsService.listScaffoldingMethods(projectPath, cursor);
|
|
1550
|
+
else result = await this.scaffoldingMethodsService.listScaffoldingMethodsByTemplate(templateName, cursor);
|
|
1494
1551
|
}
|
|
1495
1552
|
return { content: [{
|
|
1496
1553
|
type: "text",
|