@agiflowai/aicode-utils 0.4.0 â 0.5.0
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/index.cjs +474 -108
- package/dist/index.d.cts +268 -18
- package/dist/index.d.ts +268 -18
- package/dist/index.js +463 -108
- package/package.json +4 -2
package/dist/index.js
CHANGED
|
@@ -1,10 +1,365 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
+
import * as path$1 from "node:path";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import * as fs from "fs-extra";
|
|
5
|
+
import * as os from "node:os";
|
|
6
|
+
import pino from "pino";
|
|
7
|
+
import chalk from "chalk";
|
|
4
8
|
|
|
5
9
|
//#region rolldown:runtime
|
|
6
10
|
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
7
11
|
|
|
12
|
+
//#endregion
|
|
13
|
+
//#region src/constants/projectType.ts
|
|
14
|
+
/**
|
|
15
|
+
* Project type constants
|
|
16
|
+
*/
|
|
17
|
+
const ProjectType = {
|
|
18
|
+
MONOLITH: "monolith",
|
|
19
|
+
MONOREPO: "monorepo"
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Config source constants
|
|
23
|
+
*/
|
|
24
|
+
const ConfigSource = {
|
|
25
|
+
PROJECT_JSON: "project.json",
|
|
26
|
+
TOOLKIT_YAML: "toolkit.yaml"
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region src/utils/logger.ts
|
|
31
|
+
const logsDir = path$1.join(os.tmpdir(), "scaffold-mcp-logs");
|
|
32
|
+
const logger = pino({
|
|
33
|
+
level: process.env.LOG_LEVEL || "debug",
|
|
34
|
+
timestamp: pino.stdTimeFunctions.isoTime
|
|
35
|
+
}, pino.destination({
|
|
36
|
+
dest: path$1.join(logsDir, "scaffold-mcp.log"),
|
|
37
|
+
mkdir: true,
|
|
38
|
+
sync: true
|
|
39
|
+
}));
|
|
40
|
+
const log = {
|
|
41
|
+
debug: (msg, ...args) => logger.debug({ args }, msg),
|
|
42
|
+
info: (msg, ...args) => logger.info({ args }, msg),
|
|
43
|
+
warn: (msg, ...args) => logger.warn({ args }, msg),
|
|
44
|
+
error: (msg, ...args) => logger.error({ args }, msg)
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
//#endregion
|
|
48
|
+
//#region src/services/TemplatesManagerService.ts
|
|
49
|
+
var TemplatesManagerService = class TemplatesManagerService {
|
|
50
|
+
static SCAFFOLD_CONFIG_FILE = "scaffold.yaml";
|
|
51
|
+
static TEMPLATES_FOLDER = "templates";
|
|
52
|
+
static TOOLKIT_CONFIG_FILE = "toolkit.yaml";
|
|
53
|
+
/**
|
|
54
|
+
* Find the templates directory by searching upwards from the starting path.
|
|
55
|
+
*
|
|
56
|
+
* Algorithm:
|
|
57
|
+
* 1. Start from the provided path (default: current working directory)
|
|
58
|
+
* 2. Search upwards to find the workspace root (where .git exists or filesystem root)
|
|
59
|
+
* 3. Check if toolkit.yaml exists at workspace root
|
|
60
|
+
* - If yes, read templatesPath from toolkit.yaml
|
|
61
|
+
* - If no, default to 'templates' folder in workspace root
|
|
62
|
+
* 4. Verify the templates directory exists
|
|
63
|
+
*
|
|
64
|
+
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
65
|
+
* @returns The absolute path to the templates directory
|
|
66
|
+
* @throws Error if templates directory is not found
|
|
67
|
+
*/
|
|
68
|
+
static async findTemplatesPath(startPath = process.cwd()) {
|
|
69
|
+
const workspaceRoot = await TemplatesManagerService.findWorkspaceRoot(startPath);
|
|
70
|
+
const toolkitConfigPath = path.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
71
|
+
if (await fs.pathExists(toolkitConfigPath)) {
|
|
72
|
+
const yaml = await import("js-yaml");
|
|
73
|
+
const content = await fs.readFile(toolkitConfigPath, "utf-8");
|
|
74
|
+
const config = yaml.load(content);
|
|
75
|
+
if (config?.templatesPath) {
|
|
76
|
+
const templatesPath$1 = path.isAbsolute(config.templatesPath) ? config.templatesPath : path.join(workspaceRoot, config.templatesPath);
|
|
77
|
+
if (await fs.pathExists(templatesPath$1)) return templatesPath$1;
|
|
78
|
+
else throw new Error(`Templates path specified in toolkit.yaml does not exist: ${templatesPath$1}`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const templatesPath = path.join(workspaceRoot, TemplatesManagerService.TEMPLATES_FOLDER);
|
|
82
|
+
if (await fs.pathExists(templatesPath)) return templatesPath;
|
|
83
|
+
throw new Error(`Templates folder not found at ${templatesPath}.\nEither create a 'templates' folder or specify templatesPath in toolkit.yaml`);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Find the workspace root by searching upwards for .git folder
|
|
87
|
+
*/
|
|
88
|
+
static async findWorkspaceRoot(startPath) {
|
|
89
|
+
let currentPath = path.resolve(startPath);
|
|
90
|
+
const rootPath = path.parse(currentPath).root;
|
|
91
|
+
while (true) {
|
|
92
|
+
const gitPath = path.join(currentPath, ".git");
|
|
93
|
+
if (await fs.pathExists(gitPath)) return currentPath;
|
|
94
|
+
if (currentPath === rootPath) return process.cwd();
|
|
95
|
+
currentPath = path.dirname(currentPath);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Get the templates path synchronously.
|
|
100
|
+
* Use this when you need immediate access and are sure templates exist.
|
|
101
|
+
*
|
|
102
|
+
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
103
|
+
* @returns The absolute path to the templates directory
|
|
104
|
+
* @throws Error if templates directory is not found
|
|
105
|
+
*/
|
|
106
|
+
static findTemplatesPathSync(startPath = process.cwd()) {
|
|
107
|
+
const workspaceRoot = TemplatesManagerService.findWorkspaceRootSync(startPath);
|
|
108
|
+
const toolkitConfigPath = path.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
109
|
+
if (fs.pathExistsSync(toolkitConfigPath)) {
|
|
110
|
+
const yaml = __require("js-yaml");
|
|
111
|
+
const content = fs.readFileSync(toolkitConfigPath, "utf-8");
|
|
112
|
+
const config = yaml.load(content);
|
|
113
|
+
if (config?.templatesPath) {
|
|
114
|
+
const templatesPath$1 = path.isAbsolute(config.templatesPath) ? config.templatesPath : path.join(workspaceRoot, config.templatesPath);
|
|
115
|
+
if (fs.pathExistsSync(templatesPath$1)) return templatesPath$1;
|
|
116
|
+
else throw new Error(`Templates path specified in toolkit.yaml does not exist: ${templatesPath$1}`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
const templatesPath = path.join(workspaceRoot, TemplatesManagerService.TEMPLATES_FOLDER);
|
|
120
|
+
if (fs.pathExistsSync(templatesPath)) return templatesPath;
|
|
121
|
+
throw new Error(`Templates folder not found at ${templatesPath}.\nEither create a 'templates' folder or specify templatesPath in toolkit.yaml`);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Find the workspace root synchronously by searching upwards for .git folder
|
|
125
|
+
*/
|
|
126
|
+
static findWorkspaceRootSync(startPath) {
|
|
127
|
+
let currentPath = path.resolve(startPath);
|
|
128
|
+
const rootPath = path.parse(currentPath).root;
|
|
129
|
+
while (true) {
|
|
130
|
+
const gitPath = path.join(currentPath, ".git");
|
|
131
|
+
if (fs.pathExistsSync(gitPath)) return currentPath;
|
|
132
|
+
if (currentPath === rootPath) return process.cwd();
|
|
133
|
+
currentPath = path.dirname(currentPath);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Check if templates are initialized at the given path
|
|
138
|
+
*
|
|
139
|
+
* @param templatesPath - Path to check for templates
|
|
140
|
+
* @returns true if templates folder exists and is a directory
|
|
141
|
+
*/
|
|
142
|
+
static async isInitialized(templatesPath) {
|
|
143
|
+
if (!await fs.pathExists(templatesPath)) return false;
|
|
144
|
+
return (await fs.stat(templatesPath)).isDirectory();
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get the scaffold config file name
|
|
148
|
+
*/
|
|
149
|
+
static getConfigFileName() {
|
|
150
|
+
return TemplatesManagerService.SCAFFOLD_CONFIG_FILE;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Get the templates folder name
|
|
154
|
+
*/
|
|
155
|
+
static getTemplatesFolderName() {
|
|
156
|
+
return TemplatesManagerService.TEMPLATES_FOLDER;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Read toolkit.yaml configuration from workspace root
|
|
160
|
+
*
|
|
161
|
+
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
162
|
+
* @returns The toolkit configuration object or null if not found
|
|
163
|
+
*/
|
|
164
|
+
static async readToolkitConfig(startPath = process.cwd()) {
|
|
165
|
+
const workspaceRoot = await TemplatesManagerService.findWorkspaceRoot(startPath);
|
|
166
|
+
const toolkitConfigPath = path.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
167
|
+
if (!await fs.pathExists(toolkitConfigPath)) return null;
|
|
168
|
+
const yaml = await import("js-yaml");
|
|
169
|
+
const content = await fs.readFile(toolkitConfigPath, "utf-8");
|
|
170
|
+
return yaml.load(content);
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Read toolkit.yaml configuration from workspace root (sync)
|
|
174
|
+
*
|
|
175
|
+
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
176
|
+
* @returns The toolkit configuration object or null if not found
|
|
177
|
+
*/
|
|
178
|
+
static readToolkitConfigSync(startPath = process.cwd()) {
|
|
179
|
+
const workspaceRoot = TemplatesManagerService.findWorkspaceRootSync(startPath);
|
|
180
|
+
const toolkitConfigPath = path.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
181
|
+
if (!fs.pathExistsSync(toolkitConfigPath)) return null;
|
|
182
|
+
const yaml = __require("js-yaml");
|
|
183
|
+
const content = fs.readFileSync(toolkitConfigPath, "utf-8");
|
|
184
|
+
return yaml.load(content);
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Write toolkit.yaml configuration to workspace root
|
|
188
|
+
*
|
|
189
|
+
* @param config - The toolkit configuration to write
|
|
190
|
+
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
191
|
+
*/
|
|
192
|
+
static async writeToolkitConfig(config, startPath = process.cwd()) {
|
|
193
|
+
const workspaceRoot = await TemplatesManagerService.findWorkspaceRoot(startPath);
|
|
194
|
+
const toolkitConfigPath = path.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
195
|
+
const content = (await import("js-yaml")).dump(config, { indent: 2 });
|
|
196
|
+
await fs.writeFile(toolkitConfigPath, content, "utf-8");
|
|
197
|
+
}
|
|
198
|
+
/**
|
|
199
|
+
* Get the workspace root directory
|
|
200
|
+
*
|
|
201
|
+
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
202
|
+
* @returns The workspace root directory path
|
|
203
|
+
*/
|
|
204
|
+
static async getWorkspaceRoot(startPath = process.cwd()) {
|
|
205
|
+
return TemplatesManagerService.findWorkspaceRoot(startPath);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Get the workspace root directory (sync)
|
|
209
|
+
*
|
|
210
|
+
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
211
|
+
* @returns The workspace root directory path
|
|
212
|
+
*/
|
|
213
|
+
static getWorkspaceRootSync(startPath = process.cwd()) {
|
|
214
|
+
return TemplatesManagerService.findWorkspaceRootSync(startPath);
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
//#endregion
|
|
219
|
+
//#region src/services/ProjectConfigResolver.ts
|
|
220
|
+
/**
|
|
221
|
+
* ProjectConfigResolver
|
|
222
|
+
*
|
|
223
|
+
* Resolves project configuration from multiple sources with priority:
|
|
224
|
+
* 1. project.json (monorepo - Nx/Lerna/Turborepo)
|
|
225
|
+
* 2. toolkit.yaml at workspace root (monolith)
|
|
226
|
+
*/
|
|
227
|
+
var ProjectConfigResolver = class ProjectConfigResolver {
|
|
228
|
+
/**
|
|
229
|
+
* Resolve project configuration with priority fallback
|
|
230
|
+
*
|
|
231
|
+
* Priority order:
|
|
232
|
+
* 1. Check for project.json (monorepo case)
|
|
233
|
+
* 2. Check for toolkit.yaml at workspace root (monolith case)
|
|
234
|
+
* 3. Error with helpful message
|
|
235
|
+
*
|
|
236
|
+
* @param projectPath - Absolute path to the project directory
|
|
237
|
+
* @param explicitTemplate - Optional explicit template override
|
|
238
|
+
* @returns Project configuration result
|
|
239
|
+
* @throws Error if no configuration found
|
|
240
|
+
*/
|
|
241
|
+
static async resolveProjectConfig(projectPath, explicitTemplate) {
|
|
242
|
+
try {
|
|
243
|
+
const absolutePath = path.resolve(projectPath);
|
|
244
|
+
if (explicitTemplate) return {
|
|
245
|
+
type: ProjectType.MONOLITH,
|
|
246
|
+
sourceTemplate: explicitTemplate,
|
|
247
|
+
configSource: ConfigSource.TOOLKIT_YAML
|
|
248
|
+
};
|
|
249
|
+
const projectJsonPath = path.join(absolutePath, "project.json");
|
|
250
|
+
if (await fs.pathExists(projectJsonPath)) {
|
|
251
|
+
const projectJson = await fs.readJson(projectJsonPath);
|
|
252
|
+
if (projectJson.sourceTemplate && typeof projectJson.sourceTemplate === "string" && projectJson.sourceTemplate.trim()) return {
|
|
253
|
+
type: ProjectType.MONOREPO,
|
|
254
|
+
sourceTemplate: projectJson.sourceTemplate.trim(),
|
|
255
|
+
configSource: ConfigSource.PROJECT_JSON
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
try {
|
|
259
|
+
const workspaceRoot = await TemplatesManagerService.getWorkspaceRoot(absolutePath);
|
|
260
|
+
const toolkitConfig = await TemplatesManagerService.readToolkitConfig(workspaceRoot);
|
|
261
|
+
if (toolkitConfig?.projectType === "monolith" && toolkitConfig.sourceTemplate) return {
|
|
262
|
+
type: ProjectType.MONOLITH,
|
|
263
|
+
sourceTemplate: toolkitConfig.sourceTemplate,
|
|
264
|
+
configSource: ConfigSource.TOOLKIT_YAML,
|
|
265
|
+
workspaceRoot
|
|
266
|
+
};
|
|
267
|
+
} catch (error) {}
|
|
268
|
+
throw new Error(ProjectConfigResolver.getHelpfulErrorMessage(absolutePath));
|
|
269
|
+
} catch (error) {
|
|
270
|
+
if (error instanceof Error && error.message.includes("No project configuration found")) throw error;
|
|
271
|
+
throw new Error(`Failed to resolve project configuration at ${projectPath}: ${error instanceof Error ? error.message : String(error)}`);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
/**
|
|
275
|
+
* Get helpful error message when no configuration is found
|
|
276
|
+
*/
|
|
277
|
+
static getHelpfulErrorMessage(projectPath) {
|
|
278
|
+
return `No project configuration found at ${projectPath}.
|
|
279
|
+
|
|
280
|
+
For monorepo projects:
|
|
281
|
+
- Ensure project.json exists with sourceTemplate field
|
|
282
|
+
|
|
283
|
+
For monolith projects:
|
|
284
|
+
- Create toolkit.yaml at workspace root:
|
|
285
|
+
|
|
286
|
+
projectType: monolith
|
|
287
|
+
sourceTemplate: your-template-name
|
|
288
|
+
|
|
289
|
+
- OR use --template flag:
|
|
290
|
+
scaffold-mcp scaffold add <feature> --template <template-name>
|
|
291
|
+
|
|
292
|
+
Run 'scaffold-mcp scaffold list --help' for more info.`;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Check if project has configuration (without throwing error)
|
|
296
|
+
*
|
|
297
|
+
* @param projectPath - Absolute path to the project directory
|
|
298
|
+
* @returns true if configuration exists, false otherwise
|
|
299
|
+
* @throws Error if there's a filesystem error (not just missing config)
|
|
300
|
+
*/
|
|
301
|
+
static async hasConfiguration(projectPath) {
|
|
302
|
+
try {
|
|
303
|
+
await ProjectConfigResolver.resolveProjectConfig(projectPath);
|
|
304
|
+
return true;
|
|
305
|
+
} catch (error) {
|
|
306
|
+
if (error instanceof Error && error.message.includes("No project configuration found")) return false;
|
|
307
|
+
throw new Error(`Error checking project configuration: ${error instanceof Error ? error.message : String(error)}`);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Create toolkit.yaml for monolith projects
|
|
312
|
+
*
|
|
313
|
+
* @param sourceTemplate - The template identifier
|
|
314
|
+
* @param workspaceRoot - Optional workspace root path (defaults to current directory)
|
|
315
|
+
*/
|
|
316
|
+
static async createToolkitYaml(sourceTemplate, workspaceRoot) {
|
|
317
|
+
try {
|
|
318
|
+
const rootPath = workspaceRoot || await TemplatesManagerService.getWorkspaceRoot(process.cwd());
|
|
319
|
+
const existingConfig = await TemplatesManagerService.readToolkitConfig(rootPath);
|
|
320
|
+
const toolkitConfig = {
|
|
321
|
+
version: existingConfig?.version || "1.0",
|
|
322
|
+
templatesPath: existingConfig?.templatesPath || "./templates",
|
|
323
|
+
projectType: "monolith",
|
|
324
|
+
sourceTemplate
|
|
325
|
+
};
|
|
326
|
+
await TemplatesManagerService.writeToolkitConfig(toolkitConfig, rootPath);
|
|
327
|
+
log.info("Created toolkit.yaml with monolith configuration");
|
|
328
|
+
} catch (error) {
|
|
329
|
+
throw new Error(`Failed to create toolkit.yaml: ${error instanceof Error ? error.message : String(error)}`);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Create or update project.json for monorepo projects
|
|
334
|
+
*
|
|
335
|
+
* @param projectPath - Absolute path to the project directory
|
|
336
|
+
* @param projectName - Name of the project
|
|
337
|
+
* @param sourceTemplate - The template identifier
|
|
338
|
+
*/
|
|
339
|
+
static async createProjectJson(projectPath, projectName, sourceTemplate) {
|
|
340
|
+
const projectJsonPath = path.join(projectPath, "project.json");
|
|
341
|
+
try {
|
|
342
|
+
let projectJson;
|
|
343
|
+
if (await fs.pathExists(projectJsonPath)) projectJson = await fs.readJson(projectJsonPath);
|
|
344
|
+
else {
|
|
345
|
+
const relativePath = path.relative(projectPath, process.cwd());
|
|
346
|
+
projectJson = {
|
|
347
|
+
name: projectName,
|
|
348
|
+
$schema: relativePath ? `${relativePath}/node_modules/nx/schemas/project-schema.json` : "node_modules/nx/schemas/project-schema.json",
|
|
349
|
+
sourceRoot: projectPath,
|
|
350
|
+
projectType: "application"
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
projectJson.sourceTemplate = sourceTemplate;
|
|
354
|
+
const content = JSON.stringify(projectJson, null, 2);
|
|
355
|
+
await fs.writeFile(projectJsonPath, `${content}\n`);
|
|
356
|
+
log.info(`Created/updated project.json with sourceTemplate: ${sourceTemplate}`);
|
|
357
|
+
} catch (error) {
|
|
358
|
+
throw new Error(`Failed to create project.json: ${error instanceof Error ? error.message : String(error)}`);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
|
|
8
363
|
//#endregion
|
|
9
364
|
//#region src/services/ProjectFinderService.ts
|
|
10
365
|
var ProjectFinderService = class {
|
|
@@ -199,117 +554,117 @@ var ScaffoldProcessingService = class {
|
|
|
199
554
|
};
|
|
200
555
|
|
|
201
556
|
//#endregion
|
|
202
|
-
//#region src/
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
/**
|
|
240
|
-
* Find the workspace root by searching upwards for .git folder
|
|
241
|
-
*/
|
|
242
|
-
static async findWorkspaceRoot(startPath) {
|
|
243
|
-
let currentPath = path.resolve(startPath);
|
|
244
|
-
const rootPath = path.parse(currentPath).root;
|
|
245
|
-
while (true) {
|
|
246
|
-
const gitPath = path.join(currentPath, ".git");
|
|
247
|
-
if (await fs.pathExists(gitPath)) return currentPath;
|
|
248
|
-
if (currentPath === rootPath) return process.cwd();
|
|
249
|
-
currentPath = path.dirname(currentPath);
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
/**
|
|
253
|
-
* Get the templates path synchronously.
|
|
254
|
-
* Use this when you need immediate access and are sure templates exist.
|
|
255
|
-
*
|
|
256
|
-
* @param startPath - The path to start searching from (defaults to process.cwd())
|
|
257
|
-
* @returns The absolute path to the templates directory
|
|
258
|
-
* @throws Error if templates directory is not found
|
|
259
|
-
*/
|
|
260
|
-
static findTemplatesPathSync(startPath = process.cwd()) {
|
|
261
|
-
const workspaceRoot = TemplatesManagerService.findWorkspaceRootSync(startPath);
|
|
262
|
-
const toolkitConfigPath = path.join(workspaceRoot, TemplatesManagerService.TOOLKIT_CONFIG_FILE);
|
|
263
|
-
if (fs.pathExistsSync(toolkitConfigPath)) {
|
|
264
|
-
const yaml = __require("js-yaml");
|
|
265
|
-
const content = fs.readFileSync(toolkitConfigPath, "utf-8");
|
|
266
|
-
const config = yaml.load(content);
|
|
267
|
-
if (config?.templatesPath) {
|
|
268
|
-
const templatesPath$1 = path.isAbsolute(config.templatesPath) ? config.templatesPath : path.join(workspaceRoot, config.templatesPath);
|
|
269
|
-
if (fs.pathExistsSync(templatesPath$1)) return templatesPath$1;
|
|
270
|
-
else throw new Error(`Templates path specified in toolkit.yaml does not exist: ${templatesPath$1}`);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
const templatesPath = path.join(workspaceRoot, TemplatesManagerService.TEMPLATES_FOLDER);
|
|
274
|
-
if (fs.pathExistsSync(templatesPath)) return templatesPath;
|
|
275
|
-
throw new Error(`Templates folder not found at ${templatesPath}.\nEither create a 'templates' folder or specify templatesPath in toolkit.yaml`);
|
|
276
|
-
}
|
|
277
|
-
/**
|
|
278
|
-
* Find the workspace root synchronously by searching upwards for .git folder
|
|
279
|
-
*/
|
|
280
|
-
static findWorkspaceRootSync(startPath) {
|
|
281
|
-
let currentPath = path.resolve(startPath);
|
|
282
|
-
const rootPath = path.parse(currentPath).root;
|
|
283
|
-
while (true) {
|
|
284
|
-
const gitPath = path.join(currentPath, ".git");
|
|
285
|
-
if (fs.pathExistsSync(gitPath)) return currentPath;
|
|
286
|
-
if (currentPath === rootPath) return process.cwd();
|
|
287
|
-
currentPath = path.dirname(currentPath);
|
|
288
|
-
}
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* Check if templates are initialized at the given path
|
|
292
|
-
*
|
|
293
|
-
* @param templatesPath - Path to check for templates
|
|
294
|
-
* @returns true if templates folder exists and is a directory
|
|
295
|
-
*/
|
|
296
|
-
static async isInitialized(templatesPath) {
|
|
297
|
-
if (!await fs.pathExists(templatesPath)) return false;
|
|
298
|
-
return (await fs.stat(templatesPath)).isDirectory();
|
|
557
|
+
//#region src/utils/print.ts
|
|
558
|
+
/**
|
|
559
|
+
* Themed console utilities for consistent CLI output
|
|
560
|
+
*/
|
|
561
|
+
const print = {
|
|
562
|
+
info: (message) => {
|
|
563
|
+
console.log(chalk.cyan(message));
|
|
564
|
+
},
|
|
565
|
+
success: (message) => {
|
|
566
|
+
console.log(chalk.green(message));
|
|
567
|
+
},
|
|
568
|
+
warning: (message) => {
|
|
569
|
+
console.log(chalk.yellow(message));
|
|
570
|
+
},
|
|
571
|
+
error: (message, error) => {
|
|
572
|
+
if (error) {
|
|
573
|
+
const errorMsg = error instanceof Error ? error.message : error;
|
|
574
|
+
console.error(chalk.red(message), errorMsg);
|
|
575
|
+
} else console.error(chalk.red(message));
|
|
576
|
+
},
|
|
577
|
+
debug: (message) => {
|
|
578
|
+
console.log(chalk.gray(message));
|
|
579
|
+
},
|
|
580
|
+
header: (message) => {
|
|
581
|
+
console.log(chalk.bold.cyan(message));
|
|
582
|
+
},
|
|
583
|
+
item: (message) => {
|
|
584
|
+
console.log(chalk.gray(` - ${message}`));
|
|
585
|
+
},
|
|
586
|
+
indent: (message) => {
|
|
587
|
+
console.log(chalk.gray(` ${message}`));
|
|
588
|
+
},
|
|
589
|
+
highlight: (message) => {
|
|
590
|
+
console.log(chalk.bold.green(message));
|
|
591
|
+
},
|
|
592
|
+
newline: () => {
|
|
593
|
+
console.log();
|
|
299
594
|
}
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
595
|
+
};
|
|
596
|
+
/**
|
|
597
|
+
* Emoji icons for consistent visual markers
|
|
598
|
+
*/
|
|
599
|
+
const icons = {
|
|
600
|
+
rocket: "đ",
|
|
601
|
+
check: "â
",
|
|
602
|
+
cross: "â",
|
|
603
|
+
warning: "â ī¸",
|
|
604
|
+
info: "âšī¸",
|
|
605
|
+
package: "đĻ",
|
|
606
|
+
folder: "đ",
|
|
607
|
+
file: "đ",
|
|
608
|
+
config: "đ",
|
|
609
|
+
wrench: "đ§",
|
|
610
|
+
chart: "đ",
|
|
611
|
+
bulb: "đĄ",
|
|
612
|
+
download: "âŦī¸",
|
|
613
|
+
upload: "âŦī¸",
|
|
614
|
+
gear: "âī¸",
|
|
615
|
+
clipboard: "đ",
|
|
616
|
+
skip: "â"
|
|
617
|
+
};
|
|
618
|
+
/**
|
|
619
|
+
* Themed message helpers
|
|
620
|
+
*/
|
|
621
|
+
const messages = {
|
|
622
|
+
info: (message) => {
|
|
623
|
+
print.info(`${icons.info} ${message}`);
|
|
624
|
+
},
|
|
625
|
+
success: (message) => {
|
|
626
|
+
print.success(`${icons.check} ${message}`);
|
|
627
|
+
},
|
|
628
|
+
error: (message, error) => {
|
|
629
|
+
print.error(`${icons.cross} ${message}`, error);
|
|
630
|
+
},
|
|
631
|
+
warning: (message) => {
|
|
632
|
+
print.warning(`${icons.warning} ${message}`);
|
|
633
|
+
},
|
|
634
|
+
hint: (message) => {
|
|
635
|
+
print.warning(`${icons.bulb} ${message}`);
|
|
636
|
+
},
|
|
637
|
+
loading: (message) => {
|
|
638
|
+
print.info(`${icons.rocket} ${message}`);
|
|
305
639
|
}
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
640
|
+
};
|
|
641
|
+
/**
|
|
642
|
+
* Section formatters
|
|
643
|
+
*/
|
|
644
|
+
const sections = {
|
|
645
|
+
header: (title) => {
|
|
646
|
+
print.newline();
|
|
647
|
+
print.header(`${title}`);
|
|
648
|
+
print.newline();
|
|
649
|
+
},
|
|
650
|
+
list: (title, items) => {
|
|
651
|
+
print.header(`\n${title}\n`);
|
|
652
|
+
items.forEach((item) => print.item(item));
|
|
653
|
+
},
|
|
654
|
+
nextSteps: (steps) => {
|
|
655
|
+
print.header(`\n${icons.clipboard} Next steps:`);
|
|
656
|
+
steps.forEach((step) => print.indent(step));
|
|
657
|
+
},
|
|
658
|
+
createdFiles: (files, maxShow = 10) => {
|
|
659
|
+
print.header(`\n${icons.folder} Created files:`);
|
|
660
|
+
files.slice(0, maxShow).forEach((file) => print.item(file));
|
|
661
|
+
if (files.length > maxShow) print.indent(`... and ${files.length - maxShow} more files`);
|
|
662
|
+
},
|
|
663
|
+
warnings: (warnings) => {
|
|
664
|
+
print.warning(`\n${icons.warning} Warnings:`);
|
|
665
|
+
warnings.forEach((warning) => print.item(warning));
|
|
311
666
|
}
|
|
312
667
|
};
|
|
313
668
|
|
|
314
669
|
//#endregion
|
|
315
|
-
export { ProjectFinderService, ScaffoldProcessingService, TemplatesManagerService };
|
|
670
|
+
export { ConfigSource, ProjectConfigResolver, ProjectFinderService, ProjectType, ScaffoldProcessingService, TemplatesManagerService, icons, log, logger, messages, print, sections };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agiflowai/aicode-utils",
|
|
3
3
|
"description": "Shared utilities and types for AI-powered code generation, scaffolding, and analysis",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.5.0",
|
|
5
5
|
"license": "AGPL-3.0",
|
|
6
6
|
"author": "AgiflowIO",
|
|
7
7
|
"repository": {
|
|
@@ -30,8 +30,10 @@
|
|
|
30
30
|
"README.md"
|
|
31
31
|
],
|
|
32
32
|
"dependencies": {
|
|
33
|
+
"chalk": "5.6.2",
|
|
33
34
|
"fs-extra": "11.3.2",
|
|
34
|
-
"js-yaml": "4.1.0"
|
|
35
|
+
"js-yaml": "4.1.0",
|
|
36
|
+
"pino": "^10.0.0"
|
|
35
37
|
},
|
|
36
38
|
"devDependencies": {
|
|
37
39
|
"@types/fs-extra": "^11.0.4",
|