@mandujs/mcp 0.9.18 → 0.9.19
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/package.json +1 -1
- package/src/tools/slot.ts +3 -199
package/package.json
CHANGED
package/src/tools/slot.ts
CHANGED
|
@@ -3,12 +3,10 @@ import {
|
|
|
3
3
|
loadManifest,
|
|
4
4
|
validateSlotContent,
|
|
5
5
|
correctSlotContent,
|
|
6
|
-
runSlotCorrection,
|
|
7
6
|
summarizeValidationIssues,
|
|
8
7
|
} from "@mandujs/core";
|
|
9
8
|
import { getProjectPaths, isInsideProject } from "../utils/project.js";
|
|
10
9
|
import path from "path";
|
|
11
|
-
import fs from "fs/promises";
|
|
12
10
|
|
|
13
11
|
export const slotToolDefinitions: Tool[] = [
|
|
14
12
|
{
|
|
@@ -25,40 +23,6 @@ export const slotToolDefinitions: Tool[] = [
|
|
|
25
23
|
required: ["routeId"],
|
|
26
24
|
},
|
|
27
25
|
},
|
|
28
|
-
{
|
|
29
|
-
name: "mandu_write_slot",
|
|
30
|
-
description:
|
|
31
|
-
"Write or update the contents of a slot file with optional auto-correction",
|
|
32
|
-
inputSchema: {
|
|
33
|
-
type: "object",
|
|
34
|
-
properties: {
|
|
35
|
-
routeId: {
|
|
36
|
-
type: "string",
|
|
37
|
-
description: "The route ID whose slot file to write",
|
|
38
|
-
},
|
|
39
|
-
content: {
|
|
40
|
-
type: "string",
|
|
41
|
-
description: "The TypeScript content to write to the slot file",
|
|
42
|
-
},
|
|
43
|
-
autoCorrect: {
|
|
44
|
-
type: "boolean",
|
|
45
|
-
description:
|
|
46
|
-
"If true, automatically fix correctable issues (default: false)",
|
|
47
|
-
},
|
|
48
|
-
maxRetries: {
|
|
49
|
-
type: "number",
|
|
50
|
-
description:
|
|
51
|
-
"Maximum correction attempts when autoCorrect is true (default: 3)",
|
|
52
|
-
},
|
|
53
|
-
validateOnly: {
|
|
54
|
-
type: "boolean",
|
|
55
|
-
description:
|
|
56
|
-
"If true, only validate without writing (default: false)",
|
|
57
|
-
},
|
|
58
|
-
},
|
|
59
|
-
required: ["routeId", "content"],
|
|
60
|
-
},
|
|
61
|
-
},
|
|
62
26
|
{
|
|
63
27
|
name: "mandu_validate_slot",
|
|
64
28
|
description:
|
|
@@ -141,166 +105,6 @@ export function slotTools(projectRoot: string) {
|
|
|
141
105
|
}
|
|
142
106
|
},
|
|
143
107
|
|
|
144
|
-
mandu_write_slot: async (args: Record<string, unknown>) => {
|
|
145
|
-
const {
|
|
146
|
-
routeId,
|
|
147
|
-
content,
|
|
148
|
-
autoCorrect = false,
|
|
149
|
-
maxRetries = 3,
|
|
150
|
-
validateOnly = false,
|
|
151
|
-
} = args as {
|
|
152
|
-
routeId: string;
|
|
153
|
-
content: string;
|
|
154
|
-
autoCorrect?: boolean;
|
|
155
|
-
maxRetries?: number;
|
|
156
|
-
validateOnly?: boolean;
|
|
157
|
-
};
|
|
158
|
-
|
|
159
|
-
// Load manifest to find the route
|
|
160
|
-
const manifestResult = await loadManifest(paths.manifestPath);
|
|
161
|
-
if (!manifestResult.success || !manifestResult.data) {
|
|
162
|
-
return { error: manifestResult.errors };
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
const route = manifestResult.data.routes.find((r) => r.id === routeId);
|
|
166
|
-
if (!route) {
|
|
167
|
-
return { error: `Route not found: ${routeId}` };
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
if (!route.slotModule) {
|
|
171
|
-
return {
|
|
172
|
-
error: `Route '${routeId}' does not have a slotModule defined`,
|
|
173
|
-
tip: "Add slotModule to the route spec first",
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const slotPath = path.join(projectRoot, route.slotModule);
|
|
178
|
-
|
|
179
|
-
// Security check
|
|
180
|
-
if (!isInsideProject(slotPath, projectRoot)) {
|
|
181
|
-
return { error: "Slot path is outside project directory" };
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// 1. 초기 검증
|
|
185
|
-
const initialValidation = validateSlotContent(content);
|
|
186
|
-
|
|
187
|
-
// validateOnly 모드면 검증 결과만 반환
|
|
188
|
-
if (validateOnly) {
|
|
189
|
-
return {
|
|
190
|
-
validateOnly: true,
|
|
191
|
-
valid: initialValidation.valid,
|
|
192
|
-
summary: summarizeValidationIssues(initialValidation.issues),
|
|
193
|
-
issues: initialValidation.issues,
|
|
194
|
-
tip: initialValidation.valid
|
|
195
|
-
? "Content is valid and ready to write"
|
|
196
|
-
: "Fix the issues and try again, or use autoCorrect: true",
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
// 2. autoCorrect 모드
|
|
201
|
-
let finalContent = content;
|
|
202
|
-
let correctionResult = null;
|
|
203
|
-
|
|
204
|
-
if (autoCorrect && !initialValidation.valid) {
|
|
205
|
-
correctionResult = await runSlotCorrection(
|
|
206
|
-
content,
|
|
207
|
-
validateSlotContent,
|
|
208
|
-
maxRetries
|
|
209
|
-
);
|
|
210
|
-
finalContent = correctionResult.finalContent;
|
|
211
|
-
|
|
212
|
-
// 여전히 에러가 있으면 쓰기 거부
|
|
213
|
-
if (!correctionResult.success) {
|
|
214
|
-
const errors = correctionResult.remainingIssues.filter(
|
|
215
|
-
(i) => i.severity === "error"
|
|
216
|
-
);
|
|
217
|
-
if (errors.length > 0) {
|
|
218
|
-
return {
|
|
219
|
-
success: false,
|
|
220
|
-
autoCorrectAttempted: true,
|
|
221
|
-
attempts: correctionResult.attempts,
|
|
222
|
-
appliedFixes: correctionResult.allFixes,
|
|
223
|
-
remainingErrors: errors,
|
|
224
|
-
summary: `${correctionResult.allFixes.length}개 문제 수정, ${errors.length}개 에러 남음`,
|
|
225
|
-
tip: "수동으로 수정이 필요한 에러가 있습니다",
|
|
226
|
-
suggestedContent: finalContent, // 부분적으로 수정된 내용 제공
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
} else if (!autoCorrect && !initialValidation.valid) {
|
|
231
|
-
// autoCorrect 없이 에러가 있으면 경고와 함께 진행 여부 결정
|
|
232
|
-
const errors = initialValidation.issues.filter(
|
|
233
|
-
(i) => i.severity === "error"
|
|
234
|
-
);
|
|
235
|
-
if (errors.length > 0) {
|
|
236
|
-
return {
|
|
237
|
-
success: false,
|
|
238
|
-
valid: false,
|
|
239
|
-
errors,
|
|
240
|
-
summary: summarizeValidationIssues(initialValidation.issues),
|
|
241
|
-
tip: "Use autoCorrect: true to attempt automatic fixes, or fix manually",
|
|
242
|
-
autoFixable: initialValidation.issues
|
|
243
|
-
.filter((i) => i.autoFixable)
|
|
244
|
-
.map((i) => i.code),
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// 3. 파일 쓰기
|
|
250
|
-
try {
|
|
251
|
-
// Ensure directory exists
|
|
252
|
-
const slotDir = path.dirname(slotPath);
|
|
253
|
-
await fs.mkdir(slotDir, { recursive: true });
|
|
254
|
-
|
|
255
|
-
// Check if file exists (for backup/warning)
|
|
256
|
-
const file = Bun.file(slotPath);
|
|
257
|
-
const existed = await file.exists();
|
|
258
|
-
let previousContent: string | null = null;
|
|
259
|
-
|
|
260
|
-
if (existed) {
|
|
261
|
-
previousContent = await file.text();
|
|
262
|
-
}
|
|
263
|
-
|
|
264
|
-
// Write the new content
|
|
265
|
-
await Bun.write(slotPath, finalContent);
|
|
266
|
-
|
|
267
|
-
// 최종 검증
|
|
268
|
-
const finalValidation = validateSlotContent(finalContent);
|
|
269
|
-
|
|
270
|
-
const result: Record<string, unknown> = {
|
|
271
|
-
success: true,
|
|
272
|
-
slotPath: route.slotModule,
|
|
273
|
-
action: existed ? "updated" : "created",
|
|
274
|
-
lineCount: finalContent.split("\n").length,
|
|
275
|
-
previousLineCount: previousContent
|
|
276
|
-
? previousContent.split("\n").length
|
|
277
|
-
: null,
|
|
278
|
-
validation: {
|
|
279
|
-
valid: finalValidation.valid,
|
|
280
|
-
summary: summarizeValidationIssues(finalValidation.issues),
|
|
281
|
-
warnings: finalValidation.issues.filter(
|
|
282
|
-
(i) => i.severity === "warning"
|
|
283
|
-
),
|
|
284
|
-
},
|
|
285
|
-
};
|
|
286
|
-
|
|
287
|
-
// autoCorrect 결과 추가
|
|
288
|
-
if (correctionResult) {
|
|
289
|
-
result.autoCorrection = {
|
|
290
|
-
applied: true,
|
|
291
|
-
attempts: correctionResult.attempts,
|
|
292
|
-
fixes: correctionResult.allFixes,
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
return result;
|
|
297
|
-
} catch (error) {
|
|
298
|
-
return {
|
|
299
|
-
error: `Failed to write slot file: ${error instanceof Error ? error.message : String(error)}`,
|
|
300
|
-
};
|
|
301
|
-
}
|
|
302
|
-
},
|
|
303
|
-
|
|
304
108
|
mandu_validate_slot: async (args: Record<string, unknown>) => {
|
|
305
109
|
const { content } = args as { content: string };
|
|
306
110
|
|
|
@@ -342,10 +146,10 @@ export function slotTools(projectRoot: string) {
|
|
|
342
146
|
})),
|
|
343
147
|
correctionPreview,
|
|
344
148
|
tip: validation.valid
|
|
345
|
-
? "Content is valid"
|
|
149
|
+
? "Content is valid. Use Edit tool to write the slot file."
|
|
346
150
|
: autoFixable.length > 0
|
|
347
|
-
? "
|
|
348
|
-
: "Manual fixes required before writing",
|
|
151
|
+
? "Auto-fixable issues found. Apply corrections and use Edit tool to write."
|
|
152
|
+
: "Manual fixes required before writing. Use Edit tool after fixing.",
|
|
349
153
|
};
|
|
350
154
|
},
|
|
351
155
|
};
|