@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/{ListScaffoldingMethodsTool-D6BkKQyK.mjs → ListScaffoldingMethodsTool-DxdrPlcb.mjs}
RENAMED
|
@@ -3,9 +3,8 @@ import { z } from "zod";
|
|
|
3
3
|
import { Liquid } from "liquidjs";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import yaml from "js-yaml";
|
|
6
|
-
import
|
|
6
|
+
import "@composio/json-schema-to-zod";
|
|
7
7
|
import { fileURLToPath } from "node:url";
|
|
8
|
-
|
|
9
8
|
//#region src/services/TemplateService.ts
|
|
10
9
|
var TemplateService = class {
|
|
11
10
|
liquid;
|
|
@@ -79,7 +78,6 @@ var TemplateService = class {
|
|
|
79
78
|
return [/\{\{.*?\}\}/, /\{%.*?%\}/].some((pattern) => pattern.test(content));
|
|
80
79
|
}
|
|
81
80
|
};
|
|
82
|
-
|
|
83
81
|
//#endregion
|
|
84
82
|
//#region src/utils/pagination.ts
|
|
85
83
|
var PaginationHelper = class PaginationHelper {
|
|
@@ -129,41 +127,39 @@ var PaginationHelper = class PaginationHelper {
|
|
|
129
127
|
return result;
|
|
130
128
|
}
|
|
131
129
|
};
|
|
132
|
-
|
|
133
130
|
//#endregion
|
|
134
131
|
//#region src/services/FileSystemService.ts
|
|
135
132
|
var FileSystemService = class {
|
|
136
|
-
async pathExists(path
|
|
137
|
-
return pathExists(path
|
|
133
|
+
async pathExists(path) {
|
|
134
|
+
return pathExists(path);
|
|
138
135
|
}
|
|
139
|
-
async readFile(path
|
|
140
|
-
return readFile(path
|
|
136
|
+
async readFile(path, encoding = "utf8") {
|
|
137
|
+
return readFile(path, encoding);
|
|
141
138
|
}
|
|
142
|
-
async readJson(path
|
|
143
|
-
return readJson(path
|
|
139
|
+
async readJson(path) {
|
|
140
|
+
return readJson(path);
|
|
144
141
|
}
|
|
145
|
-
async writeFile(path
|
|
146
|
-
return writeFile(path
|
|
142
|
+
async writeFile(path, content, encoding = "utf8") {
|
|
143
|
+
return writeFile(path, content, encoding);
|
|
147
144
|
}
|
|
148
|
-
async ensureDir(path
|
|
149
|
-
return ensureDir(path
|
|
145
|
+
async ensureDir(path) {
|
|
146
|
+
return ensureDir(path);
|
|
150
147
|
}
|
|
151
148
|
async copy(src, dest) {
|
|
152
149
|
return copy(src, dest);
|
|
153
150
|
}
|
|
154
|
-
async readdir(path
|
|
155
|
-
return readdir(path
|
|
151
|
+
async readdir(path) {
|
|
152
|
+
return readdir(path);
|
|
156
153
|
}
|
|
157
|
-
async stat(path
|
|
158
|
-
return stat(path
|
|
154
|
+
async stat(path) {
|
|
155
|
+
return stat(path);
|
|
159
156
|
}
|
|
160
157
|
};
|
|
161
|
-
|
|
162
158
|
//#endregion
|
|
163
159
|
//#region src/services/ScaffoldConfigLoader.ts
|
|
164
160
|
const VariablesSchemaSchema = z.object({
|
|
165
161
|
type: z.literal("object"),
|
|
166
|
-
properties: z.record(z.any()),
|
|
162
|
+
properties: z.record(z.string(), z.any()),
|
|
167
163
|
required: z.array(z.string()),
|
|
168
164
|
additionalProperties: z.boolean()
|
|
169
165
|
});
|
|
@@ -195,7 +191,7 @@ var ScaffoldConfigLoader = class {
|
|
|
195
191
|
return ScaffoldYamlSchema.parse(rawConfig);
|
|
196
192
|
} catch (error) {
|
|
197
193
|
if (error instanceof z.ZodError) {
|
|
198
|
-
const errorMessages = error.
|
|
194
|
+
const errorMessages = error.issues.map((err) => `${err.path.join(".")}: ${err.message}`).join("; ");
|
|
199
195
|
throw new Error(`scaffold.yaml validation failed: ${errorMessages}`);
|
|
200
196
|
}
|
|
201
197
|
throw new Error(`Failed to parse scaffold.yaml: ${error instanceof Error ? error.message : String(error)}`);
|
|
@@ -298,7 +294,6 @@ var ScaffoldConfigLoader = class {
|
|
|
298
294
|
};
|
|
299
295
|
}
|
|
300
296
|
};
|
|
301
|
-
|
|
302
297
|
//#endregion
|
|
303
298
|
//#region src/utils/schemaDefaults.ts
|
|
304
299
|
/**
|
|
@@ -315,7 +310,6 @@ function applySchemaDefaults(schema, variables) {
|
|
|
315
310
|
for (const [key, propSchema] of Object.entries(schema.properties)) if (result[key] === void 0 && propSchema.default !== void 0) result[key] = propSchema.default;
|
|
316
311
|
return result;
|
|
317
312
|
}
|
|
318
|
-
|
|
319
313
|
//#endregion
|
|
320
314
|
//#region src/services/ScaffoldProcessingService.ts
|
|
321
315
|
/**
|
|
@@ -397,10 +391,10 @@ var ScaffoldProcessingService = class {
|
|
|
397
391
|
}
|
|
398
392
|
}));
|
|
399
393
|
const directories = [];
|
|
400
|
-
for (const { itemPath, stat
|
|
401
|
-
if (!stat
|
|
402
|
-
if (stat
|
|
403
|
-
else if (stat
|
|
394
|
+
for (const { itemPath, stat } of statResults) {
|
|
395
|
+
if (!stat) continue;
|
|
396
|
+
if (stat.isDirectory()) directories.push(itemPath);
|
|
397
|
+
else if (stat.isFile()) createdFiles.push(itemPath);
|
|
404
398
|
}
|
|
405
399
|
await Promise.all(directories.map((dir) => this.trackCreatedFilesRecursive(dir, createdFiles)));
|
|
406
400
|
}
|
|
@@ -433,15 +427,14 @@ var ScaffoldProcessingService = class {
|
|
|
433
427
|
}
|
|
434
428
|
}));
|
|
435
429
|
const directories = [];
|
|
436
|
-
for (const { itemPath, stat
|
|
437
|
-
if (!stat
|
|
438
|
-
if (stat
|
|
439
|
-
else if (stat
|
|
430
|
+
for (const { itemPath, stat } of statResults) {
|
|
431
|
+
if (!stat) continue;
|
|
432
|
+
if (stat.isDirectory()) directories.push(itemPath);
|
|
433
|
+
else if (stat.isFile()) existingFiles.push(itemPath);
|
|
440
434
|
}
|
|
441
435
|
await Promise.all(directories.map((dir) => this.trackExistingFilesRecursive(dir, existingFiles)));
|
|
442
436
|
}
|
|
443
437
|
};
|
|
444
|
-
|
|
445
438
|
//#endregion
|
|
446
439
|
//#region src/services/ScaffoldService.ts
|
|
447
440
|
var ScaffoldService = class ScaffoldService {
|
|
@@ -477,7 +470,7 @@ var ScaffoldService = class ScaffoldService {
|
|
|
477
470
|
};
|
|
478
471
|
}
|
|
479
472
|
const architectConfig = await this.scaffoldConfigLoader.parseArchitectConfig(templatePath);
|
|
480
|
-
if (!architectConfig
|
|
473
|
+
if (!architectConfig?.boilerplate) return {
|
|
481
474
|
success: false,
|
|
482
475
|
message: `Invalid architect configuration: missing 'boilerplate' section in scaffold.yaml`
|
|
483
476
|
};
|
|
@@ -530,7 +523,7 @@ var ScaffoldService = class ScaffoldService {
|
|
|
530
523
|
message: `Target directory ${targetPath} does not exist. Please create the parent directory first.`
|
|
531
524
|
};
|
|
532
525
|
const architectConfig = await this.scaffoldConfigLoader.parseArchitectConfig(templatePath);
|
|
533
|
-
if (!architectConfig
|
|
526
|
+
if (!architectConfig?.features) return {
|
|
534
527
|
success: false,
|
|
535
528
|
message: `Invalid architect configuration: missing 'features' section in scaffold.yaml`
|
|
536
529
|
};
|
|
@@ -667,7 +660,6 @@ var ScaffoldService = class ScaffoldService {
|
|
|
667
660
|
};
|
|
668
661
|
}
|
|
669
662
|
};
|
|
670
|
-
|
|
671
663
|
//#endregion
|
|
672
664
|
//#region src/services/VariableReplacementService.ts
|
|
673
665
|
var VariableReplacementService = class {
|
|
@@ -721,10 +713,10 @@ var VariableReplacementService = class {
|
|
|
721
713
|
}));
|
|
722
714
|
const directories = [];
|
|
723
715
|
const files = [];
|
|
724
|
-
for (const { itemPath, stat
|
|
725
|
-
if (!stat
|
|
726
|
-
if (stat
|
|
727
|
-
else if (stat
|
|
716
|
+
for (const { itemPath, stat } of statResults) {
|
|
717
|
+
if (!stat) continue;
|
|
718
|
+
if (stat.isDirectory()) directories.push(itemPath);
|
|
719
|
+
else if (stat.isFile()) files.push(itemPath);
|
|
728
720
|
}
|
|
729
721
|
await Promise.all([...files.map((file) => this.replaceVariablesInFile(file, variables)), ...directories.map((dir) => this.processFilesForVariableReplacement(dir, variables))]);
|
|
730
722
|
}
|
|
@@ -743,7 +735,6 @@ var VariableReplacementService = class {
|
|
|
743
735
|
return this.binaryExtensions.includes(ext);
|
|
744
736
|
}
|
|
745
737
|
};
|
|
746
|
-
|
|
747
738
|
//#endregion
|
|
748
739
|
//#region src/services/ScaffoldingMethodsService.ts
|
|
749
740
|
var ScaffoldingMethodsService = class {
|
|
@@ -971,11 +962,9 @@ Please follow this **instruction**: \n ${method.instruction ? this.processScaffo
|
|
|
971
962
|
};
|
|
972
963
|
}
|
|
973
964
|
};
|
|
974
|
-
|
|
975
965
|
//#endregion
|
|
976
966
|
//#region src/instructions/tools/list-scaffolding-methods/description.md?raw
|
|
977
967
|
var description_default = "Lists all available scaffolding methods (features) that can be added to an existing project{% if not isMonolith %} or for a specific template{% endif %}.\n\nThis tool:\n{% if isMonolith %}\n- Reads your project's sourceTemplate from .toolkit/settings.yaml at workspace root\n{% else %}\n- Reads the project's sourceTemplate from project.json (monorepo) or .toolkit/settings.yaml (monolith), OR\n- Directly uses the provided templateName to list available features\n{% endif %}\n- Returns available features for that template type\n- Provides variable schemas for each scaffolding method\n- Shows descriptions of what each method creates\n\nUse this FIRST when adding features to understand:\n- What scaffolding methods are available\n- What variables each method requires\n- What files/features will be generated\n\nExample methods might include:\n- Adding new React routes (for React apps)\n- Creating API endpoints (for backend projects)\n- Adding new components (for frontend projects)\n- Setting up database models (for API projects)\n";
|
|
978
|
-
|
|
979
968
|
//#endregion
|
|
980
969
|
//#region src/tools/ListScaffoldingMethodsTool.ts
|
|
981
970
|
var ListScaffoldingMethodsTool = class ListScaffoldingMethodsTool {
|
|
@@ -1052,6 +1041,5 @@ var ListScaffoldingMethodsTool = class ListScaffoldingMethodsTool {
|
|
|
1052
1041
|
}
|
|
1053
1042
|
}
|
|
1054
1043
|
};
|
|
1055
|
-
|
|
1056
1044
|
//#endregion
|
|
1057
|
-
export { ScaffoldProcessingService as a, PaginationHelper as c, ScaffoldService as i, TemplateService as l, ScaffoldingMethodsService as n, ScaffoldConfigLoader as o, VariableReplacementService as r, FileSystemService as s, ListScaffoldingMethodsTool as t };
|
|
1045
|
+
export { ScaffoldProcessingService as a, PaginationHelper as c, ScaffoldService as i, TemplateService as l, ScaffoldingMethodsService as n, ScaffoldConfigLoader as o, VariableReplacementService as r, FileSystemService as s, ListScaffoldingMethodsTool as t };
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
import { t as ListScaffoldingMethodsTool } from "./ListScaffoldingMethodsTool-
|
|
2
|
-
import "./tools-
|
|
3
|
-
import { n as resolveNewFileWriteTarget, t as formatScaffoldMethodsHookMessage } from "./shared-
|
|
1
|
+
import { t as ListScaffoldingMethodsTool } from "./ListScaffoldingMethodsTool-DxdrPlcb.mjs";
|
|
2
|
+
import "./tools-Dn5KgBUI.mjs";
|
|
3
|
+
import { n as resolveNewFileWriteTarget, t as formatScaffoldMethodsHookMessage } from "./shared-BVYIN3Is.mjs";
|
|
4
4
|
import { ProjectFinderService, TemplatesManagerService } from "@agiflowai/aicode-utils";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import fs from "node:fs/promises";
|
|
7
7
|
import os from "node:os";
|
|
8
8
|
import { DECISION_ALLOW, DECISION_DENY, DECISION_SKIP, ExecutionLogService } from "@agiflowai/hooks-adapter";
|
|
9
9
|
import { execFileSync } from "node:child_process";
|
|
10
|
-
|
|
11
10
|
//#region src/hooks/claudeCode/phantomCodeCheck.ts
|
|
12
11
|
/**
|
|
13
12
|
* PhantomCodeCheck Hook for Claude Code
|
|
@@ -145,7 +144,6 @@ var PhantomCodeCheckHook = class {
|
|
|
145
144
|
}
|
|
146
145
|
}
|
|
147
146
|
};
|
|
148
|
-
|
|
149
147
|
//#endregion
|
|
150
148
|
//#region src/hooks/claudeCode/useScaffoldMethod.ts
|
|
151
149
|
/**
|
|
@@ -272,8 +270,8 @@ var UseScaffoldMethodHook = class {
|
|
|
272
270
|
const filePath = context.tool_input?.file_path;
|
|
273
271
|
if ((context.tool_name === "mcp__one-mcp__use_tool" ? context.tool_input?.toolName : context.tool_name) === "use-scaffold-method") {
|
|
274
272
|
if (context.hook_event_name === "PostToolUse") {
|
|
275
|
-
const scaffoldId
|
|
276
|
-
if (scaffoldId
|
|
273
|
+
const scaffoldId = extractScaffoldId(context.tool_response);
|
|
274
|
+
if (scaffoldId) await processPendingScaffoldLogs(context.session_id, scaffoldId);
|
|
277
275
|
}
|
|
278
276
|
return {
|
|
279
277
|
decision: DECISION_ALLOW,
|
|
@@ -355,7 +353,7 @@ Don't forget to complete the implementation for all scaffolded files!
|
|
|
355
353
|
*/
|
|
356
354
|
function extractScaffoldId(toolResult) {
|
|
357
355
|
try {
|
|
358
|
-
if (!toolResult
|
|
356
|
+
if (!toolResult?.content) return null;
|
|
359
357
|
for (const item of toolResult.content) if (item.type === "text" && typeof item.text === "string") {
|
|
360
358
|
const match = item.text.match(/^SCAFFOLD_ID:([a-z0-9]+)$/);
|
|
361
359
|
if (match) return match[1];
|
|
@@ -442,6 +440,5 @@ async function processPendingScaffoldLogs(sessionId, scaffoldId) {
|
|
|
442
440
|
if (error instanceof Error && "code" in error && error.code !== "ENOENT") console.error("Error processing pending scaffold logs:", error);
|
|
443
441
|
}
|
|
444
442
|
}
|
|
445
|
-
|
|
446
443
|
//#endregion
|
|
447
|
-
export { PhantomCodeCheckHook, UseScaffoldMethodHook };
|
|
444
|
+
export { PhantomCodeCheckHook, UseScaffoldMethodHook };
|
|
@@ -1,16 +1,15 @@
|
|
|
1
|
-
const require_ListScaffoldingMethodsTool = require(
|
|
2
|
-
require(
|
|
3
|
-
const require_shared = require(
|
|
4
|
-
let
|
|
1
|
+
const require_ListScaffoldingMethodsTool = require("./ListScaffoldingMethodsTool-CYZtpU-W.cjs");
|
|
2
|
+
require("./tools-COb9iBtt.cjs");
|
|
3
|
+
const require_shared = require("./shared-QxPXh-L-.cjs");
|
|
4
|
+
let _agiflowai_aicode_utils = require("@agiflowai/aicode-utils");
|
|
5
5
|
let node_path = require("node:path");
|
|
6
|
-
node_path = require_ListScaffoldingMethodsTool.__toESM(node_path);
|
|
6
|
+
node_path = require_ListScaffoldingMethodsTool.__toESM(node_path, 1);
|
|
7
7
|
let node_fs_promises = require("node:fs/promises");
|
|
8
|
-
node_fs_promises = require_ListScaffoldingMethodsTool.__toESM(node_fs_promises);
|
|
8
|
+
node_fs_promises = require_ListScaffoldingMethodsTool.__toESM(node_fs_promises, 1);
|
|
9
9
|
let node_os = require("node:os");
|
|
10
|
-
node_os = require_ListScaffoldingMethodsTool.__toESM(node_os);
|
|
11
|
-
let
|
|
10
|
+
node_os = require_ListScaffoldingMethodsTool.__toESM(node_os, 1);
|
|
11
|
+
let _agiflowai_hooks_adapter = require("@agiflowai/hooks-adapter");
|
|
12
12
|
let node_child_process = require("node:child_process");
|
|
13
|
-
|
|
14
13
|
//#region src/hooks/claudeCode/phantomCodeCheck.ts
|
|
15
14
|
/**
|
|
16
15
|
* PhantomCodeCheck Hook for Claude Code
|
|
@@ -84,17 +83,17 @@ var PhantomCodeCheckHook = class {
|
|
|
84
83
|
try {
|
|
85
84
|
const phantomFiles = this.scanForPhantomFiles(context.cwd);
|
|
86
85
|
if (phantomFiles.length === 0) return {
|
|
87
|
-
decision:
|
|
86
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
88
87
|
message: "No phantom scaffold files found"
|
|
89
88
|
};
|
|
90
89
|
const fileList = phantomFiles.map((f) => ` - ${f}`).join("\n");
|
|
91
90
|
return {
|
|
92
|
-
decision:
|
|
91
|
+
decision: _agiflowai_hooks_adapter.DECISION_DENY,
|
|
93
92
|
message: `⚠️ ${phantomFiles.length} scaffold file(s) still contain \`${this.markerComment}\` and have not been implemented:\n${fileList}\n\nPlease implement these files and remove the marker comment before ending the session.`
|
|
94
93
|
};
|
|
95
94
|
} catch {
|
|
96
95
|
return {
|
|
97
|
-
decision:
|
|
96
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
98
97
|
message: "PhantomCodeCheckHook.stop error — skipping"
|
|
99
98
|
};
|
|
100
99
|
}
|
|
@@ -107,18 +106,18 @@ var PhantomCodeCheckHook = class {
|
|
|
107
106
|
try {
|
|
108
107
|
const phantomFiles = this.scanForPhantomFiles(context.cwd);
|
|
109
108
|
if (phantomFiles.length === 0) return {
|
|
110
|
-
decision:
|
|
109
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
111
110
|
message: "No phantom scaffold files found"
|
|
112
111
|
};
|
|
113
112
|
const fileList = phantomFiles.map((f) => ` - ${f}`).join("\n");
|
|
114
113
|
return {
|
|
115
|
-
decision:
|
|
114
|
+
decision: _agiflowai_hooks_adapter.DECISION_ALLOW,
|
|
116
115
|
message: "",
|
|
117
116
|
userMessage: `⚠️ Reminder: ${phantomFiles.length} scaffold file(s) still contain \`${this.markerComment}\`:\n${fileList}\n\nPlease implement these files and remove the marker comment.`
|
|
118
117
|
};
|
|
119
118
|
} catch {
|
|
120
119
|
return {
|
|
121
|
-
decision:
|
|
120
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
122
121
|
message: "PhantomCodeCheckHook.userPromptSubmit error — skipping"
|
|
123
122
|
};
|
|
124
123
|
}
|
|
@@ -131,24 +130,23 @@ var PhantomCodeCheckHook = class {
|
|
|
131
130
|
try {
|
|
132
131
|
const phantomFiles = this.scanForPhantomFiles(context.cwd);
|
|
133
132
|
if (phantomFiles.length === 0) return {
|
|
134
|
-
decision:
|
|
133
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
135
134
|
message: "No phantom scaffold files found"
|
|
136
135
|
};
|
|
137
136
|
const fileList = phantomFiles.map((f) => ` - ${f}`).join("\n");
|
|
138
137
|
return {
|
|
139
|
-
decision:
|
|
138
|
+
decision: _agiflowai_hooks_adapter.DECISION_DENY,
|
|
140
139
|
exitCode: 2,
|
|
141
140
|
message: `⚠️ ${phantomFiles.length} scaffold file(s) still contain \`${this.markerComment}\` and have not been implemented:\n${fileList}\n\nTask cannot complete until all scaffold files are implemented.`
|
|
142
141
|
};
|
|
143
142
|
} catch {
|
|
144
143
|
return {
|
|
145
|
-
decision:
|
|
144
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
146
145
|
message: "PhantomCodeCheckHook.taskCompleted error — skipping"
|
|
147
146
|
};
|
|
148
147
|
}
|
|
149
148
|
}
|
|
150
149
|
};
|
|
151
|
-
|
|
152
150
|
//#endregion
|
|
153
151
|
//#region src/hooks/claudeCode/useScaffoldMethod.ts
|
|
154
152
|
/**
|
|
@@ -185,48 +183,48 @@ var UseScaffoldMethodHook = class {
|
|
|
185
183
|
async preToolUse(context) {
|
|
186
184
|
try {
|
|
187
185
|
if (!("tool_name" in context)) return {
|
|
188
|
-
decision:
|
|
186
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
189
187
|
message: "Not a tool use event"
|
|
190
188
|
};
|
|
191
189
|
const filePath = context.tool_input?.file_path;
|
|
192
190
|
const absoluteFilePath = await require_shared.resolveNewFileWriteTarget(context.cwd, context.tool_name, filePath);
|
|
193
191
|
if (!absoluteFilePath || !filePath) return {
|
|
194
|
-
decision:
|
|
192
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
195
193
|
message: "Not a new file write operation"
|
|
196
194
|
};
|
|
197
|
-
const executionLog = new
|
|
195
|
+
const executionLog = new _agiflowai_hooks_adapter.ExecutionLogService(context.session_id);
|
|
198
196
|
if (await executionLog.hasExecuted({
|
|
199
197
|
filePath,
|
|
200
|
-
decision:
|
|
198
|
+
decision: _agiflowai_hooks_adapter.DECISION_DENY
|
|
201
199
|
})) return {
|
|
202
|
-
decision:
|
|
200
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
203
201
|
message: "Scaffolding methods already provided for this file"
|
|
204
202
|
};
|
|
205
|
-
const templatesPath = await
|
|
203
|
+
const templatesPath = await _agiflowai_aicode_utils.TemplatesManagerService.findTemplatesPath();
|
|
206
204
|
if (!templatesPath) return {
|
|
207
|
-
decision:
|
|
205
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
208
206
|
message: "Templates folder not found - skipping scaffold method check"
|
|
209
207
|
};
|
|
210
208
|
const tool = new require_ListScaffoldingMethodsTool.ListScaffoldingMethodsTool(templatesPath, false);
|
|
211
|
-
const projectPath = (await new
|
|
209
|
+
const projectPath = (await new _agiflowai_aicode_utils.ProjectFinderService(await _agiflowai_aicode_utils.TemplatesManagerService.getWorkspaceRoot(context.cwd)).findProjectForFile(absoluteFilePath))?.root || context.cwd;
|
|
212
210
|
const result = await tool.execute({ projectPath });
|
|
213
211
|
const firstContent = result.content[0];
|
|
214
212
|
if (firstContent?.type !== "text") return {
|
|
215
|
-
decision:
|
|
213
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
216
214
|
message: "⚠️ Unexpected response type from scaffolding methods tool"
|
|
217
215
|
};
|
|
218
216
|
if (result.isError) return {
|
|
219
|
-
decision:
|
|
217
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
220
218
|
message: `⚠️ Could not load scaffolding methods: ${firstContent.text}`
|
|
221
219
|
};
|
|
222
220
|
const resultText = firstContent.text;
|
|
223
221
|
if (typeof resultText !== "string") return {
|
|
224
|
-
decision:
|
|
222
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
225
223
|
message: "⚠️ Invalid response format from scaffolding methods tool"
|
|
226
224
|
};
|
|
227
225
|
const parsed = JSON.parse(resultText);
|
|
228
226
|
if (!isScaffoldMethodsResponse(parsed)) return {
|
|
229
|
-
decision:
|
|
227
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
230
228
|
message: "⚠️ Unexpected response shape from scaffolding methods tool"
|
|
231
229
|
};
|
|
232
230
|
const data = parsed;
|
|
@@ -234,10 +232,10 @@ var UseScaffoldMethodHook = class {
|
|
|
234
232
|
await executionLog.logExecution({
|
|
235
233
|
filePath,
|
|
236
234
|
operation: "list-scaffold-methods",
|
|
237
|
-
decision:
|
|
235
|
+
decision: _agiflowai_hooks_adapter.DECISION_ALLOW
|
|
238
236
|
});
|
|
239
237
|
return {
|
|
240
|
-
decision:
|
|
238
|
+
decision: _agiflowai_hooks_adapter.DECISION_ALLOW,
|
|
241
239
|
message: "No scaffolding methods are available for this project template. You should write new files directly using the Write tool."
|
|
242
240
|
};
|
|
243
241
|
}
|
|
@@ -245,15 +243,15 @@ var UseScaffoldMethodHook = class {
|
|
|
245
243
|
await executionLog.logExecution({
|
|
246
244
|
filePath,
|
|
247
245
|
operation: "list-scaffold-methods",
|
|
248
|
-
decision:
|
|
246
|
+
decision: _agiflowai_hooks_adapter.DECISION_DENY
|
|
249
247
|
});
|
|
250
248
|
return {
|
|
251
|
-
decision:
|
|
249
|
+
decision: _agiflowai_hooks_adapter.DECISION_DENY,
|
|
252
250
|
message
|
|
253
251
|
};
|
|
254
252
|
} catch (error) {
|
|
255
253
|
return {
|
|
256
|
-
decision:
|
|
254
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
257
255
|
message: `⚠️ Hook error: ${error instanceof Error ? error.message : String(error)}`
|
|
258
256
|
};
|
|
259
257
|
}
|
|
@@ -268,37 +266,37 @@ var UseScaffoldMethodHook = class {
|
|
|
268
266
|
async postToolUse(context) {
|
|
269
267
|
try {
|
|
270
268
|
if (!("tool_name" in context)) return {
|
|
271
|
-
decision:
|
|
269
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
272
270
|
message: "Not a tool use event"
|
|
273
271
|
};
|
|
274
|
-
const executionLog = new
|
|
272
|
+
const executionLog = new _agiflowai_hooks_adapter.ExecutionLogService(context.session_id);
|
|
275
273
|
const filePath = context.tool_input?.file_path;
|
|
276
274
|
if ((context.tool_name === "mcp__one-mcp__use_tool" ? context.tool_input?.toolName : context.tool_name) === "use-scaffold-method") {
|
|
277
275
|
if (context.hook_event_name === "PostToolUse") {
|
|
278
|
-
const scaffoldId
|
|
279
|
-
if (scaffoldId
|
|
276
|
+
const scaffoldId = extractScaffoldId(context.tool_response);
|
|
277
|
+
if (scaffoldId) await processPendingScaffoldLogs(context.session_id, scaffoldId);
|
|
280
278
|
}
|
|
281
279
|
return {
|
|
282
|
-
decision:
|
|
280
|
+
decision: _agiflowai_hooks_adapter.DECISION_ALLOW,
|
|
283
281
|
message: "Scaffold execution logged for progress tracking"
|
|
284
282
|
};
|
|
285
283
|
}
|
|
286
284
|
if (!filePath || context.tool_name !== "Edit" && context.tool_name !== "Write" && context.tool_name !== "Update") return {
|
|
287
|
-
decision:
|
|
285
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
288
286
|
message: "Not a file edit/write operation"
|
|
289
287
|
};
|
|
290
288
|
const lastScaffoldExecution = await getLastScaffoldExecution(executionLog);
|
|
291
289
|
if (!lastScaffoldExecution) return {
|
|
292
|
-
decision:
|
|
290
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
293
291
|
message: "No scaffold execution found"
|
|
294
292
|
};
|
|
295
293
|
const { scaffoldId, generatedFiles, featureName } = lastScaffoldExecution;
|
|
296
294
|
const fulfilledKey = `scaffold-fulfilled-${scaffoldId}`;
|
|
297
295
|
if (await executionLog.hasExecuted({
|
|
298
296
|
filePath: fulfilledKey,
|
|
299
|
-
decision:
|
|
297
|
+
decision: _agiflowai_hooks_adapter.DECISION_ALLOW
|
|
300
298
|
})) return {
|
|
301
|
-
decision:
|
|
299
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
302
300
|
message: "Scaffold already fulfilled"
|
|
303
301
|
};
|
|
304
302
|
const isScaffoldedFile = generatedFiles.includes(filePath);
|
|
@@ -306,11 +304,11 @@ var UseScaffoldMethodHook = class {
|
|
|
306
304
|
const editKey = `scaffold-edit-${scaffoldId}-${filePath}`;
|
|
307
305
|
if (!await executionLog.hasExecuted({
|
|
308
306
|
filePath: editKey,
|
|
309
|
-
decision:
|
|
307
|
+
decision: _agiflowai_hooks_adapter.DECISION_ALLOW
|
|
310
308
|
})) await executionLog.logExecution({
|
|
311
309
|
filePath: editKey,
|
|
312
310
|
operation: "scaffold-file-edit",
|
|
313
|
-
decision:
|
|
311
|
+
decision: _agiflowai_hooks_adapter.DECISION_ALLOW
|
|
314
312
|
});
|
|
315
313
|
}
|
|
316
314
|
const editedFiles = await getEditedScaffoldFiles(executionLog, scaffoldId);
|
|
@@ -320,17 +318,17 @@ var UseScaffoldMethodHook = class {
|
|
|
320
318
|
await executionLog.logExecution({
|
|
321
319
|
filePath: fulfilledKey,
|
|
322
320
|
operation: "scaffold-fulfilled",
|
|
323
|
-
decision:
|
|
321
|
+
decision: _agiflowai_hooks_adapter.DECISION_ALLOW
|
|
324
322
|
});
|
|
325
323
|
return {
|
|
326
|
-
decision:
|
|
324
|
+
decision: _agiflowai_hooks_adapter.DECISION_ALLOW,
|
|
327
325
|
message: `✅ All scaffold files${featureName ? ` for "${featureName}"` : ""} have been implemented! (${totalFiles}/${totalFiles} files completed)`
|
|
328
326
|
};
|
|
329
327
|
}
|
|
330
328
|
if (isScaffoldedFile) {
|
|
331
329
|
const remainingFilesList = remainingFiles.map((f) => ` - ${f}`).join("\n");
|
|
332
330
|
return {
|
|
333
|
-
decision:
|
|
331
|
+
decision: _agiflowai_hooks_adapter.DECISION_ALLOW,
|
|
334
332
|
message: `
|
|
335
333
|
⚠️ **Scaffold Implementation Progress${featureName ? ` for "${featureName}"` : ""}: ${editedFiles.length}/${totalFiles} files completed**
|
|
336
334
|
|
|
@@ -342,12 +340,12 @@ Don't forget to complete the implementation for all scaffolded files!
|
|
|
342
340
|
};
|
|
343
341
|
}
|
|
344
342
|
return {
|
|
345
|
-
decision:
|
|
343
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
346
344
|
message: "Edited file not part of last scaffold execution"
|
|
347
345
|
};
|
|
348
346
|
} catch (error) {
|
|
349
347
|
return {
|
|
350
|
-
decision:
|
|
348
|
+
decision: _agiflowai_hooks_adapter.DECISION_SKIP,
|
|
351
349
|
message: `⚠️ Hook error: ${error instanceof Error ? error.message : String(error)}`
|
|
352
350
|
};
|
|
353
351
|
}
|
|
@@ -358,7 +356,7 @@ Don't forget to complete the implementation for all scaffolded files!
|
|
|
358
356
|
*/
|
|
359
357
|
function extractScaffoldId(toolResult) {
|
|
360
358
|
try {
|
|
361
|
-
if (!toolResult
|
|
359
|
+
if (!toolResult?.content) return null;
|
|
362
360
|
for (const item of toolResult.content) if (item.type === "text" && typeof item.text === "string") {
|
|
363
361
|
const match = item.text.match(/^SCAFFOLD_ID:([a-z0-9]+)$/);
|
|
364
362
|
if (match) return match[1];
|
|
@@ -414,7 +412,7 @@ async function processPendingScaffoldLogs(sessionId, scaffoldId) {
|
|
|
414
412
|
const tempLogFile = node_path.default.join(node_os.default.tmpdir(), `scaffold-mcp-pending-${scaffoldId}.jsonl`);
|
|
415
413
|
try {
|
|
416
414
|
const lines = (await node_fs_promises.default.readFile(tempLogFile, "utf-8")).trim().split("\n").filter(Boolean);
|
|
417
|
-
const executionLog = new
|
|
415
|
+
const executionLog = new _agiflowai_hooks_adapter.ExecutionLogService(sessionId);
|
|
418
416
|
try {
|
|
419
417
|
for (const line of lines) try {
|
|
420
418
|
const parsed = JSON.parse(line);
|
|
@@ -425,7 +423,7 @@ async function processPendingScaffoldLogs(sessionId, scaffoldId) {
|
|
|
425
423
|
await executionLog.logExecution({
|
|
426
424
|
filePath: `scaffold-${parsed.scaffoldId}`,
|
|
427
425
|
operation: "scaffold",
|
|
428
|
-
decision:
|
|
426
|
+
decision: _agiflowai_hooks_adapter.DECISION_ALLOW,
|
|
429
427
|
generatedFiles: parsed.generatedFiles,
|
|
430
428
|
scaffoldId: parsed.scaffoldId,
|
|
431
429
|
projectPath: parsed.projectPath,
|
|
@@ -445,7 +443,6 @@ async function processPendingScaffoldLogs(sessionId, scaffoldId) {
|
|
|
445
443
|
if (error instanceof Error && "code" in error && error.code !== "ENOENT") console.error("Error processing pending scaffold logs:", error);
|
|
446
444
|
}
|
|
447
445
|
}
|
|
448
|
-
|
|
449
446
|
//#endregion
|
|
450
447
|
exports.PhantomCodeCheckHook = PhantomCodeCheckHook;
|
|
451
|
-
exports.UseScaffoldMethodHook = UseScaffoldMethodHook;
|
|
448
|
+
exports.UseScaffoldMethodHook = UseScaffoldMethodHook;
|