@agiflowai/scaffold-mcp 1.0.3 → 1.0.5
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 +27 -124
- package/dist/{cli.js → cli.mjs} +27 -120
- package/dist/index.cjs +14 -18
- package/dist/{index.d.ts → index.d.mts} +1 -1
- package/dist/{index.js → index.mjs} +14 -16
- package/dist/{stdio-DM_C4xbZ.cjs → stdio-BGj_FLky.cjs} +410 -423
- package/dist/{stdio-BheRzmRj.js → stdio-wAlpLC6l.mjs} +413 -418
- 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,23 +1,181 @@
|
|
|
1
|
-
import { ScaffoldConfigLoader } from "./ScaffoldConfigLoader-
|
|
2
|
-
import { ScaffoldService } from "./ScaffoldService-
|
|
3
|
-
import { TemplateService } from "./TemplateService-
|
|
4
|
-
import { VariableReplacementService } from "./VariableReplacementService-
|
|
5
|
-
import { ProjectConfigResolver, log } from "@agiflowai/aicode-utils";
|
|
1
|
+
import { t as ScaffoldConfigLoader } from "./ScaffoldConfigLoader-BDMJNI1o.mjs";
|
|
2
|
+
import { t as ScaffoldService } from "./ScaffoldService-BNuN00Fm.mjs";
|
|
3
|
+
import { t as TemplateService } from "./TemplateService-Cg5QV29n.mjs";
|
|
4
|
+
import { t as VariableReplacementService } from "./VariableReplacementService-DHIINRnJ.mjs";
|
|
6
5
|
import * as path$1 from "node:path";
|
|
7
6
|
import path from "node:path";
|
|
8
|
-
import {
|
|
9
|
-
import * as fs$1 from "fs-extra";
|
|
10
|
-
import fs from "fs-extra";
|
|
7
|
+
import { ProjectConfigResolver, copy, ensureDir, log, pathExists, pathExistsSync, readFile, readFileSync, readJson, readdir, stat, statSync, writeFile } from "@agiflowai/aicode-utils";
|
|
11
8
|
import * as yaml$1 from "js-yaml";
|
|
12
9
|
import yaml from "js-yaml";
|
|
10
|
+
import { readdirSync } from "node:fs";
|
|
11
|
+
import { jsonSchemaToZod } from "@composio/json-schema-to-zod";
|
|
13
12
|
import { z } from "zod";
|
|
14
|
-
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
15
13
|
import { randomUUID } from "node:crypto";
|
|
16
14
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
15
|
+
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
|
|
17
16
|
import express from "express";
|
|
18
17
|
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
19
18
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
20
19
|
|
|
20
|
+
//#region src/services/BoilerplateGeneratorService.ts
|
|
21
|
+
/**
|
|
22
|
+
* Service for generating boilerplate configurations in scaffold.yaml files
|
|
23
|
+
*/
|
|
24
|
+
var BoilerplateGeneratorService = class {
|
|
25
|
+
templatesPath;
|
|
26
|
+
constructor(templatesPath) {
|
|
27
|
+
this.templatesPath = templatesPath;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Custom YAML dumper that forces literal block style (|) for description and instruction fields
|
|
31
|
+
*/
|
|
32
|
+
dumpYamlWithLiteralBlocks(config) {
|
|
33
|
+
const LiteralBlockType = new yaml$1.Type("tag:yaml.org,2002:str", {
|
|
34
|
+
kind: "scalar",
|
|
35
|
+
construct: (data) => data,
|
|
36
|
+
represent: (data) => {
|
|
37
|
+
return data;
|
|
38
|
+
},
|
|
39
|
+
defaultStyle: "|"
|
|
40
|
+
});
|
|
41
|
+
const LITERAL_SCHEMA = yaml$1.DEFAULT_SCHEMA.extend([LiteralBlockType]);
|
|
42
|
+
const processedConfig = this.processConfigForLiteralBlocks(config);
|
|
43
|
+
return yaml$1.dump(processedConfig, {
|
|
44
|
+
schema: LITERAL_SCHEMA,
|
|
45
|
+
indent: 2,
|
|
46
|
+
lineWidth: -1,
|
|
47
|
+
noRefs: true,
|
|
48
|
+
sortKeys: false,
|
|
49
|
+
styles: { "!!str": "literal" },
|
|
50
|
+
replacer: (key, value) => {
|
|
51
|
+
if ((key === "description" || key === "instruction") && typeof value === "string") return value;
|
|
52
|
+
return value;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Process config to ensure description and instruction use literal block style
|
|
58
|
+
*/
|
|
59
|
+
processConfigForLiteralBlocks(config) {
|
|
60
|
+
const processed = JSON.parse(JSON.stringify(config));
|
|
61
|
+
if (processed.boilerplate) processed.boilerplate = processed.boilerplate.map((bp) => {
|
|
62
|
+
const newBp = { ...bp };
|
|
63
|
+
if (newBp.description && typeof newBp.description === "string") newBp.description = this.ensureMultilineFormat(newBp.description);
|
|
64
|
+
if (newBp.instruction && typeof newBp.instruction === "string") newBp.instruction = this.ensureMultilineFormat(newBp.instruction);
|
|
65
|
+
return newBp;
|
|
66
|
+
});
|
|
67
|
+
if (processed.features) processed.features = processed.features.map((feature) => {
|
|
68
|
+
const newFeature = { ...feature };
|
|
69
|
+
if (newFeature.description && typeof newFeature.description === "string") newFeature.description = this.ensureMultilineFormat(newFeature.description);
|
|
70
|
+
if (newFeature.instruction && typeof newFeature.instruction === "string") newFeature.instruction = this.ensureMultilineFormat(newFeature.instruction);
|
|
71
|
+
return newFeature;
|
|
72
|
+
});
|
|
73
|
+
return processed;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Ensure string is properly formatted for YAML literal blocks
|
|
77
|
+
*/
|
|
78
|
+
ensureMultilineFormat(text) {
|
|
79
|
+
return text.trim();
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Generate or update a boilerplate configuration in scaffold.yaml
|
|
83
|
+
*/
|
|
84
|
+
async generateBoilerplate(options) {
|
|
85
|
+
const { templateName, boilerplateName, description, instruction, targetFolder, variables, includes = [] } = options;
|
|
86
|
+
const templatePath = path$1.join(this.templatesPath, templateName);
|
|
87
|
+
await ensureDir(templatePath);
|
|
88
|
+
const scaffoldYamlPath = path$1.join(templatePath, "scaffold.yaml");
|
|
89
|
+
let scaffoldConfig = {};
|
|
90
|
+
if (await pathExists(scaffoldYamlPath)) {
|
|
91
|
+
const yamlContent = await readFile(scaffoldYamlPath, "utf-8");
|
|
92
|
+
scaffoldConfig = yaml$1.load(yamlContent);
|
|
93
|
+
}
|
|
94
|
+
if (!scaffoldConfig.boilerplate) scaffoldConfig.boilerplate = [];
|
|
95
|
+
if (scaffoldConfig.boilerplate.findIndex((b) => b.name === boilerplateName) !== -1) return {
|
|
96
|
+
success: false,
|
|
97
|
+
message: `Boilerplate '${boilerplateName}' already exists in ${scaffoldYamlPath}`
|
|
98
|
+
};
|
|
99
|
+
const requiredVars = variables.filter((v) => v.required).map((v) => v.name);
|
|
100
|
+
const boilerplateDefinition = {
|
|
101
|
+
name: boilerplateName,
|
|
102
|
+
targetFolder,
|
|
103
|
+
description,
|
|
104
|
+
variables_schema: {
|
|
105
|
+
type: "object",
|
|
106
|
+
properties: variables.reduce((acc, v) => {
|
|
107
|
+
acc[v.name] = {
|
|
108
|
+
type: v.type,
|
|
109
|
+
description: v.description
|
|
110
|
+
};
|
|
111
|
+
if (v.default !== void 0) acc[v.name].default = v.default;
|
|
112
|
+
return acc;
|
|
113
|
+
}, {}),
|
|
114
|
+
required: requiredVars,
|
|
115
|
+
additionalProperties: false
|
|
116
|
+
},
|
|
117
|
+
includes: includes.length > 0 ? includes : []
|
|
118
|
+
};
|
|
119
|
+
if (instruction) boilerplateDefinition.instruction = instruction;
|
|
120
|
+
scaffoldConfig.boilerplate.push(boilerplateDefinition);
|
|
121
|
+
await writeFile(scaffoldYamlPath, this.dumpYamlWithLiteralBlocks(scaffoldConfig), "utf-8");
|
|
122
|
+
return {
|
|
123
|
+
success: true,
|
|
124
|
+
message: `Boilerplate '${boilerplateName}' added to ${scaffoldYamlPath}`,
|
|
125
|
+
templatePath,
|
|
126
|
+
scaffoldYamlPath
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* List all templates (directories in templates folder)
|
|
131
|
+
*/
|
|
132
|
+
async listTemplates() {
|
|
133
|
+
return (await readdir(this.templatesPath, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Check if a template exists
|
|
137
|
+
*/
|
|
138
|
+
async templateExists(templateName) {
|
|
139
|
+
return pathExists(path$1.join(this.templatesPath, templateName));
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Create or update a template file for a boilerplate
|
|
143
|
+
*/
|
|
144
|
+
async createTemplateFile(options) {
|
|
145
|
+
const { templateName, filePath, content, sourceFile, header } = options;
|
|
146
|
+
const templatePath = path$1.join(this.templatesPath, templateName);
|
|
147
|
+
if (!await pathExists(templatePath)) return {
|
|
148
|
+
success: false,
|
|
149
|
+
message: `Template directory '${templateName}' does not exist at ${templatePath}`
|
|
150
|
+
};
|
|
151
|
+
let fileContent = content || "";
|
|
152
|
+
if (sourceFile) {
|
|
153
|
+
if (!await pathExists(sourceFile)) return {
|
|
154
|
+
success: false,
|
|
155
|
+
message: `Source file '${sourceFile}' does not exist`
|
|
156
|
+
};
|
|
157
|
+
fileContent = await readFile(sourceFile, "utf-8");
|
|
158
|
+
}
|
|
159
|
+
if (!fileContent && !sourceFile) return {
|
|
160
|
+
success: false,
|
|
161
|
+
message: "Either content or sourceFile must be provided"
|
|
162
|
+
};
|
|
163
|
+
const templateFilePath = filePath.endsWith(".liquid") ? filePath : `${filePath}.liquid`;
|
|
164
|
+
const fullPath = path$1.join(templatePath, templateFilePath);
|
|
165
|
+
await ensureDir(path$1.dirname(fullPath));
|
|
166
|
+
let finalContent = fileContent;
|
|
167
|
+
if (header) finalContent = `${header}\n\n${fileContent}`;
|
|
168
|
+
await writeFile(fullPath, finalContent, "utf-8");
|
|
169
|
+
return {
|
|
170
|
+
success: true,
|
|
171
|
+
message: "Template file created successfully",
|
|
172
|
+
filePath: templateFilePath,
|
|
173
|
+
fullPath
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
//#endregion
|
|
21
179
|
//#region src/utils/pagination.ts
|
|
22
180
|
var PaginationHelper = class PaginationHelper {
|
|
23
181
|
/**
|
|
@@ -71,28 +229,28 @@ var PaginationHelper = class PaginationHelper {
|
|
|
71
229
|
//#region src/services/FileSystemService.ts
|
|
72
230
|
var FileSystemService = class {
|
|
73
231
|
async pathExists(path$2) {
|
|
74
|
-
return
|
|
232
|
+
return pathExists(path$2);
|
|
75
233
|
}
|
|
76
234
|
async readFile(path$2, encoding = "utf8") {
|
|
77
|
-
return
|
|
235
|
+
return readFile(path$2, encoding);
|
|
78
236
|
}
|
|
79
237
|
async readJson(path$2) {
|
|
80
|
-
return
|
|
238
|
+
return readJson(path$2);
|
|
81
239
|
}
|
|
82
240
|
async writeFile(path$2, content, encoding = "utf8") {
|
|
83
|
-
return
|
|
241
|
+
return writeFile(path$2, content, encoding);
|
|
84
242
|
}
|
|
85
243
|
async ensureDir(path$2) {
|
|
86
|
-
return
|
|
244
|
+
return ensureDir(path$2);
|
|
87
245
|
}
|
|
88
246
|
async copy(src, dest) {
|
|
89
|
-
return
|
|
247
|
+
return copy(src, dest);
|
|
90
248
|
}
|
|
91
249
|
async readdir(path$2) {
|
|
92
|
-
return
|
|
250
|
+
return readdir(path$2);
|
|
93
251
|
}
|
|
94
252
|
async stat(path$2) {
|
|
95
|
-
return
|
|
253
|
+
return stat(path$2);
|
|
96
254
|
}
|
|
97
255
|
};
|
|
98
256
|
|
|
@@ -118,8 +276,8 @@ var BoilerplateService = class {
|
|
|
118
276
|
const templateDirs = await this.discoverTemplateDirectories();
|
|
119
277
|
for (const templatePath of templateDirs) {
|
|
120
278
|
const scaffoldYamlPath = path$1.join(this.templatesPath, templatePath, "scaffold.yaml");
|
|
121
|
-
if (
|
|
122
|
-
const scaffoldContent =
|
|
279
|
+
if (pathExistsSync(scaffoldYamlPath)) try {
|
|
280
|
+
const scaffoldContent = readFileSync(scaffoldYamlPath, "utf8");
|
|
123
281
|
const scaffoldConfig = yaml$1.load(scaffoldContent);
|
|
124
282
|
if (scaffoldConfig.boilerplate) for (const boilerplate of scaffoldConfig.boilerplate) {
|
|
125
283
|
if (!boilerplate.targetFolder) {
|
|
@@ -154,14 +312,14 @@ var BoilerplateService = class {
|
|
|
154
312
|
async discoverTemplateDirectories() {
|
|
155
313
|
const templateDirs = [];
|
|
156
314
|
const findTemplates = (dir, baseDir = "") => {
|
|
157
|
-
if (!
|
|
158
|
-
const items =
|
|
315
|
+
if (!pathExistsSync(dir)) return;
|
|
316
|
+
const items = readdirSync(dir);
|
|
159
317
|
const hasPackageJson = items.includes("package.json") || items.includes("package.json.liquid");
|
|
160
318
|
const hasScaffoldYaml = items.includes("scaffold.yaml");
|
|
161
319
|
if (hasPackageJson && hasScaffoldYaml) templateDirs.push(baseDir);
|
|
162
320
|
for (const item of items) {
|
|
163
321
|
const itemPath = path$1.join(dir, item);
|
|
164
|
-
if (
|
|
322
|
+
if (statSync(itemPath).isDirectory() && !item.startsWith(".") && item !== "node_modules") findTemplates(itemPath, baseDir ? path$1.join(baseDir, item) : item);
|
|
165
323
|
}
|
|
166
324
|
};
|
|
167
325
|
findTemplates(this.templatesPath);
|
|
@@ -295,11 +453,11 @@ var BoilerplateService = class {
|
|
|
295
453
|
};
|
|
296
454
|
|
|
297
455
|
//#endregion
|
|
298
|
-
//#region src/services/
|
|
456
|
+
//#region src/services/ScaffoldGeneratorService.ts
|
|
299
457
|
/**
|
|
300
|
-
* Service for generating
|
|
458
|
+
* Service for generating feature scaffold configurations in scaffold.yaml files
|
|
301
459
|
*/
|
|
302
|
-
var
|
|
460
|
+
var ScaffoldGeneratorService = class {
|
|
303
461
|
templatesPath;
|
|
304
462
|
constructor(templatesPath) {
|
|
305
463
|
this.templatesPath = templatesPath;
|
|
@@ -357,27 +515,26 @@ var BoilerplateGeneratorService = class {
|
|
|
357
515
|
return text.trim();
|
|
358
516
|
}
|
|
359
517
|
/**
|
|
360
|
-
* Generate or update a
|
|
518
|
+
* Generate or update a feature configuration in scaffold.yaml
|
|
361
519
|
*/
|
|
362
|
-
async
|
|
363
|
-
const { templateName,
|
|
520
|
+
async generateFeatureScaffold(options) {
|
|
521
|
+
const { templateName, featureName, description, instruction, variables, includes = [], patterns = [] } = options;
|
|
364
522
|
const templatePath = path$1.join(this.templatesPath, templateName);
|
|
365
|
-
await
|
|
523
|
+
await ensureDir(templatePath);
|
|
366
524
|
const scaffoldYamlPath = path$1.join(templatePath, "scaffold.yaml");
|
|
367
525
|
let scaffoldConfig = {};
|
|
368
|
-
if (await
|
|
369
|
-
const yamlContent
|
|
370
|
-
scaffoldConfig = yaml$1.load(yamlContent
|
|
526
|
+
if (await pathExists(scaffoldYamlPath)) {
|
|
527
|
+
const yamlContent = await readFile(scaffoldYamlPath, "utf-8");
|
|
528
|
+
scaffoldConfig = yaml$1.load(yamlContent);
|
|
371
529
|
}
|
|
372
|
-
if (!scaffoldConfig.
|
|
373
|
-
if (scaffoldConfig.
|
|
530
|
+
if (!scaffoldConfig.features) scaffoldConfig.features = [];
|
|
531
|
+
if (scaffoldConfig.features.findIndex((f) => f.name === featureName) !== -1) return {
|
|
374
532
|
success: false,
|
|
375
|
-
message: `
|
|
533
|
+
message: `Feature '${featureName}' already exists in ${scaffoldYamlPath}`
|
|
376
534
|
};
|
|
377
535
|
const requiredVars = variables.filter((v) => v.required).map((v) => v.name);
|
|
378
|
-
const
|
|
379
|
-
name:
|
|
380
|
-
targetFolder,
|
|
536
|
+
const featureDefinition = {
|
|
537
|
+
name: featureName,
|
|
381
538
|
description,
|
|
382
539
|
variables_schema: {
|
|
383
540
|
type: "object",
|
|
@@ -394,13 +551,13 @@ var BoilerplateGeneratorService = class {
|
|
|
394
551
|
},
|
|
395
552
|
includes: includes.length > 0 ? includes : []
|
|
396
553
|
};
|
|
397
|
-
if (instruction)
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
await
|
|
554
|
+
if (instruction) featureDefinition.instruction = instruction;
|
|
555
|
+
if (patterns && patterns.length > 0) featureDefinition.patterns = patterns;
|
|
556
|
+
scaffoldConfig.features.push(featureDefinition);
|
|
557
|
+
await writeFile(scaffoldYamlPath, this.dumpYamlWithLiteralBlocks(scaffoldConfig), "utf-8");
|
|
401
558
|
return {
|
|
402
559
|
success: true,
|
|
403
|
-
message: `
|
|
560
|
+
message: `Feature '${featureName}' added to ${scaffoldYamlPath}`,
|
|
404
561
|
templatePath,
|
|
405
562
|
scaffoldYamlPath
|
|
406
563
|
};
|
|
@@ -409,91 +566,228 @@ var BoilerplateGeneratorService = class {
|
|
|
409
566
|
* List all templates (directories in templates folder)
|
|
410
567
|
*/
|
|
411
568
|
async listTemplates() {
|
|
412
|
-
return (await
|
|
569
|
+
return (await readdir(this.templatesPath, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
413
570
|
}
|
|
414
571
|
/**
|
|
415
572
|
* Check if a template exists
|
|
416
573
|
*/
|
|
417
574
|
async templateExists(templateName) {
|
|
418
|
-
|
|
419
|
-
return fs$1.pathExists(templatePath);
|
|
420
|
-
}
|
|
421
|
-
/**
|
|
422
|
-
* Create or update a template file for a boilerplate
|
|
423
|
-
*/
|
|
424
|
-
async createTemplateFile(options) {
|
|
425
|
-
const { templateName, filePath, content, sourceFile, header } = options;
|
|
426
|
-
const templatePath = path$1.join(this.templatesPath, templateName);
|
|
427
|
-
if (!await fs$1.pathExists(templatePath)) return {
|
|
428
|
-
success: false,
|
|
429
|
-
message: `Template directory '${templateName}' does not exist at ${templatePath}`
|
|
430
|
-
};
|
|
431
|
-
let fileContent = content || "";
|
|
432
|
-
if (sourceFile) {
|
|
433
|
-
if (!await fs$1.pathExists(sourceFile)) return {
|
|
434
|
-
success: false,
|
|
435
|
-
message: `Source file '${sourceFile}' does not exist`
|
|
436
|
-
};
|
|
437
|
-
fileContent = await fs$1.readFile(sourceFile, "utf-8");
|
|
438
|
-
}
|
|
439
|
-
if (!fileContent && !sourceFile) return {
|
|
440
|
-
success: false,
|
|
441
|
-
message: "Either content or sourceFile must be provided"
|
|
442
|
-
};
|
|
443
|
-
const templateFilePath = filePath.endsWith(".liquid") ? filePath : `${filePath}.liquid`;
|
|
444
|
-
const fullPath = path$1.join(templatePath, templateFilePath);
|
|
445
|
-
await fs$1.ensureDir(path$1.dirname(fullPath));
|
|
446
|
-
let finalContent = fileContent;
|
|
447
|
-
if (header) finalContent = `${header}\n\n${fileContent}`;
|
|
448
|
-
await fs$1.writeFile(fullPath, finalContent, "utf-8");
|
|
449
|
-
return {
|
|
450
|
-
success: true,
|
|
451
|
-
message: "Template file created successfully",
|
|
452
|
-
filePath: templateFilePath,
|
|
453
|
-
fullPath
|
|
454
|
-
};
|
|
575
|
+
return pathExists(path$1.join(this.templatesPath, templateName));
|
|
455
576
|
}
|
|
456
577
|
};
|
|
457
578
|
|
|
458
579
|
//#endregion
|
|
459
|
-
//#region src/
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
isMonolith;
|
|
467
|
-
constructor(templatesPath, isMonolith = false) {
|
|
468
|
-
this.boilerplateGeneratorService = new BoilerplateGeneratorService(templatesPath);
|
|
469
|
-
this.isMonolith = isMonolith;
|
|
580
|
+
//#region src/services/ScaffoldingMethodsService.ts
|
|
581
|
+
var ScaffoldingMethodsService = class {
|
|
582
|
+
templateService;
|
|
583
|
+
constructor(fileSystem, templatesRootPath) {
|
|
584
|
+
this.fileSystem = fileSystem;
|
|
585
|
+
this.templatesRootPath = templatesRootPath;
|
|
586
|
+
this.templateService = new TemplateService();
|
|
470
587
|
}
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
588
|
+
async listScaffoldingMethods(projectPath, cursor) {
|
|
589
|
+
const absoluteProjectPath = path.resolve(projectPath);
|
|
590
|
+
const sourceTemplate = (await ProjectConfigResolver.resolveProjectConfig(absoluteProjectPath)).sourceTemplate;
|
|
591
|
+
return this.listScaffoldingMethodsByTemplate(sourceTemplate, cursor);
|
|
592
|
+
}
|
|
593
|
+
async listScaffoldingMethodsByTemplate(templateName, cursor) {
|
|
594
|
+
const templatePath = await this.findTemplatePath(templateName);
|
|
595
|
+
if (!templatePath) throw new Error(`Template not found for sourceTemplate: ${templateName}`);
|
|
596
|
+
const fullTemplatePath = path.join(this.templatesRootPath, templatePath);
|
|
597
|
+
const scaffoldYamlPath = path.join(fullTemplatePath, "scaffold.yaml");
|
|
598
|
+
if (!await this.fileSystem.pathExists(scaffoldYamlPath)) throw new Error(`scaffold.yaml not found at ${scaffoldYamlPath}`);
|
|
599
|
+
const scaffoldContent = await this.fileSystem.readFile(scaffoldYamlPath, "utf8");
|
|
600
|
+
const architectConfig = yaml.load(scaffoldContent);
|
|
601
|
+
const methods = [];
|
|
602
|
+
if (architectConfig.features && Array.isArray(architectConfig.features)) architectConfig.features.forEach((feature) => {
|
|
603
|
+
const featureName = feature.name || `scaffold-${templateName}`;
|
|
604
|
+
methods.push({
|
|
605
|
+
name: featureName,
|
|
606
|
+
description: feature.description || "",
|
|
607
|
+
instruction: feature.instruction || "",
|
|
608
|
+
variables_schema: feature.variables_schema || {
|
|
609
|
+
type: "object",
|
|
610
|
+
properties: {},
|
|
611
|
+
required: [],
|
|
612
|
+
additionalProperties: false
|
|
613
|
+
},
|
|
614
|
+
generator: feature.generator
|
|
615
|
+
});
|
|
616
|
+
});
|
|
617
|
+
const paginatedResult = PaginationHelper.paginate(methods, cursor);
|
|
618
|
+
return {
|
|
619
|
+
sourceTemplate: templateName,
|
|
620
|
+
templatePath,
|
|
621
|
+
methods: paginatedResult.items,
|
|
622
|
+
nextCursor: paginatedResult.nextCursor,
|
|
623
|
+
_meta: paginatedResult._meta
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
/**
|
|
627
|
+
* Gets scaffolding methods with instructions rendered using provided variables
|
|
628
|
+
*/
|
|
629
|
+
async listScaffoldingMethodsWithVariables(projectPath, variables, cursor) {
|
|
630
|
+
const result = await this.listScaffoldingMethods(projectPath, cursor);
|
|
631
|
+
const processedMethods = result.methods.map((method) => ({
|
|
632
|
+
...method,
|
|
633
|
+
instruction: method.instruction ? this.processScaffoldInstruction(method.instruction, variables) : void 0
|
|
634
|
+
}));
|
|
635
|
+
return {
|
|
636
|
+
...result,
|
|
637
|
+
methods: processedMethods
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Processes scaffold instruction with template service
|
|
642
|
+
*/
|
|
643
|
+
processScaffoldInstruction(instruction, variables) {
|
|
644
|
+
if (this.templateService.containsTemplateVariables(instruction)) return this.templateService.renderString(instruction, variables);
|
|
645
|
+
return instruction;
|
|
646
|
+
}
|
|
647
|
+
async findTemplatePath(sourceTemplate) {
|
|
648
|
+
const templateDirs = await this.discoverTemplateDirs();
|
|
649
|
+
if (templateDirs.includes(sourceTemplate)) return sourceTemplate;
|
|
650
|
+
for (const templateDir of templateDirs) {
|
|
651
|
+
const templatePath = path.join(this.templatesRootPath, templateDir);
|
|
652
|
+
const scaffoldYamlPath = path.join(templatePath, "scaffold.yaml");
|
|
653
|
+
if (await this.fileSystem.pathExists(scaffoldYamlPath)) try {
|
|
654
|
+
const scaffoldContent = await this.fileSystem.readFile(scaffoldYamlPath, "utf8");
|
|
655
|
+
const architectConfig = yaml.load(scaffoldContent);
|
|
656
|
+
if (architectConfig.boilerplate && Array.isArray(architectConfig.boilerplate)) {
|
|
657
|
+
for (const boilerplate of architectConfig.boilerplate) if (boilerplate.name?.includes(sourceTemplate)) return templateDir;
|
|
658
|
+
}
|
|
659
|
+
} catch (error) {
|
|
660
|
+
log.warn(`Failed to read scaffold.yaml at ${scaffoldYamlPath}:`, error);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
return null;
|
|
664
|
+
}
|
|
665
|
+
/**
|
|
666
|
+
* Resolves the project path, handling both monorepo and monolith cases
|
|
667
|
+
* Uses ProjectConfigResolver to find the correct workspace/project root
|
|
668
|
+
*/
|
|
669
|
+
async resolveProjectPath(projectPath) {
|
|
670
|
+
const absolutePath = path.resolve(projectPath);
|
|
671
|
+
return (await ProjectConfigResolver.resolveProjectConfig(absolutePath)).workspaceRoot || absolutePath;
|
|
672
|
+
}
|
|
673
|
+
/**
|
|
674
|
+
* Dynamically discovers all template directories
|
|
675
|
+
* Supports both flat structure (templates/nextjs-15) and nested structure (templates/apps/nextjs-15)
|
|
676
|
+
**/
|
|
677
|
+
async discoverTemplateDirs() {
|
|
678
|
+
const templateDirs = [];
|
|
679
|
+
try {
|
|
680
|
+
const items = await this.fileSystem.readdir(this.templatesRootPath);
|
|
681
|
+
for (const item of items) {
|
|
682
|
+
const itemPath = path.join(this.templatesRootPath, item);
|
|
683
|
+
if (!(await this.fileSystem.stat(itemPath)).isDirectory()) continue;
|
|
684
|
+
const scaffoldYamlPath = path.join(itemPath, "scaffold.yaml");
|
|
685
|
+
if (await this.fileSystem.pathExists(scaffoldYamlPath)) {
|
|
686
|
+
templateDirs.push(item);
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
try {
|
|
690
|
+
const subItems = await this.fileSystem.readdir(itemPath);
|
|
691
|
+
for (const subItem of subItems) {
|
|
692
|
+
const subItemPath = path.join(itemPath, subItem);
|
|
693
|
+
if (!(await this.fileSystem.stat(subItemPath)).isDirectory()) continue;
|
|
694
|
+
const subScaffoldYamlPath = path.join(subItemPath, "scaffold.yaml");
|
|
695
|
+
if (await this.fileSystem.pathExists(subScaffoldYamlPath)) {
|
|
696
|
+
const relativePath = path.join(item, subItem);
|
|
697
|
+
templateDirs.push(relativePath);
|
|
698
|
+
}
|
|
699
|
+
}
|
|
700
|
+
} catch (error) {
|
|
701
|
+
log.warn(`Failed to read subdirectories in ${itemPath}:`, error);
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
} catch (error) {
|
|
705
|
+
log.warn(`Failed to read templates root directory ${this.templatesRootPath}:`, error);
|
|
706
|
+
}
|
|
707
|
+
return templateDirs;
|
|
708
|
+
}
|
|
709
|
+
async useScaffoldMethod(request) {
|
|
710
|
+
const { projectPath, scaffold_feature_name, variables } = request;
|
|
711
|
+
const absoluteProjectPath = await this.resolveProjectPath(projectPath);
|
|
712
|
+
const scaffoldingMethods = await this.listScaffoldingMethods(absoluteProjectPath);
|
|
713
|
+
const method = scaffoldingMethods.methods.find((m) => m.name === scaffold_feature_name);
|
|
714
|
+
if (!method) {
|
|
715
|
+
const availableMethods = scaffoldingMethods.methods.map((m) => m.name).join(", ");
|
|
716
|
+
throw new Error(`Scaffold method '${scaffold_feature_name}' not found. Available methods: ${availableMethods}`);
|
|
717
|
+
}
|
|
718
|
+
const ScaffoldService$1 = (await import("./ScaffoldService-BNdfC21Z.mjs")).ScaffoldService;
|
|
719
|
+
const ScaffoldConfigLoader$1 = (await import("./ScaffoldConfigLoader-SHk-KEje.mjs")).ScaffoldConfigLoader;
|
|
720
|
+
const VariableReplacementService$1 = (await import("./VariableReplacementService-BWCd-z7X.mjs")).VariableReplacementService;
|
|
721
|
+
const TemplateService$1 = (await import("./TemplateService-BRfzfaZs.mjs")).TemplateService;
|
|
722
|
+
const templateService = new TemplateService$1();
|
|
723
|
+
const scaffoldConfigLoader = new ScaffoldConfigLoader$1(this.fileSystem, templateService);
|
|
724
|
+
const variableReplacer = new VariableReplacementService$1(this.fileSystem, templateService);
|
|
725
|
+
const scaffoldService = new ScaffoldService$1(this.fileSystem, scaffoldConfigLoader, variableReplacer, this.templatesRootPath);
|
|
726
|
+
const projectName = path.basename(absoluteProjectPath);
|
|
727
|
+
const result = await scaffoldService.useFeature({
|
|
728
|
+
projectPath: absoluteProjectPath,
|
|
729
|
+
templateFolder: scaffoldingMethods.templatePath,
|
|
730
|
+
featureName: scaffold_feature_name,
|
|
731
|
+
variables: {
|
|
732
|
+
...variables,
|
|
733
|
+
appPath: absoluteProjectPath,
|
|
734
|
+
appName: projectName
|
|
735
|
+
}
|
|
736
|
+
});
|
|
737
|
+
if (!result.success) throw new Error(result.message);
|
|
738
|
+
return {
|
|
739
|
+
success: true,
|
|
740
|
+
message: `
|
|
741
|
+
Successfully scaffolded ${scaffold_feature_name} in ${projectPath}.
|
|
742
|
+
Please follow this **instruction**: \n ${method.instruction ? this.processScaffoldInstruction(method.instruction, variables) : ""}.
|
|
743
|
+
-> Create or update the plan based on the instruction.
|
|
744
|
+
`,
|
|
745
|
+
warnings: result.warnings,
|
|
746
|
+
createdFiles: result.createdFiles,
|
|
747
|
+
existingFiles: result.existingFiles
|
|
748
|
+
};
|
|
749
|
+
}
|
|
750
|
+
};
|
|
751
|
+
|
|
752
|
+
//#endregion
|
|
753
|
+
//#region src/tools/GenerateBoilerplateFileTool.ts
|
|
754
|
+
/**
|
|
755
|
+
* Tool to generate template files for boilerplates and features
|
|
756
|
+
*/
|
|
757
|
+
var GenerateBoilerplateFileTool = class GenerateBoilerplateFileTool {
|
|
758
|
+
static TOOL_NAME = "generate-boilerplate-file";
|
|
759
|
+
boilerplateGeneratorService;
|
|
760
|
+
isMonolith;
|
|
761
|
+
constructor(templatesPath, isMonolith = false) {
|
|
762
|
+
this.boilerplateGeneratorService = new BoilerplateGeneratorService(templatesPath);
|
|
763
|
+
this.isMonolith = isMonolith;
|
|
764
|
+
}
|
|
765
|
+
/**
|
|
766
|
+
* Get the tool definition for MCP
|
|
767
|
+
*/
|
|
768
|
+
getDefinition() {
|
|
769
|
+
const properties = {};
|
|
770
|
+
if (!this.isMonolith) properties.templateName = {
|
|
771
|
+
type: "string",
|
|
772
|
+
description: "Name of the template folder (must already exist)"
|
|
773
|
+
};
|
|
774
|
+
Object.assign(properties, {
|
|
775
|
+
filePath: {
|
|
776
|
+
type: "string",
|
|
777
|
+
description: "Path of the file to create within the template (e.g., \"package.json\", \"src/app/page.tsx\")"
|
|
778
|
+
},
|
|
779
|
+
content: {
|
|
780
|
+
type: "string",
|
|
781
|
+
description: `Content of the template file using Liquid template syntax.
|
|
782
|
+
|
|
783
|
+
LIQUID SYNTAX:
|
|
784
|
+
- Variables: {{ variableName }} - Replaced with actual values
|
|
785
|
+
- Conditionals: {% if condition %}...{% endif %} - Conditional rendering
|
|
786
|
+
- Else: {% if condition %}...{% else %}...{% endif %}
|
|
787
|
+
- Elsif: {% if condition %}...{% elsif other %}...{% endif %}
|
|
788
|
+
- Equality: {% if var == 'value' %}...{% endif %}
|
|
789
|
+
|
|
790
|
+
AVAILABLE FILTERS:
|
|
497
791
|
You can transform variables using these filters with the pipe (|) syntax:
|
|
498
792
|
|
|
499
793
|
Case Conversion:
|
|
@@ -912,132 +1206,6 @@ Use this to add custom boilerplate configurations for frameworks not yet support
|
|
|
912
1206
|
}
|
|
913
1207
|
};
|
|
914
1208
|
|
|
915
|
-
//#endregion
|
|
916
|
-
//#region src/services/ScaffoldGeneratorService.ts
|
|
917
|
-
/**
|
|
918
|
-
* Service for generating feature scaffold configurations in scaffold.yaml files
|
|
919
|
-
*/
|
|
920
|
-
var ScaffoldGeneratorService = class {
|
|
921
|
-
templatesPath;
|
|
922
|
-
constructor(templatesPath) {
|
|
923
|
-
this.templatesPath = templatesPath;
|
|
924
|
-
}
|
|
925
|
-
/**
|
|
926
|
-
* Custom YAML dumper that forces literal block style (|) for description and instruction fields
|
|
927
|
-
*/
|
|
928
|
-
dumpYamlWithLiteralBlocks(config) {
|
|
929
|
-
const LiteralBlockType = new yaml$1.Type("tag:yaml.org,2002:str", {
|
|
930
|
-
kind: "scalar",
|
|
931
|
-
construct: (data) => data,
|
|
932
|
-
represent: (data) => {
|
|
933
|
-
return data;
|
|
934
|
-
},
|
|
935
|
-
defaultStyle: "|"
|
|
936
|
-
});
|
|
937
|
-
const LITERAL_SCHEMA = yaml$1.DEFAULT_SCHEMA.extend([LiteralBlockType]);
|
|
938
|
-
const processedConfig = this.processConfigForLiteralBlocks(config);
|
|
939
|
-
return yaml$1.dump(processedConfig, {
|
|
940
|
-
schema: LITERAL_SCHEMA,
|
|
941
|
-
indent: 2,
|
|
942
|
-
lineWidth: -1,
|
|
943
|
-
noRefs: true,
|
|
944
|
-
sortKeys: false,
|
|
945
|
-
styles: { "!!str": "literal" },
|
|
946
|
-
replacer: (key, value) => {
|
|
947
|
-
if ((key === "description" || key === "instruction") && typeof value === "string") return value;
|
|
948
|
-
return value;
|
|
949
|
-
}
|
|
950
|
-
});
|
|
951
|
-
}
|
|
952
|
-
/**
|
|
953
|
-
* Process config to ensure description and instruction use literal block style
|
|
954
|
-
*/
|
|
955
|
-
processConfigForLiteralBlocks(config) {
|
|
956
|
-
const processed = JSON.parse(JSON.stringify(config));
|
|
957
|
-
if (processed.boilerplate) processed.boilerplate = processed.boilerplate.map((bp) => {
|
|
958
|
-
const newBp = { ...bp };
|
|
959
|
-
if (newBp.description && typeof newBp.description === "string") newBp.description = this.ensureMultilineFormat(newBp.description);
|
|
960
|
-
if (newBp.instruction && typeof newBp.instruction === "string") newBp.instruction = this.ensureMultilineFormat(newBp.instruction);
|
|
961
|
-
return newBp;
|
|
962
|
-
});
|
|
963
|
-
if (processed.features) processed.features = processed.features.map((feature) => {
|
|
964
|
-
const newFeature = { ...feature };
|
|
965
|
-
if (newFeature.description && typeof newFeature.description === "string") newFeature.description = this.ensureMultilineFormat(newFeature.description);
|
|
966
|
-
if (newFeature.instruction && typeof newFeature.instruction === "string") newFeature.instruction = this.ensureMultilineFormat(newFeature.instruction);
|
|
967
|
-
return newFeature;
|
|
968
|
-
});
|
|
969
|
-
return processed;
|
|
970
|
-
}
|
|
971
|
-
/**
|
|
972
|
-
* Ensure string is properly formatted for YAML literal blocks
|
|
973
|
-
*/
|
|
974
|
-
ensureMultilineFormat(text) {
|
|
975
|
-
return text.trim();
|
|
976
|
-
}
|
|
977
|
-
/**
|
|
978
|
-
* Generate or update a feature configuration in scaffold.yaml
|
|
979
|
-
*/
|
|
980
|
-
async generateFeatureScaffold(options) {
|
|
981
|
-
const { templateName, featureName, description, instruction, variables, includes = [], patterns = [] } = options;
|
|
982
|
-
const templatePath = path$1.join(this.templatesPath, templateName);
|
|
983
|
-
await fs$1.ensureDir(templatePath);
|
|
984
|
-
const scaffoldYamlPath = path$1.join(templatePath, "scaffold.yaml");
|
|
985
|
-
let scaffoldConfig = {};
|
|
986
|
-
if (await fs$1.pathExists(scaffoldYamlPath)) {
|
|
987
|
-
const yamlContent$1 = await fs$1.readFile(scaffoldYamlPath, "utf-8");
|
|
988
|
-
scaffoldConfig = yaml$1.load(yamlContent$1);
|
|
989
|
-
}
|
|
990
|
-
if (!scaffoldConfig.features) scaffoldConfig.features = [];
|
|
991
|
-
if (scaffoldConfig.features.findIndex((f) => f.name === featureName) !== -1) return {
|
|
992
|
-
success: false,
|
|
993
|
-
message: `Feature '${featureName}' already exists in ${scaffoldYamlPath}`
|
|
994
|
-
};
|
|
995
|
-
const requiredVars = variables.filter((v) => v.required).map((v) => v.name);
|
|
996
|
-
const featureDefinition = {
|
|
997
|
-
name: featureName,
|
|
998
|
-
description,
|
|
999
|
-
variables_schema: {
|
|
1000
|
-
type: "object",
|
|
1001
|
-
properties: variables.reduce((acc, v) => {
|
|
1002
|
-
acc[v.name] = {
|
|
1003
|
-
type: v.type,
|
|
1004
|
-
description: v.description
|
|
1005
|
-
};
|
|
1006
|
-
if (v.default !== void 0) acc[v.name].default = v.default;
|
|
1007
|
-
return acc;
|
|
1008
|
-
}, {}),
|
|
1009
|
-
required: requiredVars,
|
|
1010
|
-
additionalProperties: false
|
|
1011
|
-
},
|
|
1012
|
-
includes: includes.length > 0 ? includes : []
|
|
1013
|
-
};
|
|
1014
|
-
if (instruction) featureDefinition.instruction = instruction;
|
|
1015
|
-
if (patterns && patterns.length > 0) featureDefinition.patterns = patterns;
|
|
1016
|
-
scaffoldConfig.features.push(featureDefinition);
|
|
1017
|
-
const yamlContent = this.dumpYamlWithLiteralBlocks(scaffoldConfig);
|
|
1018
|
-
await fs$1.writeFile(scaffoldYamlPath, yamlContent, "utf-8");
|
|
1019
|
-
return {
|
|
1020
|
-
success: true,
|
|
1021
|
-
message: `Feature '${featureName}' added to ${scaffoldYamlPath}`,
|
|
1022
|
-
templatePath,
|
|
1023
|
-
scaffoldYamlPath
|
|
1024
|
-
};
|
|
1025
|
-
}
|
|
1026
|
-
/**
|
|
1027
|
-
* List all templates (directories in templates folder)
|
|
1028
|
-
*/
|
|
1029
|
-
async listTemplates() {
|
|
1030
|
-
return (await fs$1.readdir(this.templatesPath, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name);
|
|
1031
|
-
}
|
|
1032
|
-
/**
|
|
1033
|
-
* Check if a template exists
|
|
1034
|
-
*/
|
|
1035
|
-
async templateExists(templateName) {
|
|
1036
|
-
const templatePath = path$1.join(this.templatesPath, templateName);
|
|
1037
|
-
return fs$1.pathExists(templatePath);
|
|
1038
|
-
}
|
|
1039
|
-
};
|
|
1040
|
-
|
|
1041
1209
|
//#endregion
|
|
1042
1210
|
//#region src/tools/GenerateFeatureScaffoldTool.ts
|
|
1043
1211
|
/**
|
|
@@ -1318,179 +1486,6 @@ var ListBoilerplatesTool = class ListBoilerplatesTool {
|
|
|
1318
1486
|
//#region src/instructions/tools/list-scaffolding-methods/description.md?raw
|
|
1319
1487
|
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";
|
|
1320
1488
|
|
|
1321
|
-
//#endregion
|
|
1322
|
-
//#region src/services/ScaffoldingMethodsService.ts
|
|
1323
|
-
var ScaffoldingMethodsService = class {
|
|
1324
|
-
templateService;
|
|
1325
|
-
constructor(fileSystem, templatesRootPath) {
|
|
1326
|
-
this.fileSystem = fileSystem;
|
|
1327
|
-
this.templatesRootPath = templatesRootPath;
|
|
1328
|
-
this.templateService = new TemplateService();
|
|
1329
|
-
}
|
|
1330
|
-
async listScaffoldingMethods(projectPath, cursor) {
|
|
1331
|
-
const absoluteProjectPath = path.resolve(projectPath);
|
|
1332
|
-
const sourceTemplate = (await ProjectConfigResolver.resolveProjectConfig(absoluteProjectPath)).sourceTemplate;
|
|
1333
|
-
return this.listScaffoldingMethodsByTemplate(sourceTemplate, cursor);
|
|
1334
|
-
}
|
|
1335
|
-
async listScaffoldingMethodsByTemplate(templateName, cursor) {
|
|
1336
|
-
const templatePath = await this.findTemplatePath(templateName);
|
|
1337
|
-
if (!templatePath) throw new Error(`Template not found for sourceTemplate: ${templateName}`);
|
|
1338
|
-
const fullTemplatePath = path.join(this.templatesRootPath, templatePath);
|
|
1339
|
-
const scaffoldYamlPath = path.join(fullTemplatePath, "scaffold.yaml");
|
|
1340
|
-
if (!await this.fileSystem.pathExists(scaffoldYamlPath)) throw new Error(`scaffold.yaml not found at ${scaffoldYamlPath}`);
|
|
1341
|
-
const scaffoldContent = await this.fileSystem.readFile(scaffoldYamlPath, "utf8");
|
|
1342
|
-
const architectConfig = yaml.load(scaffoldContent);
|
|
1343
|
-
const methods = [];
|
|
1344
|
-
if (architectConfig.features && Array.isArray(architectConfig.features)) architectConfig.features.forEach((feature) => {
|
|
1345
|
-
const featureName = feature.name || `scaffold-${templateName}`;
|
|
1346
|
-
methods.push({
|
|
1347
|
-
name: featureName,
|
|
1348
|
-
description: feature.description || "",
|
|
1349
|
-
instruction: feature.instruction || "",
|
|
1350
|
-
variables_schema: feature.variables_schema || {
|
|
1351
|
-
type: "object",
|
|
1352
|
-
properties: {},
|
|
1353
|
-
required: [],
|
|
1354
|
-
additionalProperties: false
|
|
1355
|
-
},
|
|
1356
|
-
generator: feature.generator
|
|
1357
|
-
});
|
|
1358
|
-
});
|
|
1359
|
-
const paginatedResult = PaginationHelper.paginate(methods, cursor);
|
|
1360
|
-
return {
|
|
1361
|
-
sourceTemplate: templateName,
|
|
1362
|
-
templatePath,
|
|
1363
|
-
methods: paginatedResult.items,
|
|
1364
|
-
nextCursor: paginatedResult.nextCursor,
|
|
1365
|
-
_meta: paginatedResult._meta
|
|
1366
|
-
};
|
|
1367
|
-
}
|
|
1368
|
-
/**
|
|
1369
|
-
* Gets scaffolding methods with instructions rendered using provided variables
|
|
1370
|
-
*/
|
|
1371
|
-
async listScaffoldingMethodsWithVariables(projectPath, variables, cursor) {
|
|
1372
|
-
const result = await this.listScaffoldingMethods(projectPath, cursor);
|
|
1373
|
-
const processedMethods = result.methods.map((method) => ({
|
|
1374
|
-
...method,
|
|
1375
|
-
instruction: method.instruction ? this.processScaffoldInstruction(method.instruction, variables) : void 0
|
|
1376
|
-
}));
|
|
1377
|
-
return {
|
|
1378
|
-
...result,
|
|
1379
|
-
methods: processedMethods
|
|
1380
|
-
};
|
|
1381
|
-
}
|
|
1382
|
-
/**
|
|
1383
|
-
* Processes scaffold instruction with template service
|
|
1384
|
-
*/
|
|
1385
|
-
processScaffoldInstruction(instruction, variables) {
|
|
1386
|
-
if (this.templateService.containsTemplateVariables(instruction)) return this.templateService.renderString(instruction, variables);
|
|
1387
|
-
return instruction;
|
|
1388
|
-
}
|
|
1389
|
-
async findTemplatePath(sourceTemplate) {
|
|
1390
|
-
const templateDirs = await this.discoverTemplateDirs();
|
|
1391
|
-
if (templateDirs.includes(sourceTemplate)) return sourceTemplate;
|
|
1392
|
-
for (const templateDir of templateDirs) {
|
|
1393
|
-
const templatePath = path.join(this.templatesRootPath, templateDir);
|
|
1394
|
-
const scaffoldYamlPath = path.join(templatePath, "scaffold.yaml");
|
|
1395
|
-
if (await this.fileSystem.pathExists(scaffoldYamlPath)) try {
|
|
1396
|
-
const scaffoldContent = await this.fileSystem.readFile(scaffoldYamlPath, "utf8");
|
|
1397
|
-
const architectConfig = yaml.load(scaffoldContent);
|
|
1398
|
-
if (architectConfig.boilerplate && Array.isArray(architectConfig.boilerplate)) {
|
|
1399
|
-
for (const boilerplate of architectConfig.boilerplate) if (boilerplate.name?.includes(sourceTemplate)) return templateDir;
|
|
1400
|
-
}
|
|
1401
|
-
} catch (error) {
|
|
1402
|
-
log.warn(`Failed to read scaffold.yaml at ${scaffoldYamlPath}:`, error);
|
|
1403
|
-
}
|
|
1404
|
-
}
|
|
1405
|
-
return null;
|
|
1406
|
-
}
|
|
1407
|
-
/**
|
|
1408
|
-
* Resolves the project path, handling both monorepo and monolith cases
|
|
1409
|
-
* Uses ProjectConfigResolver to find the correct workspace/project root
|
|
1410
|
-
*/
|
|
1411
|
-
async resolveProjectPath(projectPath) {
|
|
1412
|
-
const absolutePath = path.resolve(projectPath);
|
|
1413
|
-
return (await ProjectConfigResolver.resolveProjectConfig(absolutePath)).workspaceRoot || absolutePath;
|
|
1414
|
-
}
|
|
1415
|
-
/**
|
|
1416
|
-
* Dynamically discovers all template directories
|
|
1417
|
-
* Supports both flat structure (templates/nextjs-15) and nested structure (templates/apps/nextjs-15)
|
|
1418
|
-
**/
|
|
1419
|
-
async discoverTemplateDirs() {
|
|
1420
|
-
const templateDirs = [];
|
|
1421
|
-
try {
|
|
1422
|
-
const items = await this.fileSystem.readdir(this.templatesRootPath);
|
|
1423
|
-
for (const item of items) {
|
|
1424
|
-
const itemPath = path.join(this.templatesRootPath, item);
|
|
1425
|
-
if (!(await this.fileSystem.stat(itemPath)).isDirectory()) continue;
|
|
1426
|
-
const scaffoldYamlPath = path.join(itemPath, "scaffold.yaml");
|
|
1427
|
-
if (await this.fileSystem.pathExists(scaffoldYamlPath)) {
|
|
1428
|
-
templateDirs.push(item);
|
|
1429
|
-
continue;
|
|
1430
|
-
}
|
|
1431
|
-
try {
|
|
1432
|
-
const subItems = await this.fileSystem.readdir(itemPath);
|
|
1433
|
-
for (const subItem of subItems) {
|
|
1434
|
-
const subItemPath = path.join(itemPath, subItem);
|
|
1435
|
-
if (!(await this.fileSystem.stat(subItemPath)).isDirectory()) continue;
|
|
1436
|
-
const subScaffoldYamlPath = path.join(subItemPath, "scaffold.yaml");
|
|
1437
|
-
if (await this.fileSystem.pathExists(subScaffoldYamlPath)) {
|
|
1438
|
-
const relativePath = path.join(item, subItem);
|
|
1439
|
-
templateDirs.push(relativePath);
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
} catch (error) {
|
|
1443
|
-
log.warn(`Failed to read subdirectories in ${itemPath}:`, error);
|
|
1444
|
-
}
|
|
1445
|
-
}
|
|
1446
|
-
} catch (error) {
|
|
1447
|
-
log.warn(`Failed to read templates root directory ${this.templatesRootPath}:`, error);
|
|
1448
|
-
}
|
|
1449
|
-
return templateDirs;
|
|
1450
|
-
}
|
|
1451
|
-
async useScaffoldMethod(request) {
|
|
1452
|
-
const { projectPath, scaffold_feature_name, variables } = request;
|
|
1453
|
-
const absoluteProjectPath = await this.resolveProjectPath(projectPath);
|
|
1454
|
-
const scaffoldingMethods = await this.listScaffoldingMethods(absoluteProjectPath);
|
|
1455
|
-
const method = scaffoldingMethods.methods.find((m) => m.name === scaffold_feature_name);
|
|
1456
|
-
if (!method) {
|
|
1457
|
-
const availableMethods = scaffoldingMethods.methods.map((m) => m.name).join(", ");
|
|
1458
|
-
throw new Error(`Scaffold method '${scaffold_feature_name}' not found. Available methods: ${availableMethods}`);
|
|
1459
|
-
}
|
|
1460
|
-
const ScaffoldService$1 = (await import("./ScaffoldService-CJ3vNmAj.js")).ScaffoldService;
|
|
1461
|
-
const ScaffoldConfigLoader$1 = (await import("./ScaffoldConfigLoader-DhthV6xq.js")).ScaffoldConfigLoader;
|
|
1462
|
-
const VariableReplacementService$1 = (await import("./VariableReplacementService-BAwTGv_R.js")).VariableReplacementService;
|
|
1463
|
-
const TemplateService$1 = (await import("./TemplateService-DropYdp8.js")).TemplateService;
|
|
1464
|
-
const templateService = new TemplateService$1();
|
|
1465
|
-
const scaffoldConfigLoader = new ScaffoldConfigLoader$1(this.fileSystem, templateService);
|
|
1466
|
-
const variableReplacer = new VariableReplacementService$1(this.fileSystem, templateService);
|
|
1467
|
-
const scaffoldService = new ScaffoldService$1(this.fileSystem, scaffoldConfigLoader, variableReplacer, this.templatesRootPath);
|
|
1468
|
-
const projectName = path.basename(absoluteProjectPath);
|
|
1469
|
-
const result = await scaffoldService.useFeature({
|
|
1470
|
-
projectPath: absoluteProjectPath,
|
|
1471
|
-
templateFolder: scaffoldingMethods.templatePath,
|
|
1472
|
-
featureName: scaffold_feature_name,
|
|
1473
|
-
variables: {
|
|
1474
|
-
...variables,
|
|
1475
|
-
appPath: absoluteProjectPath,
|
|
1476
|
-
appName: projectName
|
|
1477
|
-
}
|
|
1478
|
-
});
|
|
1479
|
-
if (!result.success) throw new Error(result.message);
|
|
1480
|
-
return {
|
|
1481
|
-
success: true,
|
|
1482
|
-
message: `
|
|
1483
|
-
Successfully scaffolded ${scaffold_feature_name} in ${projectPath}.
|
|
1484
|
-
Please follow this **instruction**: \n ${method.instruction ? this.processScaffoldInstruction(method.instruction, variables) : ""}.
|
|
1485
|
-
-> Create or update the plan based on the instruction.
|
|
1486
|
-
`,
|
|
1487
|
-
warnings: result.warnings,
|
|
1488
|
-
createdFiles: result.createdFiles,
|
|
1489
|
-
existingFiles: result.existingFiles
|
|
1490
|
-
};
|
|
1491
|
-
}
|
|
1492
|
-
};
|
|
1493
|
-
|
|
1494
1489
|
//#endregion
|
|
1495
1490
|
//#region src/tools/ListScaffoldingMethodsTool.ts
|
|
1496
1491
|
var ListScaffoldingMethodsTool = class ListScaffoldingMethodsTool {
|
|
@@ -2140,4 +2135,4 @@ var StdioTransportHandler = class {
|
|
|
2140
2135
|
};
|
|
2141
2136
|
|
|
2142
2137
|
//#endregion
|
|
2143
|
-
export {
|
|
2138
|
+
export { UseScaffoldMethodTool as a, ListBoilerplatesTool as c, GenerateBoilerplateFileTool as d, ScaffoldingMethodsService as f, BoilerplateGeneratorService as g, FileSystemService as h, WriteToFileTool as i, GenerateFeatureScaffoldTool as l, BoilerplateService as m, SseTransportHandler as n, UseBoilerplateTool as o, ScaffoldGeneratorService as p, HttpTransportHandler as r, ListScaffoldingMethodsTool as s, StdioTransportHandler as t, GenerateBoilerplateTool as u };
|