@agiflowai/scaffold-mcp 1.0.27 → 1.2.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/README.md +19 -0
- package/dist/{ListScaffoldingMethodsTool-DBwZzJTA.cjs → ListScaffoldingMethodsTool-CYZtpU-W.cjs} +109 -126
- package/dist/{ListScaffoldingMethodsTool-D6BkKQyK.mjs → ListScaffoldingMethodsTool-DxdrPlcb.mjs} +32 -44
- package/dist/{claudeCode-Dozuzn4S.mjs → claudeCode-DbKOy8W8.mjs} +7 -10
- package/dist/{claudeCode-B6CWgRYJ.cjs → claudeCode-g1eRidPR.cjs} +54 -57
- package/dist/cli.cjs +329 -157
- package/dist/cli.mjs +202 -30
- package/dist/{geminiCli-COS3X1P7.cjs → geminiCli--s1Qy7ZP.cjs} +35 -37
- package/dist/{geminiCli-CzgQDDMl.mjs → geminiCli-CcrZEqsz.mjs} +3 -5
- package/dist/index.cjs +5 -5
- package/dist/index.d.cts +3 -12
- package/dist/index.d.mts +3 -14
- package/dist/index.mjs +4 -5
- package/dist/{shared-oDx2Btq0.mjs → shared-BVYIN3Is.mjs} +4 -10
- package/dist/{shared-fkWett9D.cjs → shared-QxPXh-L-.cjs} +17 -23
- package/dist/{src-DuOmlC4n.cjs → src-BG_X82dw.cjs} +59 -77
- package/dist/{src-CSfEg-8i.mjs → src-DnVktdhD.mjs} +12 -30
- package/dist/{tools-DsnQImJ1.cjs → tools-COb9iBtt.cjs} +132 -130
- package/dist/{tools-t-HMGLVh.mjs → tools-Dn5KgBUI.mjs} +38 -41
- package/package.json +22 -22
package/dist/cli.cjs
CHANGED
|
@@ -1,14 +1,54 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const require_ListScaffoldingMethodsTool = require(
|
|
3
|
-
const require_src = require(
|
|
4
|
-
const require_tools = require(
|
|
5
|
-
let
|
|
2
|
+
const require_ListScaffoldingMethodsTool = require("./ListScaffoldingMethodsTool-CYZtpU-W.cjs");
|
|
3
|
+
const require_src = require("./src-BG_X82dw.cjs");
|
|
4
|
+
const require_tools = require("./tools-COb9iBtt.cjs");
|
|
5
|
+
let _agiflowai_aicode_utils = require("@agiflowai/aicode-utils");
|
|
6
6
|
let node_path = require("node:path");
|
|
7
|
-
node_path = require_ListScaffoldingMethodsTool.__toESM(node_path);
|
|
7
|
+
node_path = require_ListScaffoldingMethodsTool.__toESM(node_path, 1);
|
|
8
8
|
let commander = require("commander");
|
|
9
|
-
let
|
|
10
|
-
let
|
|
11
|
-
|
|
9
|
+
let _agiflowai_coding_agent_bridge = require("@agiflowai/coding-agent-bridge");
|
|
10
|
+
let _agiflowai_hooks_adapter = require("@agiflowai/hooks-adapter");
|
|
11
|
+
//#region src/commands/utils.ts
|
|
12
|
+
function parseJsonOption(value, flagName) {
|
|
13
|
+
if (!value) throw new Error(`${flagName} is required`);
|
|
14
|
+
try {
|
|
15
|
+
return JSON.parse(value);
|
|
16
|
+
} catch (error) {
|
|
17
|
+
throw new Error(`Invalid JSON for ${flagName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
async function resolveTemplatesPath() {
|
|
21
|
+
const templatesDir = await _agiflowai_aicode_utils.TemplatesManagerService.findTemplatesPath();
|
|
22
|
+
if (!templatesDir) throw new Error("Templates folder not found. Create a templates folder or specify templatesPath in toolkit.yaml");
|
|
23
|
+
return templatesDir;
|
|
24
|
+
}
|
|
25
|
+
async function detectMonolithMode() {
|
|
26
|
+
try {
|
|
27
|
+
return (await _agiflowai_aicode_utils.ProjectConfigResolver.resolveProjectConfig(process.cwd())).type === "monolith";
|
|
28
|
+
} catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
async function loadTextOption(config) {
|
|
33
|
+
const { value, filePath, valueFlag, fileFlag, required = false } = config;
|
|
34
|
+
if (value !== void 0 && filePath !== void 0) throw new Error(`Use only one of ${valueFlag} or ${fileFlag}`);
|
|
35
|
+
if (filePath !== void 0) return (0, _agiflowai_aicode_utils.readFile)(filePath, "utf-8");
|
|
36
|
+
if (value !== void 0) return value;
|
|
37
|
+
if (required) throw new Error(`${valueFlag} or ${fileFlag} is required`);
|
|
38
|
+
}
|
|
39
|
+
function collectOption(value, previous = []) {
|
|
40
|
+
return [...previous, value];
|
|
41
|
+
}
|
|
42
|
+
function firstTextContent(result) {
|
|
43
|
+
const firstContent = result.content[0];
|
|
44
|
+
return firstContent?.type === "text" ? firstContent.text : "";
|
|
45
|
+
}
|
|
46
|
+
function assertToolSuccess(result) {
|
|
47
|
+
const text = firstTextContent(result);
|
|
48
|
+
if (result.isError) throw new Error(text || "Tool execution failed");
|
|
49
|
+
return text;
|
|
50
|
+
}
|
|
51
|
+
//#endregion
|
|
12
52
|
//#region src/commands/boilerplate.ts
|
|
13
53
|
/**
|
|
14
54
|
* Boilerplate CLI command
|
|
@@ -16,40 +56,40 @@ let __agiflowai_hooks_adapter = require("@agiflowai/hooks-adapter");
|
|
|
16
56
|
const boilerplateCommand = new commander.Command("boilerplate").description("Manage boilerplate templates");
|
|
17
57
|
boilerplateCommand.command("list").description("List all available boilerplate templates").option("-c, --cursor <cursor>", "Pagination cursor for next page").action(async (options) => {
|
|
18
58
|
try {
|
|
19
|
-
const templatesDir = await
|
|
59
|
+
const templatesDir = await _agiflowai_aicode_utils.TemplatesManagerService.findTemplatesPath();
|
|
20
60
|
if (!templatesDir) {
|
|
21
|
-
|
|
61
|
+
_agiflowai_aicode_utils.messages.error("Templates folder not found. Create a templates folder or specify templatesPath in toolkit.yaml");
|
|
22
62
|
process.exit(1);
|
|
23
63
|
}
|
|
24
64
|
const { boilerplates, nextCursor } = await new require_tools.BoilerplateService(templatesDir).listBoilerplates(options.cursor);
|
|
25
65
|
if (boilerplates.length === 0) {
|
|
26
|
-
|
|
66
|
+
_agiflowai_aicode_utils.messages.warning("No boilerplate templates found.");
|
|
27
67
|
return;
|
|
28
68
|
}
|
|
29
|
-
|
|
69
|
+
_agiflowai_aicode_utils.print.header(`\n${_agiflowai_aicode_utils.icons.package} Available Boilerplate Templates:\n`);
|
|
30
70
|
for (const bp of boilerplates) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
71
|
+
_agiflowai_aicode_utils.print.highlight(` ${bp.name}`);
|
|
72
|
+
_agiflowai_aicode_utils.print.debug(` ${bp.description}`);
|
|
73
|
+
_agiflowai_aicode_utils.print.debug(` Target: ${bp.target_folder}`);
|
|
34
74
|
const required = typeof bp.variables_schema === "object" && bp.variables_schema !== null && "required" in bp.variables_schema ? bp.variables_schema.required : [];
|
|
35
|
-
if (required && required.length > 0)
|
|
36
|
-
|
|
75
|
+
if (required && required.length > 0) _agiflowai_aicode_utils.print.debug(` Required: ${required.join(", ")}`);
|
|
76
|
+
_agiflowai_aicode_utils.print.newline();
|
|
37
77
|
}
|
|
38
78
|
if (nextCursor) {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
79
|
+
_agiflowai_aicode_utils.print.newline();
|
|
80
|
+
_agiflowai_aicode_utils.print.info(`${_agiflowai_aicode_utils.icons.info} More results available. Use --cursor to fetch next page:`);
|
|
81
|
+
_agiflowai_aicode_utils.print.debug(` scaffold-mcp boilerplate list --cursor "${nextCursor}"`);
|
|
42
82
|
}
|
|
43
83
|
} catch (error) {
|
|
44
|
-
|
|
84
|
+
_agiflowai_aicode_utils.messages.error("Error listing boilerplates:", error);
|
|
45
85
|
process.exit(1);
|
|
46
86
|
}
|
|
47
87
|
});
|
|
48
|
-
boilerplateCommand.command("create <boilerplateName>").description("Create a new project from a boilerplate template").option("-v, --vars <json>", "JSON string containing variables for the boilerplate").option("-m, --monolith", "Create as monolith project at workspace root with toolkit.yaml (default: false, creates as monorepo with project.json)").option("-t, --target-folder <path>", "Override target folder (defaults to boilerplate targetFolder for monorepo, workspace root for monolith)").option("--verbose", "Enable verbose logging").action(async (boilerplateName, options) => {
|
|
88
|
+
boilerplateCommand.command("create <boilerplateName>").description("Create a new project from a boilerplate template").option("-v, --vars <json>", "JSON string containing variables for the boilerplate").option("-m, --monolith", "Create as monolith project at workspace root with toolkit.yaml (default: false, creates as monorepo with project.json)").option("-t, --target-folder <path>", "Override target folder (defaults to boilerplate targetFolder for monorepo, workspace root for monolith)").option("--marker <tag>", "Custom scaffold marker tag to inject into generated code files").option("--verbose", "Enable verbose logging").action(async (boilerplateName, options) => {
|
|
49
89
|
try {
|
|
50
|
-
const templatesDir = await
|
|
90
|
+
const templatesDir = await _agiflowai_aicode_utils.TemplatesManagerService.findTemplatesPath();
|
|
51
91
|
if (!templatesDir) {
|
|
52
|
-
|
|
92
|
+
_agiflowai_aicode_utils.messages.error("Templates folder not found. Create a templates folder or specify templatesPath in toolkit.yaml");
|
|
53
93
|
process.exit(1);
|
|
54
94
|
}
|
|
55
95
|
const boilerplateService = new require_tools.BoilerplateService(templatesDir);
|
|
@@ -57,8 +97,8 @@ boilerplateCommand.command("create <boilerplateName>").description("Create a new
|
|
|
57
97
|
if (options.vars) try {
|
|
58
98
|
variables = JSON.parse(options.vars);
|
|
59
99
|
} catch (error) {
|
|
60
|
-
|
|
61
|
-
|
|
100
|
+
_agiflowai_aicode_utils.messages.error("Error parsing variables JSON:", error);
|
|
101
|
+
_agiflowai_aicode_utils.messages.hint("Example: --vars '{\"appName\": \"my-app\", \"description\": \"My application\"}'");
|
|
62
102
|
process.exit(1);
|
|
63
103
|
}
|
|
64
104
|
const boilerplate = await boilerplateService.getBoilerplate(boilerplateName);
|
|
@@ -66,41 +106,42 @@ boilerplateCommand.command("create <boilerplateName>").description("Create a new
|
|
|
66
106
|
let allBoilerplates = [];
|
|
67
107
|
let cursor;
|
|
68
108
|
do {
|
|
69
|
-
const result
|
|
70
|
-
allBoilerplates = allBoilerplates.concat(result
|
|
71
|
-
cursor = result
|
|
109
|
+
const result = await boilerplateService.listBoilerplates(cursor);
|
|
110
|
+
allBoilerplates = allBoilerplates.concat(result.boilerplates);
|
|
111
|
+
cursor = result.nextCursor;
|
|
72
112
|
} while (cursor);
|
|
73
|
-
|
|
74
|
-
|
|
113
|
+
_agiflowai_aicode_utils.messages.error(`Boilerplate '${boilerplateName}' not found.`);
|
|
114
|
+
_agiflowai_aicode_utils.print.warning(`Available boilerplates: ${allBoilerplates.map((b) => b.name).join(", ")}`);
|
|
75
115
|
process.exit(1);
|
|
76
116
|
}
|
|
77
117
|
const required = typeof boilerplate.variables_schema === "object" && boilerplate.variables_schema !== null && "required" in boilerplate.variables_schema ? boilerplate.variables_schema.required : [];
|
|
78
118
|
const missing = required.filter((key) => !variables[key]);
|
|
79
119
|
if (missing.length > 0) {
|
|
80
|
-
|
|
81
|
-
|
|
120
|
+
_agiflowai_aicode_utils.messages.error(`Missing required variables: ${missing.join(", ")}`);
|
|
121
|
+
_agiflowai_aicode_utils.messages.hint(`Use --vars with a JSON object containing: ${missing.join(", ")}`);
|
|
82
122
|
const exampleVars = {};
|
|
83
123
|
for (const key of required) if (key === "appName" || key === "packageName") exampleVars[key] = "my-app";
|
|
84
124
|
else if (key === "description") exampleVars[key] = "My application description";
|
|
85
125
|
else exampleVars[key] = `<${key}>`;
|
|
86
|
-
|
|
126
|
+
_agiflowai_aicode_utils.print.debug(`Example: scaffold-mcp boilerplate create ${boilerplateName} --vars '${JSON.stringify(exampleVars)}'`);
|
|
87
127
|
process.exit(1);
|
|
88
128
|
}
|
|
89
129
|
if (options.verbose) {
|
|
90
|
-
|
|
91
|
-
|
|
130
|
+
_agiflowai_aicode_utils.print.info(`${_agiflowai_aicode_utils.icons.wrench} Boilerplate: ${boilerplateName}`);
|
|
131
|
+
_agiflowai_aicode_utils.print.info(`${_agiflowai_aicode_utils.icons.chart} Variables: ${JSON.stringify(variables, null, 2)}`);
|
|
92
132
|
}
|
|
93
|
-
|
|
133
|
+
_agiflowai_aicode_utils.messages.loading(`Creating project from boilerplate '${boilerplateName}'...`);
|
|
94
134
|
const result = await boilerplateService.useBoilerplate({
|
|
95
135
|
boilerplateName,
|
|
96
136
|
variables,
|
|
97
137
|
monolith: options.monolith,
|
|
98
|
-
targetFolderOverride: options.targetFolder
|
|
138
|
+
targetFolderOverride: options.targetFolder,
|
|
139
|
+
marker: options.marker
|
|
99
140
|
});
|
|
100
141
|
if (result.success) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (result.createdFiles && result.createdFiles.length > 0)
|
|
142
|
+
_agiflowai_aicode_utils.messages.success("Project created successfully!");
|
|
143
|
+
_agiflowai_aicode_utils.print.info(result.message);
|
|
144
|
+
if (result.createdFiles && result.createdFiles.length > 0) _agiflowai_aicode_utils.sections.createdFiles(result.createdFiles);
|
|
104
145
|
const projectName = variables.appName || variables.packageName;
|
|
105
146
|
if (projectName) {
|
|
106
147
|
const targetFolder = options.targetFolder || (options.monolith ? "." : boilerplate.target_folder);
|
|
@@ -110,43 +151,100 @@ boilerplateCommand.command("create <boilerplateName>").description("Create a new
|
|
|
110
151
|
"pnpm install",
|
|
111
152
|
"pnpm dev"
|
|
112
153
|
];
|
|
113
|
-
|
|
154
|
+
_agiflowai_aicode_utils.sections.nextSteps(steps);
|
|
114
155
|
}
|
|
115
156
|
} else {
|
|
116
|
-
|
|
157
|
+
_agiflowai_aicode_utils.messages.error(`Failed to create project: ${result.message}`);
|
|
117
158
|
process.exit(1);
|
|
118
159
|
}
|
|
119
160
|
} catch (error) {
|
|
120
|
-
|
|
161
|
+
_agiflowai_aicode_utils.messages.error("Error creating project:", error);
|
|
121
162
|
if (options.verbose) console.error("Stack trace:", error.stack);
|
|
122
163
|
process.exit(1);
|
|
123
164
|
}
|
|
124
165
|
});
|
|
166
|
+
boilerplateCommand.command("generate <boilerplateName>").description("Create a new boilerplate configuration in a template's scaffold.yaml").option("-t, --template <name>", "Template name (optional in monolith mode)").option("--description <text>", "Boilerplate description").option("--description-file <path>", "Read boilerplate description from a file").option("--instruction <text>", "Detailed boilerplate instructions").option("--instruction-file <path>", "Read detailed boilerplate instructions from a file").option("--target-folder <path>", "Target folder for generated projects").option("--variables <json>", "JSON array of variable definitions: [{\"name\":\"appName\",\"description\":\"App name\",\"type\":\"string\",\"required\":true}]").option("-i, --include <path>", "Template include path (repeatable)", collectOption, []).action(async (boilerplateName, options) => {
|
|
167
|
+
try {
|
|
168
|
+
const templatesPath = await resolveTemplatesPath();
|
|
169
|
+
const isMonolith = await detectMonolithMode();
|
|
170
|
+
const description = await loadTextOption({
|
|
171
|
+
value: options.description,
|
|
172
|
+
filePath: options.descriptionFile,
|
|
173
|
+
valueFlag: "--description",
|
|
174
|
+
fileFlag: "--description-file",
|
|
175
|
+
required: true
|
|
176
|
+
});
|
|
177
|
+
const instruction = await loadTextOption({
|
|
178
|
+
value: options.instruction,
|
|
179
|
+
filePath: options.instructionFile,
|
|
180
|
+
valueFlag: "--instruction",
|
|
181
|
+
fileFlag: "--instruction-file"
|
|
182
|
+
});
|
|
183
|
+
const variables = parseJsonOption(options.variables, "--variables");
|
|
184
|
+
if (!Array.isArray(variables)) throw new Error("--variables must be a JSON array");
|
|
185
|
+
const targetFolder = options.targetFolder ?? (isMonolith ? "." : void 0);
|
|
186
|
+
if (!targetFolder) throw new Error("--target-folder is required outside monolith mode");
|
|
187
|
+
const result = await new require_tools.GenerateBoilerplateTool(templatesPath, isMonolith).execute({
|
|
188
|
+
templateName: options.template,
|
|
189
|
+
boilerplateName,
|
|
190
|
+
description: description ?? "",
|
|
191
|
+
instruction,
|
|
192
|
+
targetFolder,
|
|
193
|
+
variables,
|
|
194
|
+
includes: options.include ?? []
|
|
195
|
+
});
|
|
196
|
+
_agiflowai_aicode_utils.print.info(assertToolSuccess(result));
|
|
197
|
+
} catch (error) {
|
|
198
|
+
_agiflowai_aicode_utils.print.error("Error generating boilerplate:", error instanceof Error ? error.message : String(error));
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
});
|
|
125
202
|
boilerplateCommand.command("info <boilerplateName>").description("Show detailed information about a boilerplate template").action(async (boilerplateName) => {
|
|
126
203
|
try {
|
|
127
|
-
const templatesDir = await
|
|
204
|
+
const templatesDir = await _agiflowai_aicode_utils.TemplatesManagerService.findTemplatesPath();
|
|
128
205
|
if (!templatesDir) {
|
|
129
|
-
|
|
206
|
+
_agiflowai_aicode_utils.messages.error("Templates folder not found. Create a templates folder or specify templatesPath in toolkit.yaml");
|
|
130
207
|
process.exit(1);
|
|
131
208
|
}
|
|
132
209
|
const bp = await new require_tools.BoilerplateService(templatesDir).getBoilerplate(boilerplateName);
|
|
133
210
|
if (!bp) {
|
|
134
|
-
|
|
211
|
+
_agiflowai_aicode_utils.messages.error(`Boilerplate '${boilerplateName}' not found.`);
|
|
135
212
|
process.exit(1);
|
|
136
213
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
214
|
+
_agiflowai_aicode_utils.print.header(`\n${_agiflowai_aicode_utils.icons.package} Boilerplate: ${bp.name}\n`);
|
|
215
|
+
_agiflowai_aicode_utils.print.debug(`Description: ${bp.description}`);
|
|
216
|
+
_agiflowai_aicode_utils.print.debug(`Template Path: ${bp.template_path}`);
|
|
217
|
+
_agiflowai_aicode_utils.print.debug(`Target Folder: ${bp.target_folder}`);
|
|
218
|
+
_agiflowai_aicode_utils.print.header(`\n${_agiflowai_aicode_utils.icons.config} Variables Schema:`);
|
|
142
219
|
console.log(JSON.stringify(bp.variables_schema, null, 2));
|
|
143
|
-
if (bp.includes && bp.includes.length > 0)
|
|
220
|
+
if (bp.includes && bp.includes.length > 0) _agiflowai_aicode_utils.sections.list(`${_agiflowai_aicode_utils.icons.folder} Included Files:`, bp.includes);
|
|
221
|
+
} catch (error) {
|
|
222
|
+
_agiflowai_aicode_utils.messages.error("Error getting boilerplate info:", error);
|
|
223
|
+
process.exit(1);
|
|
224
|
+
}
|
|
225
|
+
});
|
|
226
|
+
//#endregion
|
|
227
|
+
//#region src/commands/file.ts
|
|
228
|
+
const fileCommand$1 = new commander.Command("file").description("Workspace file utilities");
|
|
229
|
+
fileCommand$1.command("write <filePath>").description("Write content to a file inside the current workspace").option("--content <text>", "Content to write").option("--content-file <path>", "Read content to write from a file").action(async (filePath, options) => {
|
|
230
|
+
try {
|
|
231
|
+
const content = await loadTextOption({
|
|
232
|
+
value: options.content,
|
|
233
|
+
filePath: options.contentFile,
|
|
234
|
+
valueFlag: "--content",
|
|
235
|
+
fileFlag: "--content-file",
|
|
236
|
+
required: true
|
|
237
|
+
});
|
|
238
|
+
const result = await new require_tools.WriteToFileTool().execute({
|
|
239
|
+
file_path: filePath,
|
|
240
|
+
content
|
|
241
|
+
});
|
|
242
|
+
_agiflowai_aicode_utils.print.info(assertToolSuccess(result));
|
|
144
243
|
} catch (error) {
|
|
145
|
-
|
|
244
|
+
_agiflowai_aicode_utils.print.error("Error writing file:", error instanceof Error ? error.message : String(error));
|
|
146
245
|
process.exit(1);
|
|
147
246
|
}
|
|
148
247
|
});
|
|
149
|
-
|
|
150
248
|
//#endregion
|
|
151
249
|
//#region src/commands/mcp-serve.ts
|
|
152
250
|
/**
|
|
@@ -180,7 +278,7 @@ function isRecord(value) {
|
|
|
180
278
|
*/
|
|
181
279
|
function parseLlmToolOption(value, flagName) {
|
|
182
280
|
if (!value) return void 0;
|
|
183
|
-
if (!(0,
|
|
281
|
+
if (!(0, _agiflowai_coding_agent_bridge.isValidLlmTool)(value)) throw new Error(`Invalid ${flagName}: ${value}. Supported: ${_agiflowai_coding_agent_bridge.SUPPORTED_LLM_TOOLS.join(", ")}`);
|
|
184
282
|
return value;
|
|
185
283
|
}
|
|
186
284
|
/**
|
|
@@ -217,12 +315,12 @@ async function startServer(handler) {
|
|
|
217
315
|
throw new Error(`Failed to start transport: ${error instanceof Error ? error.message : String(error)}`);
|
|
218
316
|
}
|
|
219
317
|
const shutdown = async (signal) => {
|
|
220
|
-
|
|
318
|
+
_agiflowai_aicode_utils.print.error(`\nReceived ${signal}, shutting down gracefully...`);
|
|
221
319
|
try {
|
|
222
320
|
await handler.stop();
|
|
223
321
|
process.exit(0);
|
|
224
322
|
} catch (error) {
|
|
225
|
-
|
|
323
|
+
_agiflowai_aicode_utils.print.error("Error during shutdown:", error instanceof Error ? error : String(error));
|
|
226
324
|
process.exit(1);
|
|
227
325
|
}
|
|
228
326
|
};
|
|
@@ -230,23 +328,23 @@ async function startServer(handler) {
|
|
|
230
328
|
try {
|
|
231
329
|
await shutdown("SIGINT");
|
|
232
330
|
} catch (error) {
|
|
233
|
-
|
|
331
|
+
_agiflowai_aicode_utils.print.error("Unexpected shutdown error:", error instanceof Error ? error : String(error));
|
|
234
332
|
}
|
|
235
333
|
});
|
|
236
334
|
process.on("SIGTERM", async () => {
|
|
237
335
|
try {
|
|
238
336
|
await shutdown("SIGTERM");
|
|
239
337
|
} catch (error) {
|
|
240
|
-
|
|
338
|
+
_agiflowai_aicode_utils.print.error("Unexpected shutdown error:", error instanceof Error ? error : String(error));
|
|
241
339
|
}
|
|
242
340
|
});
|
|
243
341
|
}
|
|
244
342
|
/**
|
|
245
343
|
* MCP Serve command
|
|
246
344
|
*/
|
|
247
|
-
const mcpServeCommand = new commander.Command("mcp-serve").description("Start MCP server with specified transport").option("-t, --type <type>", "Transport type: stdio, http, or sse").option("-p, --port <port>", "Port to listen on (http/sse only)", (val) => parseInt(val, 10)).option("--host <host>", "Host to bind to (http/sse only)").option("--admin-enable", "Enable admin tools (generate-boilerplate)", false).option("--prompt-as-skill", "Render prompts with skill front matter for Claude Code skills", false).option("--fallback-tool <tool>", `Fallback LLM tool for scaffold operations. Supported: ${
|
|
345
|
+
const mcpServeCommand = new commander.Command("mcp-serve").description("Start MCP server with specified transport").option("-t, --type <type>", "Transport type: stdio, http, or sse").option("-p, --port <port>", "Port to listen on (http/sse only)", (val) => parseInt(val, 10)).option("--host <host>", "Host to bind to (http/sse only)").option("--admin-enable", "Enable admin tools (generate-boilerplate)", false).option("--prompt-as-skill", "Render prompts with skill front matter for Claude Code skills", false).option("--fallback-tool <tool>", `Fallback LLM tool for scaffold operations. Supported: ${_agiflowai_coding_agent_bridge.SUPPORTED_LLM_TOOLS.join(", ")}`).option("--fallback-tool-config <json>", "JSON config for fallback tool (e.g., '{\"model\":\"claude-sonnet-4-6\"}')").action(async (options) => {
|
|
248
346
|
try {
|
|
249
|
-
const fileConfig = (await
|
|
347
|
+
const fileConfig = (await _agiflowai_aicode_utils.TemplatesManagerService.readToolkitConfig())?.["scaffold-mcp"]?.["mcp-serve"] ?? {};
|
|
250
348
|
const transportType = (options.type ?? fileConfig.type ?? "stdio").toLowerCase();
|
|
251
349
|
const adminEnable = options.adminEnable || fileConfig.adminEnable || false;
|
|
252
350
|
const promptAsSkill = options.promptAsSkill || fileConfig.promptAsSkill || false;
|
|
@@ -255,9 +353,9 @@ const mcpServeCommand = new commander.Command("mcp-serve").description("Start MC
|
|
|
255
353
|
const fallbackToolConfig = options.fallbackToolConfig ? parseJsonConfig(options.fallbackToolConfig, "--fallback-tool-config") : configuredFallback.config;
|
|
256
354
|
let isMonolith = false;
|
|
257
355
|
try {
|
|
258
|
-
isMonolith = (await
|
|
356
|
+
isMonolith = (await _agiflowai_aicode_utils.ProjectConfigResolver.resolveProjectConfig(process.cwd())).type === "monolith";
|
|
259
357
|
} catch (error) {
|
|
260
|
-
|
|
358
|
+
_agiflowai_aicode_utils.print.info(`No project config found, defaulting to monorepo mode: ${error instanceof Error ? error.message : String(error)}`);
|
|
261
359
|
isMonolith = false;
|
|
262
360
|
}
|
|
263
361
|
const serverOptions = {
|
|
@@ -285,15 +383,14 @@ const mcpServeCommand = new commander.Command("mcp-serve").description("Start MC
|
|
|
285
383
|
host
|
|
286
384
|
}));
|
|
287
385
|
} else {
|
|
288
|
-
|
|
386
|
+
_agiflowai_aicode_utils.print.error(`Unknown transport type: ${transportType}. Use: stdio, http, or sse`);
|
|
289
387
|
process.exit(1);
|
|
290
388
|
}
|
|
291
389
|
} catch (error) {
|
|
292
|
-
|
|
390
|
+
_agiflowai_aicode_utils.print.error("Failed to start MCP server:", error instanceof Error ? error : String(error));
|
|
293
391
|
process.exit(1);
|
|
294
392
|
}
|
|
295
393
|
});
|
|
296
|
-
|
|
297
394
|
//#endregion
|
|
298
395
|
//#region src/commands/scaffold.ts
|
|
299
396
|
/**
|
|
@@ -302,77 +399,71 @@ const mcpServeCommand = new commander.Command("mcp-serve").description("Start MC
|
|
|
302
399
|
const scaffoldCommand = new commander.Command("scaffold").description("Add features to existing projects");
|
|
303
400
|
scaffoldCommand.command("list [projectPath]").description("List available scaffolding methods for a project or template").option("-t, --template <name>", "Template name (e.g., nextjs-15, typescript-mcp-package)").option("-c, --cursor <cursor>", "Pagination cursor for next page").action(async (projectPath, options) => {
|
|
304
401
|
try {
|
|
305
|
-
|
|
306
|
-
__agiflowai_aicode_utils.messages.error("Either projectPath or --template option must be provided");
|
|
307
|
-
__agiflowai_aicode_utils.messages.hint("Examples:");
|
|
308
|
-
__agiflowai_aicode_utils.print.debug(" scaffold-mcp scaffold list ./my-project");
|
|
309
|
-
__agiflowai_aicode_utils.print.debug(" scaffold-mcp scaffold list --template nextjs-15");
|
|
310
|
-
process.exit(1);
|
|
311
|
-
}
|
|
312
|
-
const templatesDir = await __agiflowai_aicode_utils.TemplatesManagerService.findTemplatesPath();
|
|
402
|
+
const templatesDir = await _agiflowai_aicode_utils.TemplatesManagerService.findTemplatesPath();
|
|
313
403
|
if (!templatesDir) {
|
|
314
|
-
|
|
404
|
+
_agiflowai_aicode_utils.messages.error("Templates folder not found. Create a templates folder or specify templatesPath in toolkit.yaml");
|
|
315
405
|
process.exit(1);
|
|
316
406
|
}
|
|
317
407
|
const scaffoldingMethodsService = new require_ListScaffoldingMethodsTool.ScaffoldingMethodsService(new require_ListScaffoldingMethodsTool.FileSystemService(), templatesDir);
|
|
318
408
|
let result;
|
|
319
409
|
let displayName;
|
|
320
|
-
if (projectPath) {
|
|
321
|
-
const
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
410
|
+
if (projectPath || !options.template) {
|
|
411
|
+
const inputProjectPath = projectPath ?? process.cwd();
|
|
412
|
+
const absolutePath = node_path.default.resolve(inputProjectPath);
|
|
413
|
+
if (!await _agiflowai_aicode_utils.ProjectConfigResolver.hasConfiguration(absolutePath)) {
|
|
414
|
+
_agiflowai_aicode_utils.messages.error(`No project configuration found in ${absolutePath}`);
|
|
415
|
+
_agiflowai_aicode_utils.messages.hint("For monorepo: ensure project.json exists with sourceTemplate field\nFor monolith: ensure toolkit.yaml exists at workspace root\nOr use --template option to list methods for a specific template");
|
|
325
416
|
process.exit(1);
|
|
326
417
|
}
|
|
327
418
|
result = await scaffoldingMethodsService.listScaffoldingMethods(absolutePath, options.cursor);
|
|
328
|
-
displayName = projectPath;
|
|
419
|
+
displayName = projectPath ?? absolutePath;
|
|
329
420
|
} else {
|
|
330
421
|
result = await scaffoldingMethodsService.listScaffoldingMethodsByTemplate(options.template, options.cursor);
|
|
331
422
|
displayName = `template: ${options.template}`;
|
|
332
423
|
}
|
|
333
424
|
const methods = result.methods;
|
|
334
425
|
if (methods.length === 0) {
|
|
335
|
-
|
|
426
|
+
_agiflowai_aicode_utils.messages.warning(`No scaffolding methods available for ${displayName}.`);
|
|
336
427
|
return;
|
|
337
428
|
}
|
|
338
|
-
|
|
429
|
+
_agiflowai_aicode_utils.print.header(`\n${_agiflowai_aicode_utils.icons.wrench} Available Scaffolding Methods for ${displayName}:\n`);
|
|
339
430
|
for (const method of methods) {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
if (method.variables_schema.required && method.variables_schema.required.length > 0)
|
|
343
|
-
|
|
431
|
+
_agiflowai_aicode_utils.print.highlight(` ${method.name}`);
|
|
432
|
+
_agiflowai_aicode_utils.print.debug(` ${method.instruction || method.description || "No description available"}`);
|
|
433
|
+
if (method.variables_schema.required && method.variables_schema.required.length > 0) _agiflowai_aicode_utils.print.debug(` Required: ${method.variables_schema.required.join(", ")}`);
|
|
434
|
+
_agiflowai_aicode_utils.print.newline();
|
|
344
435
|
}
|
|
345
436
|
if (result.nextCursor) {
|
|
346
|
-
|
|
347
|
-
|
|
437
|
+
_agiflowai_aicode_utils.print.newline();
|
|
438
|
+
_agiflowai_aicode_utils.print.info(`${_agiflowai_aicode_utils.icons.info} More results available. Use --cursor to fetch next page:`);
|
|
348
439
|
const cursorOption = `--cursor "${result.nextCursor}"`;
|
|
349
|
-
if (projectPath)
|
|
350
|
-
else
|
|
440
|
+
if (projectPath) _agiflowai_aicode_utils.print.debug(` scaffold-mcp scaffold list ${projectPath} ${cursorOption}`);
|
|
441
|
+
else _agiflowai_aicode_utils.print.debug(` scaffold-mcp scaffold list --template ${options.template} ${cursorOption}`);
|
|
351
442
|
}
|
|
352
443
|
} catch (error) {
|
|
353
|
-
|
|
444
|
+
_agiflowai_aicode_utils.messages.error("Error listing scaffolding methods:", error);
|
|
354
445
|
process.exit(1);
|
|
355
446
|
}
|
|
356
447
|
});
|
|
357
|
-
scaffoldCommand.command("add <featureName>").description("Add a feature to an existing project").option("-p, --project <path>", "Project path", process.cwd()).option("-v, --vars <json>", "JSON string containing variables for the feature").option("--verbose", "Enable verbose logging").action(async (featureName, options) => {
|
|
448
|
+
scaffoldCommand.command("add <featureName>").description("Add a feature to an existing project").option("-p, --project <path>", "Project path", process.cwd()).option("-v, --vars <json>", "JSON string containing variables for the feature").option("--marker <tag>", "Custom scaffold marker tag to inject into generated code files").option("--verbose", "Enable verbose logging").action(async (featureName, options) => {
|
|
358
449
|
try {
|
|
359
450
|
const projectPath = node_path.default.resolve(options.project);
|
|
360
|
-
if (!await
|
|
361
|
-
|
|
362
|
-
|
|
451
|
+
if (!await _agiflowai_aicode_utils.ProjectConfigResolver.hasConfiguration(projectPath)) {
|
|
452
|
+
_agiflowai_aicode_utils.messages.error(`No project configuration found in ${projectPath}`);
|
|
453
|
+
_agiflowai_aicode_utils.messages.hint("For monorepo: ensure project.json exists with sourceTemplate field\nFor monolith: ensure toolkit.yaml exists at workspace root");
|
|
363
454
|
process.exit(1);
|
|
364
455
|
}
|
|
365
456
|
let variables = {};
|
|
366
457
|
if (options.vars) try {
|
|
367
458
|
variables = JSON.parse(options.vars);
|
|
368
459
|
} catch (error) {
|
|
369
|
-
|
|
370
|
-
|
|
460
|
+
_agiflowai_aicode_utils.messages.error("Error parsing variables JSON:", error);
|
|
461
|
+
_agiflowai_aicode_utils.messages.hint("Example: --vars '{\"componentName\": \"UserProfile\", \"description\": \"User profile component\"}'");
|
|
371
462
|
process.exit(1);
|
|
372
463
|
}
|
|
373
|
-
const templatesDir = await
|
|
464
|
+
const templatesDir = await _agiflowai_aicode_utils.TemplatesManagerService.findTemplatesPath();
|
|
374
465
|
if (!templatesDir) {
|
|
375
|
-
|
|
466
|
+
_agiflowai_aicode_utils.messages.error("Templates folder not found. Create a templates folder or specify templatesPath in toolkit.yaml");
|
|
376
467
|
process.exit(1);
|
|
377
468
|
}
|
|
378
469
|
const scaffoldingMethodsService = new require_ListScaffoldingMethodsTool.ScaffoldingMethodsService(new require_ListScaffoldingMethodsTool.FileSystemService(), templatesDir);
|
|
@@ -385,73 +476,116 @@ scaffoldCommand.command("add <featureName>").description("Add a feature to an ex
|
|
|
385
476
|
} while (cursor);
|
|
386
477
|
const method = allMethods.find((m) => m.name === featureName);
|
|
387
478
|
if (!method) {
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
479
|
+
_agiflowai_aicode_utils.messages.error(`Scaffold method '${featureName}' not found.`);
|
|
480
|
+
_agiflowai_aicode_utils.print.warning(`Available methods: ${allMethods.map((m) => m.name).join(", ")}`);
|
|
481
|
+
_agiflowai_aicode_utils.print.debug(`Run 'scaffold-mcp scaffold list ${options.project}' to see all available methods`);
|
|
391
482
|
process.exit(1);
|
|
392
483
|
}
|
|
393
484
|
const required = typeof method.variables_schema === "object" && method.variables_schema !== null && "required" in method.variables_schema ? method.variables_schema.required : [];
|
|
394
485
|
const missing = required.filter((key) => !variables[key]);
|
|
395
486
|
if (missing.length > 0) {
|
|
396
|
-
|
|
397
|
-
|
|
487
|
+
_agiflowai_aicode_utils.messages.error(`❌ Missing required variables: ${missing.join(", ")}`);
|
|
488
|
+
_agiflowai_aicode_utils.messages.hint(`💡 Use --vars with a JSON object containing: ${missing.join(", ")}`);
|
|
398
489
|
const exampleVars = {};
|
|
399
490
|
for (const key of required) if (key.includes("Name")) exampleVars[key] = "MyFeature";
|
|
400
491
|
else if (key === "description") exampleVars[key] = "Feature description";
|
|
401
492
|
else exampleVars[key] = `<${key}>`;
|
|
402
|
-
|
|
493
|
+
_agiflowai_aicode_utils.print.debug(`Example: scaffold-mcp scaffold add ${featureName} --project ${options.project} --vars '${JSON.stringify(exampleVars)}'`);
|
|
403
494
|
process.exit(1);
|
|
404
495
|
}
|
|
405
496
|
if (options.verbose) {
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
497
|
+
_agiflowai_aicode_utils.print.info(`🔧 Feature: ${featureName}`);
|
|
498
|
+
_agiflowai_aicode_utils.print.info(`📊 Variables: ${JSON.stringify(variables, null, 2)}`);
|
|
499
|
+
_agiflowai_aicode_utils.print.info(`📁 Project Path: ${projectPath}`);
|
|
409
500
|
}
|
|
410
|
-
|
|
501
|
+
_agiflowai_aicode_utils.print.info(`🚀 Adding '${featureName}' to project...`);
|
|
411
502
|
const result = await scaffoldingMethodsService.useScaffoldMethod({
|
|
412
503
|
projectPath,
|
|
413
504
|
scaffold_feature_name: featureName,
|
|
414
|
-
variables
|
|
505
|
+
variables,
|
|
506
|
+
marker: options.marker
|
|
415
507
|
});
|
|
416
508
|
if (result.success) {
|
|
417
|
-
|
|
509
|
+
const scaffoldId = (0, _agiflowai_aicode_utils.generateStableId)(6);
|
|
510
|
+
if (result.createdFiles && result.createdFiles.length > 0) await require_tools.writePendingScaffoldLog({
|
|
511
|
+
scaffoldId,
|
|
512
|
+
projectPath,
|
|
513
|
+
featureName,
|
|
514
|
+
generatedFiles: result.createdFiles
|
|
515
|
+
});
|
|
516
|
+
_agiflowai_aicode_utils.messages.success("✅ Feature added successfully!");
|
|
418
517
|
if (result.createdFiles && result.createdFiles.length > 0) {
|
|
419
|
-
|
|
518
|
+
_agiflowai_aicode_utils.print.header("\n📁 Created files:");
|
|
420
519
|
result.createdFiles.forEach((file) => {
|
|
421
|
-
|
|
520
|
+
_agiflowai_aicode_utils.print.debug(` - ${file}`);
|
|
422
521
|
});
|
|
423
522
|
}
|
|
424
523
|
if (result.warnings && result.warnings.length > 0) {
|
|
425
|
-
|
|
524
|
+
_agiflowai_aicode_utils.messages.warning("\n⚠️ Warnings:");
|
|
426
525
|
result.warnings.forEach((warning) => {
|
|
427
|
-
|
|
526
|
+
_agiflowai_aicode_utils.print.debug(` - ${warning}`);
|
|
428
527
|
});
|
|
429
528
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
529
|
+
_agiflowai_aicode_utils.print.debug(`\nSCAFFOLD_ID:${scaffoldId}`);
|
|
530
|
+
_agiflowai_aicode_utils.print.header("\n📋 Next steps:");
|
|
531
|
+
_agiflowai_aicode_utils.print.debug(" - Review the generated files");
|
|
532
|
+
_agiflowai_aicode_utils.print.debug(" - Update imports if necessary");
|
|
533
|
+
_agiflowai_aicode_utils.print.debug(" - Run tests to ensure everything works");
|
|
434
534
|
} else {
|
|
435
|
-
|
|
535
|
+
_agiflowai_aicode_utils.messages.error(`❌ Failed to add feature: ${result.message}`);
|
|
436
536
|
process.exit(1);
|
|
437
537
|
}
|
|
438
538
|
} catch (error) {
|
|
439
|
-
|
|
539
|
+
_agiflowai_aicode_utils.messages.error(`❌ Error adding feature: ${error.message}`);
|
|
540
|
+
process.exit(1);
|
|
541
|
+
}
|
|
542
|
+
});
|
|
543
|
+
scaffoldCommand.command("generate <featureName>").description("Create a new feature scaffold configuration in a template's scaffold.yaml").option("-t, --template <name>", "Template name (optional in monolith mode)").option("--description <text>", "Feature description").option("--description-file <path>", "Read feature description from a file").option("--instruction <text>", "Detailed feature instructions").option("--instruction-file <path>", "Read detailed feature instructions from a file").option("--variables <json>", "JSON array of variable definitions: [{\"name\":\"featureName\",\"description\":\"Feature name\",\"type\":\"string\",\"required\":true}]").option("-i, --include <path>", "Template include path (repeatable)", collectOption, []).option("--pattern <glob>", "File pattern this scaffold applies to (repeatable)", collectOption, []).action(async (featureName, options) => {
|
|
544
|
+
try {
|
|
545
|
+
const templatesPath = await resolveTemplatesPath();
|
|
546
|
+
const isMonolith = await detectMonolithMode();
|
|
547
|
+
const description = await loadTextOption({
|
|
548
|
+
value: options.description,
|
|
549
|
+
filePath: options.descriptionFile,
|
|
550
|
+
valueFlag: "--description",
|
|
551
|
+
fileFlag: "--description-file",
|
|
552
|
+
required: true
|
|
553
|
+
});
|
|
554
|
+
const instruction = await loadTextOption({
|
|
555
|
+
value: options.instruction,
|
|
556
|
+
filePath: options.instructionFile,
|
|
557
|
+
valueFlag: "--instruction",
|
|
558
|
+
fileFlag: "--instruction-file"
|
|
559
|
+
});
|
|
560
|
+
const variables = parseJsonOption(options.variables, "--variables");
|
|
561
|
+
if (!Array.isArray(variables)) throw new Error("--variables must be a JSON array");
|
|
562
|
+
const result = await new require_tools.GenerateFeatureScaffoldTool(templatesPath, isMonolith).execute({
|
|
563
|
+
templateName: options.template,
|
|
564
|
+
featureName,
|
|
565
|
+
description: description ?? "",
|
|
566
|
+
instruction,
|
|
567
|
+
variables,
|
|
568
|
+
includes: options.include ?? [],
|
|
569
|
+
patterns: options.pattern ?? []
|
|
570
|
+
});
|
|
571
|
+
_agiflowai_aicode_utils.print.info(assertToolSuccess(result));
|
|
572
|
+
} catch (error) {
|
|
573
|
+
_agiflowai_aicode_utils.print.error("Error generating feature scaffold:", error instanceof Error ? error.message : String(error));
|
|
440
574
|
process.exit(1);
|
|
441
575
|
}
|
|
442
576
|
});
|
|
443
577
|
scaffoldCommand.command("info <featureName>").description("Show detailed information about a scaffold method").option("-p, --project <path>", "Project path").option("-t, --template <name>", "Template name (e.g., nextjs-15, typescript-mcp-package)").action(async (featureName, options) => {
|
|
444
578
|
try {
|
|
445
579
|
if (!options.project && !options.template) {
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
580
|
+
_agiflowai_aicode_utils.messages.error("Either --project or --template option must be provided");
|
|
581
|
+
_agiflowai_aicode_utils.messages.hint("Examples:");
|
|
582
|
+
_agiflowai_aicode_utils.print.debug(" scaffold-mcp scaffold info scaffold-route --project ./my-app");
|
|
583
|
+
_agiflowai_aicode_utils.print.debug(" scaffold-mcp scaffold info scaffold-route --template nextjs-15");
|
|
450
584
|
process.exit(1);
|
|
451
585
|
}
|
|
452
|
-
const templatesDir = await
|
|
586
|
+
const templatesDir = await _agiflowai_aicode_utils.TemplatesManagerService.findTemplatesPath();
|
|
453
587
|
if (!templatesDir) {
|
|
454
|
-
|
|
588
|
+
_agiflowai_aicode_utils.messages.error("Templates folder not found. Create a templates folder or specify templatesPath in toolkit.yaml");
|
|
455
589
|
process.exit(1);
|
|
456
590
|
}
|
|
457
591
|
const scaffoldingMethodsService = new require_ListScaffoldingMethodsTool.ScaffoldingMethodsService(new require_ListScaffoldingMethodsTool.FileSystemService(), templatesDir);
|
|
@@ -459,9 +593,9 @@ scaffoldCommand.command("info <featureName>").description("Show detailed informa
|
|
|
459
593
|
let cursor;
|
|
460
594
|
if (options.project) {
|
|
461
595
|
const projectPath = node_path.default.resolve(options.project);
|
|
462
|
-
if (!await
|
|
463
|
-
|
|
464
|
-
|
|
596
|
+
if (!await _agiflowai_aicode_utils.ProjectConfigResolver.hasConfiguration(projectPath)) {
|
|
597
|
+
_agiflowai_aicode_utils.messages.error(`No project configuration found in ${projectPath}`);
|
|
598
|
+
_agiflowai_aicode_utils.messages.hint("For monorepo: ensure project.json exists with sourceTemplate field\nFor monolith: ensure toolkit.yaml exists at workspace root\nOr use --template option to view info for a specific template");
|
|
465
599
|
process.exit(1);
|
|
466
600
|
}
|
|
467
601
|
do {
|
|
@@ -476,28 +610,27 @@ scaffoldCommand.command("info <featureName>").description("Show detailed informa
|
|
|
476
610
|
} while (cursor);
|
|
477
611
|
const method = allMethods.find((m) => m.name === featureName);
|
|
478
612
|
if (!method) {
|
|
479
|
-
|
|
613
|
+
_agiflowai_aicode_utils.messages.error(`❌ Scaffold method '${featureName}' not found.`);
|
|
480
614
|
process.exit(1);
|
|
481
615
|
}
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
616
|
+
_agiflowai_aicode_utils.print.header(`\n🔧 Scaffold Method: ${method.name}\n`);
|
|
617
|
+
_agiflowai_aicode_utils.print.debug(`Description: ${method.description}`);
|
|
618
|
+
_agiflowai_aicode_utils.print.header("\n📝 Variables Schema:");
|
|
619
|
+
_agiflowai_aicode_utils.print.debug(JSON.stringify(method.variables_schema, null, 2));
|
|
486
620
|
const includes = "includes" in method ? method.includes : [];
|
|
487
621
|
if (includes && includes.length > 0) {
|
|
488
|
-
|
|
622
|
+
_agiflowai_aicode_utils.print.header("\n📁 Files to be created:");
|
|
489
623
|
includes.forEach((include) => {
|
|
490
624
|
const parts = include.split(">>");
|
|
491
|
-
if (parts.length === 2)
|
|
492
|
-
else
|
|
625
|
+
if (parts.length === 2) _agiflowai_aicode_utils.print.debug(` - ${parts[1].trim()}`);
|
|
626
|
+
else _agiflowai_aicode_utils.print.debug(` - ${include}`);
|
|
493
627
|
});
|
|
494
628
|
}
|
|
495
629
|
} catch (error) {
|
|
496
|
-
|
|
630
|
+
_agiflowai_aicode_utils.messages.error(`❌ Error getting scaffold info: ${error.message}`);
|
|
497
631
|
process.exit(1);
|
|
498
632
|
}
|
|
499
633
|
});
|
|
500
|
-
|
|
501
634
|
//#endregion
|
|
502
635
|
//#region src/commands/hook.ts
|
|
503
636
|
/**
|
|
@@ -563,23 +696,23 @@ function resolveFallbackConfig(config) {
|
|
|
563
696
|
/**
|
|
564
697
|
* Hook command for executing scaffold hooks
|
|
565
698
|
*/
|
|
566
|
-
const hookCommand = new commander.Command("hook").description("Execute scaffold hooks for AI agent integrations").option("--type <agentAndMethod>", "Hook type: <agent>.<method> (e.g., claude-code.postToolUse, gemini-cli.postToolUse)").option("--marker <tag>", "Scaffold marker tag to scan for in phantom code check").option("--fallback-tool <tool>", `Fallback LLM tool for scaffold operations. Supported: ${
|
|
699
|
+
const hookCommand = new commander.Command("hook").description("Execute scaffold hooks for AI agent integrations").option("--type <agentAndMethod>", "Hook type: <agent>.<method> (e.g., claude-code.postToolUse, gemini-cli.postToolUse)").option("--marker <tag>", "Scaffold marker tag to scan for in phantom code check").option("--fallback-tool <tool>", `Fallback LLM tool for scaffold operations. Supported: ${_agiflowai_coding_agent_bridge.SUPPORTED_LLM_TOOLS.join(", ")}`).option("--fallback-tool-config <json>", "JSON config for the fallback tool (e.g., '{\"model\":\"claude-sonnet-4-6\"}')").action(async (options) => {
|
|
567
700
|
try {
|
|
568
701
|
if (!options.type) throw new Error("--type option is required. Examples: claude-code.preToolUse, claude-code.postToolUse, gemini-cli.postToolUse");
|
|
569
|
-
const { agent, hookMethod } = (0,
|
|
570
|
-
const methodConfig = ((await
|
|
702
|
+
const { agent, hookMethod } = (0, _agiflowai_hooks_adapter.parseHookType)(options.type);
|
|
703
|
+
const methodConfig = ((await _agiflowai_aicode_utils.TemplatesManagerService.readToolkitConfig())?.["scaffold-mcp"]?.hook)?.[agent]?.[hookMethod];
|
|
571
704
|
const marker = options.marker ?? "@scaffold-generated";
|
|
572
705
|
const configuredFallback = resolveFallbackConfig(methodConfig);
|
|
573
706
|
const fallbackToolStr = options.fallbackTool ?? methodConfig?.["fallback-tool"] ?? methodConfig?.["llm-tool"] ?? configuredFallback.tool;
|
|
574
707
|
const fallbackToolConfig = options.fallbackToolConfig ? parseJsonConfigOption(options.fallbackToolConfig, "--fallback-tool-config") : methodConfig?.["fallback-tool-config"] ?? methodConfig?.["tool-config"] ?? configuredFallback.config;
|
|
575
|
-
if (fallbackToolStr && !(0,
|
|
708
|
+
if (fallbackToolStr && !(0, _agiflowai_coding_agent_bridge.isValidLlmTool)(fallbackToolStr)) throw new Error(`Invalid --fallback-tool: ${fallbackToolStr}. Supported: ${_agiflowai_coding_agent_bridge.SUPPORTED_LLM_TOOLS.join(", ")}`);
|
|
576
709
|
const adapterConfig = {};
|
|
577
710
|
if (fallbackToolConfig) adapterConfig.tool_config = fallbackToolConfig;
|
|
578
711
|
if (fallbackToolStr) adapterConfig.llm_tool = fallbackToolStr;
|
|
579
712
|
const resolvedAdapterConfig = Object.keys(adapterConfig).length > 0 ? adapterConfig : void 0;
|
|
580
713
|
if (!isHookMethod(hookMethod)) process.exit(0);
|
|
581
|
-
if (agent ===
|
|
582
|
-
const hookModule = await Promise.resolve().then(() => require("./claudeCode-
|
|
714
|
+
if (agent === _agiflowai_coding_agent_bridge.CLAUDE_CODE) {
|
|
715
|
+
const hookModule = await Promise.resolve().then(() => require("./claudeCode-g1eRidPR.cjs"));
|
|
583
716
|
const claudeCallbacks = [];
|
|
584
717
|
if (hookModule.UseScaffoldMethodHook) {
|
|
585
718
|
const hookInstance = new hookModule.UseScaffoldMethodHook();
|
|
@@ -592,9 +725,9 @@ const hookCommand = new commander.Command("hook").description("Execute scaffold
|
|
|
592
725
|
if (hookFn) claudeCallbacks.push(hookFn.bind(hookInstance));
|
|
593
726
|
}
|
|
594
727
|
if (claudeCallbacks.length === 0) process.exit(0);
|
|
595
|
-
await new
|
|
596
|
-
} else if (agent ===
|
|
597
|
-
const hookModule = await Promise.resolve().then(() => require("./geminiCli
|
|
728
|
+
await new _agiflowai_hooks_adapter.ClaudeCodeAdapter().executeMultiple(claudeCallbacks, resolvedAdapterConfig);
|
|
729
|
+
} else if (agent === _agiflowai_coding_agent_bridge.GEMINI_CLI) {
|
|
730
|
+
const hookModule = await Promise.resolve().then(() => require("./geminiCli--s1Qy7ZP.cjs"));
|
|
598
731
|
const geminiCallbacks = [];
|
|
599
732
|
if (hookModule.UseScaffoldMethodHook) {
|
|
600
733
|
const hookInstance = new hookModule.UseScaffoldMethodHook();
|
|
@@ -602,14 +735,52 @@ const hookCommand = new commander.Command("hook").description("Execute scaffold
|
|
|
602
735
|
if (hookFn) geminiCallbacks.push(hookFn.bind(hookInstance));
|
|
603
736
|
}
|
|
604
737
|
if (geminiCallbacks.length === 0) process.exit(0);
|
|
605
|
-
await new
|
|
606
|
-
} else throw new Error(`Unsupported agent: ${agent}. Supported: ${
|
|
738
|
+
await new _agiflowai_hooks_adapter.GeminiCliAdapter().executeMultiple(geminiCallbacks, resolvedAdapterConfig);
|
|
739
|
+
} else throw new Error(`Unsupported agent: ${agent}. Supported: ${_agiflowai_coding_agent_bridge.CLAUDE_CODE}, ${_agiflowai_coding_agent_bridge.GEMINI_CLI}`);
|
|
740
|
+
} catch (error) {
|
|
741
|
+
_agiflowai_aicode_utils.print.error(`Hook error: ${error instanceof Error ? error.message : String(error)}`);
|
|
742
|
+
process.exit(1);
|
|
743
|
+
}
|
|
744
|
+
});
|
|
745
|
+
//#endregion
|
|
746
|
+
//#region src/commands/template.ts
|
|
747
|
+
const templateCommand = new commander.Command("template").description("Manage scaffold template authoring assets");
|
|
748
|
+
const fileCommand = new commander.Command("file").description("Manage template files");
|
|
749
|
+
fileCommand.command("create <filePath>").description("Create or update a Liquid template file for a boilerplate or feature").option("-t, --template <name>", "Template name (optional in monolith mode)").option("--content <text>", "Template file content").option("--content-file <path>", "Read template file content from a file").option("--source-file <path>", "Copy content from an existing source file").option("--header <text>", "Header comment to prepend to the template file").option("--header-file <path>", "Read header comment from a file").action(async (filePath, options) => {
|
|
750
|
+
try {
|
|
751
|
+
if ([
|
|
752
|
+
options.content !== void 0,
|
|
753
|
+
options.contentFile !== void 0,
|
|
754
|
+
options.sourceFile !== void 0
|
|
755
|
+
].filter(Boolean).length !== 1) throw new Error("Use exactly one of --content, --content-file, or --source-file");
|
|
756
|
+
const templatesPath = await resolveTemplatesPath();
|
|
757
|
+
const isMonolith = await detectMonolithMode();
|
|
758
|
+
const content = await loadTextOption({
|
|
759
|
+
value: options.content,
|
|
760
|
+
filePath: options.contentFile,
|
|
761
|
+
valueFlag: "--content",
|
|
762
|
+
fileFlag: "--content-file"
|
|
763
|
+
});
|
|
764
|
+
const header = await loadTextOption({
|
|
765
|
+
value: options.header,
|
|
766
|
+
filePath: options.headerFile,
|
|
767
|
+
valueFlag: "--header",
|
|
768
|
+
fileFlag: "--header-file"
|
|
769
|
+
});
|
|
770
|
+
const result = await new require_tools.GenerateBoilerplateFileTool(templatesPath, isMonolith).execute({
|
|
771
|
+
templateName: options.template,
|
|
772
|
+
filePath,
|
|
773
|
+
content,
|
|
774
|
+
sourceFile: options.sourceFile,
|
|
775
|
+
header
|
|
776
|
+
});
|
|
777
|
+
_agiflowai_aicode_utils.print.info(assertToolSuccess(result));
|
|
607
778
|
} catch (error) {
|
|
608
|
-
|
|
779
|
+
_agiflowai_aicode_utils.print.error("Error creating template file:", error instanceof Error ? error.message : String(error));
|
|
609
780
|
process.exit(1);
|
|
610
781
|
}
|
|
611
782
|
});
|
|
612
|
-
|
|
783
|
+
templateCommand.addCommand(fileCommand);
|
|
613
784
|
//#endregion
|
|
614
785
|
//#region src/cli.ts
|
|
615
786
|
/**
|
|
@@ -621,9 +792,10 @@ async function main() {
|
|
|
621
792
|
program.addCommand(mcpServeCommand);
|
|
622
793
|
program.addCommand(boilerplateCommand);
|
|
623
794
|
program.addCommand(scaffoldCommand);
|
|
795
|
+
program.addCommand(templateCommand);
|
|
796
|
+
program.addCommand(fileCommand$1);
|
|
624
797
|
program.addCommand(hookCommand);
|
|
625
798
|
await program.parseAsync(process.argv);
|
|
626
799
|
}
|
|
627
800
|
main();
|
|
628
|
-
|
|
629
|
-
//#endregion
|
|
801
|
+
//#endregion
|