@agiflowai/scaffold-mcp 1.0.12 → 1.0.14

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.
Files changed (32) hide show
  1. package/dist/ListScaffoldingMethodsTool-B49G_iLj.mjs +350 -0
  2. package/dist/ListScaffoldingMethodsTool-DuYGFDwJ.cjs +376 -0
  3. package/dist/ScaffoldConfigLoader-8YI7v2GJ.mjs +142 -0
  4. package/dist/ScaffoldConfigLoader-BWpNpMx-.cjs +150 -0
  5. package/dist/ScaffoldConfigLoader-DKJtnrWT.mjs +3 -0
  6. package/dist/ScaffoldConfigLoader-HutEtfaH.cjs +3 -0
  7. package/dist/ScaffoldService-DSQBnAHm.cjs +308 -0
  8. package/dist/ScaffoldService-DcsGLMuD.mjs +295 -0
  9. package/dist/ScaffoldService-DfXjmrNT.cjs +3 -0
  10. package/dist/ScaffoldService-dL74anIv.mjs +3 -0
  11. package/dist/TemplateService-7QcWREot.cjs +85 -0
  12. package/dist/TemplateService-B1bd6iHw.mjs +3 -0
  13. package/dist/TemplateService-CVDL2uqt.mjs +79 -0
  14. package/dist/TemplateService-DUbdBOFs.cjs +3 -0
  15. package/dist/VariableReplacementService-B9RA8D0a.mjs +66 -0
  16. package/dist/VariableReplacementService-BO-UYgcf.mjs +3 -0
  17. package/dist/VariableReplacementService-DNYx0Dym.cjs +73 -0
  18. package/dist/VariableReplacementService-wuYKgeui.cjs +3 -0
  19. package/dist/chunk-CbDLau6x.cjs +34 -0
  20. package/dist/cli.cjs +16 -11
  21. package/dist/cli.mjs +9 -5
  22. package/dist/index.cjs +11 -7
  23. package/dist/index.mjs +6 -2
  24. package/dist/{stdio-DqZJsqKM.mjs → stdio-AbTm52SJ.mjs} +18 -15
  25. package/dist/{stdio-ohQyWnxq.cjs → stdio-baUp7xGL.cjs} +28 -24
  26. package/dist/{useScaffoldMethod-CC8ARsl9.mjs → useScaffoldMethod-BMWhFebp.mjs} +5 -7
  27. package/dist/{useScaffoldMethod-B-q_yBnX.mjs → useScaffoldMethod-CPgJIBHx.mjs} +2 -1
  28. package/dist/{useScaffoldMethod-DqF6pT1A.cjs → useScaffoldMethod-CcrpFEPv.cjs} +3 -1
  29. package/dist/{useScaffoldMethod-fzsnprJs.cjs → useScaffoldMethod-DOvwnNOJ.cjs} +9 -10
  30. package/package.json +3 -3
  31. package/dist/ListScaffoldingMethodsTool-D3ecmSLf.mjs +0 -994
  32. package/dist/ListScaffoldingMethodsTool-D7S3xpJE.cjs +0 -1082
@@ -0,0 +1,308 @@
1
+ const require_chunk = require('./chunk-CbDLau6x.cjs');
2
+ let node_path = require("node:path");
3
+ node_path = require_chunk.__toESM(node_path);
4
+ let __agiflowai_aicode_utils = require("@agiflowai/aicode-utils");
5
+ let node_url = require("node:url");
6
+
7
+ //#region src/services/ScaffoldProcessingService.ts
8
+ /**
9
+ * Shared service for common scaffolding operations like processing templates and tracking files
10
+ */
11
+ var ScaffoldProcessingService = class {
12
+ constructor(fileSystem, variableReplacer) {
13
+ this.fileSystem = fileSystem;
14
+ this.variableReplacer = variableReplacer;
15
+ }
16
+ /**
17
+ * Process a target path for variable replacement, handling both files and directories
18
+ */
19
+ async processTargetForVariableReplacement(targetPath, variables) {
20
+ if ((await this.fileSystem.stat(targetPath)).isDirectory()) await this.variableReplacer.processFilesForVariableReplacement(targetPath, variables);
21
+ else await this.variableReplacer.replaceVariablesInFile(targetPath, variables);
22
+ }
23
+ /**
24
+ * Track all created files, handling both single files and directories
25
+ */
26
+ async trackCreatedFiles(targetPath, createdFiles) {
27
+ if ((await this.fileSystem.stat(targetPath)).isDirectory()) await this.trackCreatedFilesRecursive(targetPath, createdFiles);
28
+ else createdFiles.push(targetPath);
29
+ }
30
+ /**
31
+ * Track all existing files, handling both single files and directories
32
+ */
33
+ async trackExistingFiles(targetPath, existingFiles) {
34
+ if ((await this.fileSystem.stat(targetPath)).isDirectory()) await this.trackExistingFilesRecursive(targetPath, existingFiles);
35
+ else existingFiles.push(targetPath);
36
+ }
37
+ /**
38
+ * Copy source to target, then process templates and track files
39
+ * Now supports tracking existing files separately from created files
40
+ * Automatically handles .liquid template files by stripping the extension
41
+ */
42
+ async copyAndProcess(sourcePath, targetPath, variables, createdFiles, existingFiles) {
43
+ await this.fileSystem.ensureDir(node_path.default.dirname(targetPath));
44
+ if (await this.fileSystem.pathExists(targetPath) && existingFiles) {
45
+ await this.trackExistingFiles(targetPath, existingFiles);
46
+ return;
47
+ }
48
+ let actualSourcePath = sourcePath;
49
+ if (!await this.fileSystem.pathExists(sourcePath)) {
50
+ const liquidSourcePath = `${sourcePath}.liquid`;
51
+ if (await this.fileSystem.pathExists(liquidSourcePath)) actualSourcePath = liquidSourcePath;
52
+ else throw new Error(`Source file not found: ${sourcePath} (also tried ${liquidSourcePath})`);
53
+ }
54
+ await this.fileSystem.copy(actualSourcePath, targetPath);
55
+ await this.processTargetForVariableReplacement(targetPath, variables);
56
+ await this.trackCreatedFiles(targetPath, createdFiles);
57
+ }
58
+ /**
59
+ * Recursively collect all file paths in a directory for created files
60
+ */
61
+ async trackCreatedFilesRecursive(dirPath, createdFiles) {
62
+ let items = [];
63
+ try {
64
+ items = await this.fileSystem.readdir(dirPath);
65
+ } catch (error) {
66
+ __agiflowai_aicode_utils.log.warn(`Cannot read directory ${dirPath}: ${error}`);
67
+ return;
68
+ }
69
+ for (const item of items) {
70
+ if (!item) continue;
71
+ const itemPath = node_path.default.join(dirPath, item);
72
+ try {
73
+ const stat = await this.fileSystem.stat(itemPath);
74
+ if (stat.isDirectory()) await this.trackCreatedFilesRecursive(itemPath, createdFiles);
75
+ else if (stat.isFile()) createdFiles.push(itemPath);
76
+ } catch (error) {
77
+ __agiflowai_aicode_utils.log.warn(`Cannot stat ${itemPath}: ${error}`);
78
+ }
79
+ }
80
+ }
81
+ /**
82
+ * Recursively collect all file paths in a directory for existing files
83
+ */
84
+ async trackExistingFilesRecursive(dirPath, existingFiles) {
85
+ let items = [];
86
+ try {
87
+ items = await this.fileSystem.readdir(dirPath);
88
+ } catch (error) {
89
+ __agiflowai_aicode_utils.log.warn(`Cannot read directory ${dirPath}: ${error}`);
90
+ return;
91
+ }
92
+ for (const item of items) {
93
+ if (!item) continue;
94
+ const itemPath = node_path.default.join(dirPath, item);
95
+ try {
96
+ const stat = await this.fileSystem.stat(itemPath);
97
+ if (stat.isDirectory()) await this.trackExistingFilesRecursive(itemPath, existingFiles);
98
+ else if (stat.isFile()) existingFiles.push(itemPath);
99
+ } catch (error) {
100
+ __agiflowai_aicode_utils.log.warn(`Cannot stat ${itemPath}: ${error}`);
101
+ }
102
+ }
103
+ }
104
+ };
105
+
106
+ //#endregion
107
+ //#region src/services/ScaffoldService.ts
108
+ var ScaffoldService = class {
109
+ templatesRootPath;
110
+ processingService;
111
+ constructor(fileSystem, scaffoldConfigLoader, variableReplacer, templatesRootPath) {
112
+ this.fileSystem = fileSystem;
113
+ this.scaffoldConfigLoader = scaffoldConfigLoader;
114
+ this.variableReplacer = variableReplacer;
115
+ const resolvedPath = templatesRootPath || __agiflowai_aicode_utils.TemplatesManagerService.findTemplatesPathSync();
116
+ if (!resolvedPath) throw new Error("Templates folder not found. Please create a \"templates\" folder in your workspace root, or specify \"templatesPath\" in toolkit.yaml to point to your templates directory.");
117
+ this.templatesRootPath = resolvedPath;
118
+ this.processingService = new ScaffoldProcessingService(fileSystem, variableReplacer);
119
+ }
120
+ /**
121
+ * Scaffold a new project from a boilerplate template
122
+ */
123
+ async useBoilerplate(options) {
124
+ try {
125
+ const { projectName, packageName, targetFolder, templateFolder, boilerplateName, variables = {} } = options;
126
+ const targetPath = node_path.default.isAbsolute(targetFolder) ? projectName ? node_path.default.join(targetFolder, projectName) : targetFolder : projectName ? node_path.default.join(process.cwd(), targetFolder, projectName) : node_path.default.join(process.cwd(), targetFolder);
127
+ const templatePath = node_path.default.join(this.templatesRootPath, templateFolder);
128
+ const validationResult = await this.scaffoldConfigLoader.validateTemplate(templatePath, "boilerplate");
129
+ if (!validationResult.isValid) return {
130
+ success: false,
131
+ message: `Template validation failed: ${[...validationResult.errors, ...validationResult.missingFiles.map((f) => `Template file not found: ${f}`)].join("; ")}`
132
+ };
133
+ if (projectName) {
134
+ if (await this.fileSystem.pathExists(targetPath)) return {
135
+ success: false,
136
+ message: `Directory ${targetPath} already exists`
137
+ };
138
+ }
139
+ const architectConfig = await this.scaffoldConfigLoader.parseArchitectConfig(templatePath);
140
+ if (!architectConfig || !architectConfig.boilerplate) return {
141
+ success: false,
142
+ message: `Invalid architect configuration: missing 'boilerplate' section in scaffold.yaml`
143
+ };
144
+ const boilerplateArray = architectConfig.boilerplate;
145
+ let config;
146
+ if (Array.isArray(boilerplateArray)) {
147
+ config = boilerplateArray.find((b) => b.name === boilerplateName);
148
+ if (!config) return {
149
+ success: false,
150
+ message: `Boilerplate '${boilerplateName}' not found in scaffold configuration`
151
+ };
152
+ } else config = architectConfig.boilerplate;
153
+ const effectiveProjectName = projectName || (packageName.includes("/") ? packageName.split("/")[1] : packageName);
154
+ const allVariables = {
155
+ ...variables,
156
+ projectName: effectiveProjectName,
157
+ packageName
158
+ };
159
+ return await this.processScaffold({
160
+ config,
161
+ targetPath,
162
+ templatePath,
163
+ allVariables,
164
+ scaffoldType: "boilerplate"
165
+ });
166
+ } catch (error) {
167
+ return {
168
+ success: false,
169
+ message: `Error scaffolding boilerplate: ${error instanceof Error ? error.message : String(error)}`
170
+ };
171
+ }
172
+ }
173
+ /**
174
+ * Scaffold a new feature into an existing project
175
+ */
176
+ async useFeature(options) {
177
+ try {
178
+ const { projectPath, templateFolder, featureName, variables = {} } = options;
179
+ const targetPath = node_path.default.resolve(projectPath);
180
+ const templatePath = node_path.default.join(this.templatesRootPath, templateFolder);
181
+ const projectName = node_path.default.basename(targetPath);
182
+ const validationResult = await this.scaffoldConfigLoader.validateTemplate(templatePath, "features");
183
+ if (!validationResult.isValid) return {
184
+ success: false,
185
+ message: `Template validation failed: ${[...validationResult.errors, ...validationResult.missingFiles.map((f) => `Template file not found: ${f}`)].join("; ")}`
186
+ };
187
+ if (!await this.fileSystem.pathExists(targetPath)) return {
188
+ success: false,
189
+ message: `Target directory ${targetPath} does not exist. Please create the parent directory first.`
190
+ };
191
+ const architectConfig = await this.scaffoldConfigLoader.parseArchitectConfig(templatePath);
192
+ if (!architectConfig || !architectConfig.features) return {
193
+ success: false,
194
+ message: `Invalid architect configuration: missing 'features' section in scaffold.yaml`
195
+ };
196
+ const featureArray = architectConfig.features;
197
+ let config;
198
+ if (Array.isArray(featureArray)) {
199
+ config = featureArray.find((f) => f.name === featureName);
200
+ if (!config) return {
201
+ success: false,
202
+ message: `Feature '${featureName}' not found in scaffold configuration`
203
+ };
204
+ } else config = architectConfig.features;
205
+ const allVariables = {
206
+ ...variables,
207
+ projectName,
208
+ appPath: targetPath,
209
+ appName: projectName
210
+ };
211
+ return await this.processScaffold({
212
+ config,
213
+ targetPath,
214
+ templatePath,
215
+ allVariables,
216
+ scaffoldType: "feature"
217
+ });
218
+ } catch (error) {
219
+ return {
220
+ success: false,
221
+ message: `Error scaffolding feature: ${error instanceof Error ? error.message : String(error)}`
222
+ };
223
+ }
224
+ }
225
+ /**
226
+ * Common scaffolding processing logic shared by both useBoilerplate and useFeature
227
+ */
228
+ async processScaffold(params) {
229
+ const { config, targetPath, templatePath, allVariables, scaffoldType } = params;
230
+ __agiflowai_aicode_utils.log.debug("Config generator:", config.generator);
231
+ __agiflowai_aicode_utils.log.debug("Config:", JSON.stringify(config, null, 2));
232
+ if (config.generator) {
233
+ __agiflowai_aicode_utils.log.info("Using custom generator:", config.generator);
234
+ try {
235
+ const generator = (await import(node_path.default.join(templatePath, "generators", config.generator))).default;
236
+ if (typeof generator !== "function") return {
237
+ success: false,
238
+ message: `Invalid generator: ${config.generator} does not export a default function`
239
+ };
240
+ return await generator({
241
+ variables: allVariables,
242
+ config,
243
+ targetPath,
244
+ templatePath,
245
+ fileSystem: this.fileSystem,
246
+ scaffoldConfigLoader: this.scaffoldConfigLoader,
247
+ variableReplacer: this.variableReplacer,
248
+ ScaffoldProcessingService: this.processingService.constructor,
249
+ getRootPath: () => {
250
+ const __dirname$1 = node_path.default.dirname((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
251
+ return node_path.default.join(__dirname$1, "../../../../..");
252
+ },
253
+ getProjectPath: (projectPath) => {
254
+ const __dirname$1 = node_path.default.dirname((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
255
+ const rootPath = node_path.default.join(__dirname$1, "../../../../..");
256
+ return projectPath.replace(rootPath, "").replace("/", "");
257
+ }
258
+ });
259
+ } catch (error) {
260
+ return {
261
+ success: false,
262
+ message: `Error loading or executing generator ${config.generator}: ${error instanceof Error ? error.message : String(error)}`
263
+ };
264
+ }
265
+ }
266
+ const parsedIncludes = [];
267
+ const warnings = [];
268
+ if (config.includes && Array.isArray(config.includes)) for (const includeEntry of config.includes) {
269
+ const parsed = this.scaffoldConfigLoader.parseIncludeEntry(includeEntry, allVariables);
270
+ if (!this.scaffoldConfigLoader.shouldIncludeFile(parsed.conditions, allVariables)) continue;
271
+ parsedIncludes.push(parsed);
272
+ const targetFilePath = node_path.default.join(targetPath, parsed.targetPath);
273
+ if (await this.fileSystem.pathExists(targetFilePath)) warnings.push(`File/folder ${parsed.targetPath} already exists and will be preserved`);
274
+ }
275
+ await this.fileSystem.ensureDir(targetPath);
276
+ const createdFiles = [];
277
+ const existingFiles = [];
278
+ for (const parsed of parsedIncludes) {
279
+ const sourcePath = node_path.default.join(templatePath, parsed.sourcePath);
280
+ const targetFilePath = node_path.default.join(targetPath, parsed.targetPath);
281
+ await this.processingService.copyAndProcess(sourcePath, targetFilePath, allVariables, createdFiles, existingFiles);
282
+ }
283
+ let message = `Successfully scaffolded ${scaffoldType} at ${targetPath}`;
284
+ if (existingFiles.length > 0) message += `. ${existingFiles.length} existing file(s) were preserved`;
285
+ message += ". Run 'pnpm install' to install dependencies.";
286
+ return {
287
+ success: true,
288
+ message,
289
+ warnings: warnings.length > 0 ? warnings : void 0,
290
+ createdFiles: createdFiles.length > 0 ? createdFiles : void 0,
291
+ existingFiles: existingFiles.length > 0 ? existingFiles : void 0
292
+ };
293
+ }
294
+ };
295
+
296
+ //#endregion
297
+ Object.defineProperty(exports, 'ScaffoldProcessingService', {
298
+ enumerable: true,
299
+ get: function () {
300
+ return ScaffoldProcessingService;
301
+ }
302
+ });
303
+ Object.defineProperty(exports, 'ScaffoldService', {
304
+ enumerable: true,
305
+ get: function () {
306
+ return ScaffoldService;
307
+ }
308
+ });
@@ -0,0 +1,295 @@
1
+ import path from "node:path";
2
+ import { TemplatesManagerService, log } from "@agiflowai/aicode-utils";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ //#region src/services/ScaffoldProcessingService.ts
6
+ /**
7
+ * Shared service for common scaffolding operations like processing templates and tracking files
8
+ */
9
+ var ScaffoldProcessingService = class {
10
+ constructor(fileSystem, variableReplacer) {
11
+ this.fileSystem = fileSystem;
12
+ this.variableReplacer = variableReplacer;
13
+ }
14
+ /**
15
+ * Process a target path for variable replacement, handling both files and directories
16
+ */
17
+ async processTargetForVariableReplacement(targetPath, variables) {
18
+ if ((await this.fileSystem.stat(targetPath)).isDirectory()) await this.variableReplacer.processFilesForVariableReplacement(targetPath, variables);
19
+ else await this.variableReplacer.replaceVariablesInFile(targetPath, variables);
20
+ }
21
+ /**
22
+ * Track all created files, handling both single files and directories
23
+ */
24
+ async trackCreatedFiles(targetPath, createdFiles) {
25
+ if ((await this.fileSystem.stat(targetPath)).isDirectory()) await this.trackCreatedFilesRecursive(targetPath, createdFiles);
26
+ else createdFiles.push(targetPath);
27
+ }
28
+ /**
29
+ * Track all existing files, handling both single files and directories
30
+ */
31
+ async trackExistingFiles(targetPath, existingFiles) {
32
+ if ((await this.fileSystem.stat(targetPath)).isDirectory()) await this.trackExistingFilesRecursive(targetPath, existingFiles);
33
+ else existingFiles.push(targetPath);
34
+ }
35
+ /**
36
+ * Copy source to target, then process templates and track files
37
+ * Now supports tracking existing files separately from created files
38
+ * Automatically handles .liquid template files by stripping the extension
39
+ */
40
+ async copyAndProcess(sourcePath, targetPath, variables, createdFiles, existingFiles) {
41
+ await this.fileSystem.ensureDir(path.dirname(targetPath));
42
+ if (await this.fileSystem.pathExists(targetPath) && existingFiles) {
43
+ await this.trackExistingFiles(targetPath, existingFiles);
44
+ return;
45
+ }
46
+ let actualSourcePath = sourcePath;
47
+ if (!await this.fileSystem.pathExists(sourcePath)) {
48
+ const liquidSourcePath = `${sourcePath}.liquid`;
49
+ if (await this.fileSystem.pathExists(liquidSourcePath)) actualSourcePath = liquidSourcePath;
50
+ else throw new Error(`Source file not found: ${sourcePath} (also tried ${liquidSourcePath})`);
51
+ }
52
+ await this.fileSystem.copy(actualSourcePath, targetPath);
53
+ await this.processTargetForVariableReplacement(targetPath, variables);
54
+ await this.trackCreatedFiles(targetPath, createdFiles);
55
+ }
56
+ /**
57
+ * Recursively collect all file paths in a directory for created files
58
+ */
59
+ async trackCreatedFilesRecursive(dirPath, createdFiles) {
60
+ let items = [];
61
+ try {
62
+ items = await this.fileSystem.readdir(dirPath);
63
+ } catch (error) {
64
+ log.warn(`Cannot read directory ${dirPath}: ${error}`);
65
+ return;
66
+ }
67
+ for (const item of items) {
68
+ if (!item) continue;
69
+ const itemPath = path.join(dirPath, item);
70
+ try {
71
+ const stat$1 = await this.fileSystem.stat(itemPath);
72
+ if (stat$1.isDirectory()) await this.trackCreatedFilesRecursive(itemPath, createdFiles);
73
+ else if (stat$1.isFile()) createdFiles.push(itemPath);
74
+ } catch (error) {
75
+ log.warn(`Cannot stat ${itemPath}: ${error}`);
76
+ }
77
+ }
78
+ }
79
+ /**
80
+ * Recursively collect all file paths in a directory for existing files
81
+ */
82
+ async trackExistingFilesRecursive(dirPath, existingFiles) {
83
+ let items = [];
84
+ try {
85
+ items = await this.fileSystem.readdir(dirPath);
86
+ } catch (error) {
87
+ log.warn(`Cannot read directory ${dirPath}: ${error}`);
88
+ return;
89
+ }
90
+ for (const item of items) {
91
+ if (!item) continue;
92
+ const itemPath = path.join(dirPath, item);
93
+ try {
94
+ const stat$1 = await this.fileSystem.stat(itemPath);
95
+ if (stat$1.isDirectory()) await this.trackExistingFilesRecursive(itemPath, existingFiles);
96
+ else if (stat$1.isFile()) existingFiles.push(itemPath);
97
+ } catch (error) {
98
+ log.warn(`Cannot stat ${itemPath}: ${error}`);
99
+ }
100
+ }
101
+ }
102
+ };
103
+
104
+ //#endregion
105
+ //#region src/services/ScaffoldService.ts
106
+ var ScaffoldService = class {
107
+ templatesRootPath;
108
+ processingService;
109
+ constructor(fileSystem, scaffoldConfigLoader, variableReplacer, templatesRootPath) {
110
+ this.fileSystem = fileSystem;
111
+ this.scaffoldConfigLoader = scaffoldConfigLoader;
112
+ this.variableReplacer = variableReplacer;
113
+ const resolvedPath = templatesRootPath || TemplatesManagerService.findTemplatesPathSync();
114
+ if (!resolvedPath) throw new Error("Templates folder not found. Please create a \"templates\" folder in your workspace root, or specify \"templatesPath\" in toolkit.yaml to point to your templates directory.");
115
+ this.templatesRootPath = resolvedPath;
116
+ this.processingService = new ScaffoldProcessingService(fileSystem, variableReplacer);
117
+ }
118
+ /**
119
+ * Scaffold a new project from a boilerplate template
120
+ */
121
+ async useBoilerplate(options) {
122
+ try {
123
+ const { projectName, packageName, targetFolder, templateFolder, boilerplateName, variables = {} } = options;
124
+ const targetPath = path.isAbsolute(targetFolder) ? projectName ? path.join(targetFolder, projectName) : targetFolder : projectName ? path.join(process.cwd(), targetFolder, projectName) : path.join(process.cwd(), targetFolder);
125
+ const templatePath = path.join(this.templatesRootPath, templateFolder);
126
+ const validationResult = await this.scaffoldConfigLoader.validateTemplate(templatePath, "boilerplate");
127
+ if (!validationResult.isValid) return {
128
+ success: false,
129
+ message: `Template validation failed: ${[...validationResult.errors, ...validationResult.missingFiles.map((f) => `Template file not found: ${f}`)].join("; ")}`
130
+ };
131
+ if (projectName) {
132
+ if (await this.fileSystem.pathExists(targetPath)) return {
133
+ success: false,
134
+ message: `Directory ${targetPath} already exists`
135
+ };
136
+ }
137
+ const architectConfig = await this.scaffoldConfigLoader.parseArchitectConfig(templatePath);
138
+ if (!architectConfig || !architectConfig.boilerplate) return {
139
+ success: false,
140
+ message: `Invalid architect configuration: missing 'boilerplate' section in scaffold.yaml`
141
+ };
142
+ const boilerplateArray = architectConfig.boilerplate;
143
+ let config;
144
+ if (Array.isArray(boilerplateArray)) {
145
+ config = boilerplateArray.find((b) => b.name === boilerplateName);
146
+ if (!config) return {
147
+ success: false,
148
+ message: `Boilerplate '${boilerplateName}' not found in scaffold configuration`
149
+ };
150
+ } else config = architectConfig.boilerplate;
151
+ const effectiveProjectName = projectName || (packageName.includes("/") ? packageName.split("/")[1] : packageName);
152
+ const allVariables = {
153
+ ...variables,
154
+ projectName: effectiveProjectName,
155
+ packageName
156
+ };
157
+ return await this.processScaffold({
158
+ config,
159
+ targetPath,
160
+ templatePath,
161
+ allVariables,
162
+ scaffoldType: "boilerplate"
163
+ });
164
+ } catch (error) {
165
+ return {
166
+ success: false,
167
+ message: `Error scaffolding boilerplate: ${error instanceof Error ? error.message : String(error)}`
168
+ };
169
+ }
170
+ }
171
+ /**
172
+ * Scaffold a new feature into an existing project
173
+ */
174
+ async useFeature(options) {
175
+ try {
176
+ const { projectPath, templateFolder, featureName, variables = {} } = options;
177
+ const targetPath = path.resolve(projectPath);
178
+ const templatePath = path.join(this.templatesRootPath, templateFolder);
179
+ const projectName = path.basename(targetPath);
180
+ const validationResult = await this.scaffoldConfigLoader.validateTemplate(templatePath, "features");
181
+ if (!validationResult.isValid) return {
182
+ success: false,
183
+ message: `Template validation failed: ${[...validationResult.errors, ...validationResult.missingFiles.map((f) => `Template file not found: ${f}`)].join("; ")}`
184
+ };
185
+ if (!await this.fileSystem.pathExists(targetPath)) return {
186
+ success: false,
187
+ message: `Target directory ${targetPath} does not exist. Please create the parent directory first.`
188
+ };
189
+ const architectConfig = await this.scaffoldConfigLoader.parseArchitectConfig(templatePath);
190
+ if (!architectConfig || !architectConfig.features) return {
191
+ success: false,
192
+ message: `Invalid architect configuration: missing 'features' section in scaffold.yaml`
193
+ };
194
+ const featureArray = architectConfig.features;
195
+ let config;
196
+ if (Array.isArray(featureArray)) {
197
+ config = featureArray.find((f) => f.name === featureName);
198
+ if (!config) return {
199
+ success: false,
200
+ message: `Feature '${featureName}' not found in scaffold configuration`
201
+ };
202
+ } else config = architectConfig.features;
203
+ const allVariables = {
204
+ ...variables,
205
+ projectName,
206
+ appPath: targetPath,
207
+ appName: projectName
208
+ };
209
+ return await this.processScaffold({
210
+ config,
211
+ targetPath,
212
+ templatePath,
213
+ allVariables,
214
+ scaffoldType: "feature"
215
+ });
216
+ } catch (error) {
217
+ return {
218
+ success: false,
219
+ message: `Error scaffolding feature: ${error instanceof Error ? error.message : String(error)}`
220
+ };
221
+ }
222
+ }
223
+ /**
224
+ * Common scaffolding processing logic shared by both useBoilerplate and useFeature
225
+ */
226
+ async processScaffold(params) {
227
+ const { config, targetPath, templatePath, allVariables, scaffoldType } = params;
228
+ log.debug("Config generator:", config.generator);
229
+ log.debug("Config:", JSON.stringify(config, null, 2));
230
+ if (config.generator) {
231
+ log.info("Using custom generator:", config.generator);
232
+ try {
233
+ const generator = (await import(path.join(templatePath, "generators", config.generator))).default;
234
+ if (typeof generator !== "function") return {
235
+ success: false,
236
+ message: `Invalid generator: ${config.generator} does not export a default function`
237
+ };
238
+ return await generator({
239
+ variables: allVariables,
240
+ config,
241
+ targetPath,
242
+ templatePath,
243
+ fileSystem: this.fileSystem,
244
+ scaffoldConfigLoader: this.scaffoldConfigLoader,
245
+ variableReplacer: this.variableReplacer,
246
+ ScaffoldProcessingService: this.processingService.constructor,
247
+ getRootPath: () => {
248
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
249
+ return path.join(__dirname, "../../../../..");
250
+ },
251
+ getProjectPath: (projectPath) => {
252
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
253
+ const rootPath = path.join(__dirname, "../../../../..");
254
+ return projectPath.replace(rootPath, "").replace("/", "");
255
+ }
256
+ });
257
+ } catch (error) {
258
+ return {
259
+ success: false,
260
+ message: `Error loading or executing generator ${config.generator}: ${error instanceof Error ? error.message : String(error)}`
261
+ };
262
+ }
263
+ }
264
+ const parsedIncludes = [];
265
+ const warnings = [];
266
+ if (config.includes && Array.isArray(config.includes)) for (const includeEntry of config.includes) {
267
+ const parsed = this.scaffoldConfigLoader.parseIncludeEntry(includeEntry, allVariables);
268
+ if (!this.scaffoldConfigLoader.shouldIncludeFile(parsed.conditions, allVariables)) continue;
269
+ parsedIncludes.push(parsed);
270
+ const targetFilePath = path.join(targetPath, parsed.targetPath);
271
+ if (await this.fileSystem.pathExists(targetFilePath)) warnings.push(`File/folder ${parsed.targetPath} already exists and will be preserved`);
272
+ }
273
+ await this.fileSystem.ensureDir(targetPath);
274
+ const createdFiles = [];
275
+ const existingFiles = [];
276
+ for (const parsed of parsedIncludes) {
277
+ const sourcePath = path.join(templatePath, parsed.sourcePath);
278
+ const targetFilePath = path.join(targetPath, parsed.targetPath);
279
+ await this.processingService.copyAndProcess(sourcePath, targetFilePath, allVariables, createdFiles, existingFiles);
280
+ }
281
+ let message = `Successfully scaffolded ${scaffoldType} at ${targetPath}`;
282
+ if (existingFiles.length > 0) message += `. ${existingFiles.length} existing file(s) were preserved`;
283
+ message += ". Run 'pnpm install' to install dependencies.";
284
+ return {
285
+ success: true,
286
+ message,
287
+ warnings: warnings.length > 0 ? warnings : void 0,
288
+ createdFiles: createdFiles.length > 0 ? createdFiles : void 0,
289
+ existingFiles: existingFiles.length > 0 ? existingFiles : void 0
290
+ };
291
+ }
292
+ };
293
+
294
+ //#endregion
295
+ export { ScaffoldProcessingService as n, ScaffoldService as t };
@@ -0,0 +1,3 @@
1
+ const require_ScaffoldService = require('./ScaffoldService-DSQBnAHm.cjs');
2
+
3
+ exports.ScaffoldService = require_ScaffoldService.ScaffoldService;
@@ -0,0 +1,3 @@
1
+ import { t as ScaffoldService } from "./ScaffoldService-DcsGLMuD.mjs";
2
+
3
+ export { ScaffoldService };