@mandujs/mcp 0.18.2 → 0.18.4
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/activity-monitor.ts +11 -14
- package/src/server.ts +14 -5
- package/src/tools/ate.ts +132 -51
- package/src/tools/brain.ts +1 -1
- package/src/tools/contract.ts +56 -17
- package/src/tools/generate.ts +18 -4
- package/src/tools/project.ts +92 -44
- package/src/tools/runtime.ts +69 -58
- package/src/tools/slot.ts +21 -7
- package/src/tools/spec.ts +39 -10
- package/src/utils/project.ts +4 -2
package/package.json
CHANGED
package/src/activity-monitor.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import fs from "fs";
|
|
9
9
|
import path from "path";
|
|
10
|
-
import {
|
|
10
|
+
import type { Subprocess } from "bun";
|
|
11
11
|
|
|
12
12
|
const TOOL_ICONS: Record<string, string> = {
|
|
13
13
|
// Spec
|
|
@@ -266,7 +266,7 @@ function writeDefaultConfig(projectRoot: string, config: Required<MonitorConfig>
|
|
|
266
266
|
export class ActivityMonitor {
|
|
267
267
|
private logFile = "";
|
|
268
268
|
private logStream: fs.WriteStream | null = null;
|
|
269
|
-
private tailProcess:
|
|
269
|
+
private tailProcess: Subprocess | null = null;
|
|
270
270
|
private projectRoot: string;
|
|
271
271
|
private config: Required<MonitorConfig>;
|
|
272
272
|
private outputFormat: MonitorOutputFormat;
|
|
@@ -813,9 +813,9 @@ export class ActivityMonitor {
|
|
|
813
813
|
private openTerminal(): void {
|
|
814
814
|
try {
|
|
815
815
|
if (process.platform === "win32") {
|
|
816
|
-
this.tailProcess = spawn(
|
|
817
|
-
"cmd",
|
|
816
|
+
this.tailProcess = Bun.spawn(
|
|
818
817
|
[
|
|
818
|
+
"cmd",
|
|
819
819
|
"/c",
|
|
820
820
|
"start",
|
|
821
821
|
"Mandu Activity Monitor",
|
|
@@ -824,22 +824,19 @@ export class ActivityMonitor {
|
|
|
824
824
|
"-Command",
|
|
825
825
|
`[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; chcp 65001 | Out-Null; Get-Content '${this.logFile}' -Wait -Encoding UTF8`,
|
|
826
826
|
],
|
|
827
|
-
{ cwd: this.projectRoot,
|
|
827
|
+
{ cwd: this.projectRoot, stdio: ["ignore", "ignore", "ignore"] }
|
|
828
828
|
);
|
|
829
829
|
} else if (process.platform === "darwin") {
|
|
830
|
-
this.tailProcess = spawn(
|
|
831
|
-
"osascript",
|
|
832
|
-
["
|
|
833
|
-
{ detached: true, stdio: "ignore" }
|
|
830
|
+
this.tailProcess = Bun.spawn(
|
|
831
|
+
["osascript", "-e", `tell application "Terminal" to do script "tail -f '${this.logFile}'"`],
|
|
832
|
+
{ stdio: ["ignore", "ignore", "ignore"] }
|
|
834
833
|
);
|
|
835
834
|
} else {
|
|
836
|
-
this.tailProcess = spawn(
|
|
837
|
-
"x-terminal-emulator",
|
|
838
|
-
["
|
|
839
|
-
{ cwd: this.projectRoot, detached: true, stdio: "ignore" }
|
|
835
|
+
this.tailProcess = Bun.spawn(
|
|
836
|
+
["x-terminal-emulator", "-e", `tail -f '${this.logFile}'`],
|
|
837
|
+
{ cwd: this.projectRoot, stdio: ["ignore", "ignore", "ignore"] }
|
|
840
838
|
);
|
|
841
839
|
}
|
|
842
|
-
this.tailProcess?.unref();
|
|
843
840
|
} catch {
|
|
844
841
|
// Terminal auto-open failed silently
|
|
845
842
|
}
|
package/src/server.ts
CHANGED
|
@@ -322,7 +322,10 @@ export class ManduMcpServer {
|
|
|
322
322
|
* 리소스 패턴 매칭
|
|
323
323
|
*/
|
|
324
324
|
function matchResourcePattern(pattern: string, uri: string): boolean {
|
|
325
|
-
const regexPattern = pattern
|
|
325
|
+
const regexPattern = pattern
|
|
326
|
+
.split(/\{[^}]+\}/)
|
|
327
|
+
.map(part => part.replace(/[.+*?^${}()|[\]\\]/g, "\\$&"))
|
|
328
|
+
.join("([^/]+)");
|
|
326
329
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
327
330
|
return regex.test(uri);
|
|
328
331
|
}
|
|
@@ -332,10 +335,16 @@ function matchResourcePattern(pattern: string, uri: string): boolean {
|
|
|
332
335
|
*/
|
|
333
336
|
function extractResourceParams(pattern: string, uri: string): Record<string, string> {
|
|
334
337
|
const paramNames: string[] = [];
|
|
335
|
-
const regexPattern = pattern
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
338
|
+
const regexPattern = pattern
|
|
339
|
+
.split(/\{([^}]+)\}/)
|
|
340
|
+
.map((part, index) => {
|
|
341
|
+
if (index % 2 === 1) {
|
|
342
|
+
paramNames.push(part);
|
|
343
|
+
return "([^/]+)";
|
|
344
|
+
}
|
|
345
|
+
return part.replace(/[.+*?^${}()|[\]\\]/g, "\\$&");
|
|
346
|
+
})
|
|
347
|
+
.join("");
|
|
339
348
|
|
|
340
349
|
const regex = new RegExp(`^${regexPattern}$`);
|
|
341
350
|
const match = uri.match(regex);
|
package/src/tools/ate.ts
CHANGED
|
@@ -14,61 +14,110 @@ import {
|
|
|
14
14
|
export const ateToolDefinitions: Tool[] = [
|
|
15
15
|
{
|
|
16
16
|
name: "mandu.ate.extract",
|
|
17
|
-
description:
|
|
17
|
+
description:
|
|
18
|
+
"ATE Step 1 — Extract: Statically analyze the Mandu project's AST to build an interaction graph of routes, slots, contracts, and data flow. " +
|
|
19
|
+
"Identifies all testable interactions without running the server. " +
|
|
20
|
+
"Output is stored in .mandu/ate/extract/ and used by mandu.ate.generate.",
|
|
18
21
|
inputSchema: {
|
|
19
22
|
type: "object",
|
|
20
23
|
properties: {
|
|
21
|
-
repoRoot: { type: "string" },
|
|
22
|
-
tsconfigPath: { type: "string" },
|
|
23
|
-
routeGlobs: {
|
|
24
|
-
|
|
24
|
+
repoRoot: { type: "string", description: "Absolute path to the Mandu project root" },
|
|
25
|
+
tsconfigPath: { type: "string", description: "Path to tsconfig.json (default: tsconfig.json in repoRoot)" },
|
|
26
|
+
routeGlobs: {
|
|
27
|
+
type: "array",
|
|
28
|
+
items: { type: "string" },
|
|
29
|
+
description: "Glob patterns to limit which routes are analyzed (e.g. ['app/api/**', 'app/blog/**']). Omit for all routes.",
|
|
30
|
+
},
|
|
31
|
+
buildSalt: {
|
|
32
|
+
type: "string",
|
|
33
|
+
description: "Cache invalidation salt — change this to force re-extraction even if source hasn't changed",
|
|
34
|
+
},
|
|
25
35
|
},
|
|
26
36
|
required: ["repoRoot"],
|
|
27
37
|
},
|
|
28
38
|
},
|
|
29
39
|
{
|
|
30
40
|
name: "mandu.ate.generate",
|
|
31
|
-
description:
|
|
41
|
+
description:
|
|
42
|
+
"ATE Step 2 — Generate: Create Playwright test scenarios from the interaction graph produced by mandu.ate.extract. " +
|
|
43
|
+
"Oracle level controls assertion depth: " +
|
|
44
|
+
"L0 = no assertions (smoke test only), " +
|
|
45
|
+
"L1 = basic HTTP status checks, " +
|
|
46
|
+
"L2 = contract schema validation (response shape matches Zod contract), " +
|
|
47
|
+
"L3 = full behavioral contract (side effects, state changes, error paths). " +
|
|
48
|
+
"Output: .mandu/ate/tests/*.spec.ts ready to run with Playwright.",
|
|
32
49
|
inputSchema: {
|
|
33
50
|
type: "object",
|
|
34
51
|
properties: {
|
|
35
|
-
repoRoot: { type: "string" },
|
|
36
|
-
oracleLevel: {
|
|
37
|
-
|
|
52
|
+
repoRoot: { type: "string", description: "Absolute path to the Mandu project root" },
|
|
53
|
+
oracleLevel: {
|
|
54
|
+
type: "string",
|
|
55
|
+
enum: ["L0", "L1", "L2", "L3"],
|
|
56
|
+
description: "Assertion depth: L0=smoke, L1=HTTP status, L2=contract schema, L3=full behavioral",
|
|
57
|
+
},
|
|
58
|
+
onlyRoutes: {
|
|
59
|
+
type: "array",
|
|
60
|
+
items: { type: "string" },
|
|
61
|
+
description: "Limit test generation to specific routeIds (e.g. ['api-users', 'blog-slug']). Omit for all routes.",
|
|
62
|
+
},
|
|
38
63
|
},
|
|
39
64
|
required: ["repoRoot"],
|
|
40
65
|
},
|
|
41
66
|
},
|
|
42
67
|
{
|
|
43
68
|
name: "mandu.ate.run",
|
|
44
|
-
description:
|
|
69
|
+
description:
|
|
70
|
+
"ATE Step 3 — Run: Execute the generated Playwright specs against a running Mandu dev server. " +
|
|
71
|
+
"Collects test artifacts (screenshots, traces, results) in .mandu/ate/runs/{runId}/. " +
|
|
72
|
+
"Requires the Mandu dev server to be running (use mandu_dev_start first). " +
|
|
73
|
+
"Returns a runId for use with mandu.ate.report and mandu.ate.heal.",
|
|
45
74
|
inputSchema: {
|
|
46
75
|
type: "object",
|
|
47
76
|
properties: {
|
|
48
|
-
repoRoot: { type: "string" },
|
|
49
|
-
baseURL: {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
77
|
+
repoRoot: { type: "string", description: "Absolute path to the Mandu project root" },
|
|
78
|
+
baseURL: {
|
|
79
|
+
type: "string",
|
|
80
|
+
description: "Dev server URL (default: http://localhost:3333). Must match the running mandu dev server.",
|
|
81
|
+
},
|
|
82
|
+
ci: { type: "boolean", description: "CI mode: stricter timeouts, no interactive prompts" },
|
|
83
|
+
headless: { type: "boolean", description: "Run browsers headlessly (default: true)" },
|
|
84
|
+
browsers: {
|
|
85
|
+
type: "array",
|
|
86
|
+
items: { type: "string", enum: ["chromium", "firefox", "webkit"] },
|
|
87
|
+
description: "Browsers to test against (default: ['chromium'])",
|
|
88
|
+
},
|
|
53
89
|
},
|
|
54
90
|
required: ["repoRoot"],
|
|
55
91
|
},
|
|
56
92
|
},
|
|
57
93
|
{
|
|
58
94
|
name: "mandu.ate.report",
|
|
59
|
-
description:
|
|
95
|
+
description:
|
|
96
|
+
"ATE Step 4 — Report: Generate a test report from run artifacts. " +
|
|
97
|
+
"Produces pass/fail summary, coverage by route, and failure details. " +
|
|
98
|
+
"Use the runId returned by mandu.ate.run. " +
|
|
99
|
+
"If tests failed, follow up with mandu.ate.heal to get fix suggestions.",
|
|
60
100
|
inputSchema: {
|
|
61
101
|
type: "object",
|
|
62
102
|
properties: {
|
|
63
|
-
repoRoot: { type: "string" },
|
|
64
|
-
runId: { type: "string" },
|
|
65
|
-
startedAt: { type: "string" },
|
|
66
|
-
finishedAt: { type: "string" },
|
|
67
|
-
exitCode: { type: "number" },
|
|
68
|
-
oracleLevel: {
|
|
69
|
-
|
|
103
|
+
repoRoot: { type: "string", description: "Absolute path to the Mandu project root" },
|
|
104
|
+
runId: { type: "string", description: "Run ID returned by mandu.ate.run" },
|
|
105
|
+
startedAt: { type: "string", description: "ISO timestamp when run started" },
|
|
106
|
+
finishedAt: { type: "string", description: "ISO timestamp when run finished" },
|
|
107
|
+
exitCode: { type: "number", description: "Playwright process exit code (0=pass, non-zero=fail)" },
|
|
108
|
+
oracleLevel: {
|
|
109
|
+
type: "string",
|
|
110
|
+
enum: ["L0", "L1", "L2", "L3"],
|
|
111
|
+
description: "Oracle level used during generation (for report context)",
|
|
112
|
+
},
|
|
113
|
+
format: {
|
|
114
|
+
type: "string",
|
|
115
|
+
enum: ["json", "html", "both"],
|
|
116
|
+
description: "Report format: json (machine-readable), html (visual), both (default)",
|
|
117
|
+
},
|
|
70
118
|
impact: {
|
|
71
119
|
type: "object",
|
|
120
|
+
description: "Impact analysis context — set if tests were run on a subset of routes via mandu.ate.impact",
|
|
72
121
|
properties: {
|
|
73
122
|
mode: { type: "string", enum: ["full", "subset"] },
|
|
74
123
|
changedFiles: { type: "array", items: { type: "string" } },
|
|
@@ -82,61 +131,89 @@ export const ateToolDefinitions: Tool[] = [
|
|
|
82
131
|
},
|
|
83
132
|
{
|
|
84
133
|
name: "mandu.ate.heal",
|
|
85
|
-
description:
|
|
134
|
+
description:
|
|
135
|
+
"ATE Step 5 — Heal: Analyze test failures from a run and generate safe diff suggestions for fixing the code. " +
|
|
136
|
+
"Classifies failures by root cause (schema mismatch, missing handler, wrong status, selector stale, etc.) " +
|
|
137
|
+
"and produces reviewable diffs — never auto-commits or overwrites files. " +
|
|
138
|
+
"Use mandu.ate.apply_heal to apply a specific suggestion after review. " +
|
|
139
|
+
"Supports rollback via mandu_rollback if applied changes cause regressions.",
|
|
86
140
|
inputSchema: {
|
|
87
141
|
type: "object",
|
|
88
142
|
properties: {
|
|
89
|
-
repoRoot: { type: "string" },
|
|
90
|
-
runId: { type: "string" },
|
|
143
|
+
repoRoot: { type: "string", description: "Absolute path to the Mandu project root" },
|
|
144
|
+
runId: { type: "string", description: "Run ID from mandu.ate.run with failures to analyze" },
|
|
91
145
|
},
|
|
92
146
|
required: ["repoRoot", "runId"],
|
|
93
147
|
},
|
|
94
148
|
},
|
|
95
149
|
{
|
|
96
150
|
name: "mandu.ate.impact",
|
|
97
|
-
description:
|
|
151
|
+
description:
|
|
152
|
+
"ATE Optimization — Impact Analysis: Calculate the minimal subset of routes affected by changed files using git diff. " +
|
|
153
|
+
"Avoids running the full test suite when only part of the codebase changed. " +
|
|
154
|
+
"Returns selectedRoutes to pass to mandu.ate.generate (onlyRoutes) or mandu.ate.run. " +
|
|
155
|
+
"Typical use: run after `git commit` to test only affected routes in CI.",
|
|
98
156
|
inputSchema: {
|
|
99
157
|
type: "object",
|
|
100
158
|
properties: {
|
|
101
|
-
repoRoot: { type: "string" },
|
|
102
|
-
base: { type: "string" },
|
|
103
|
-
head: { type: "string" },
|
|
159
|
+
repoRoot: { type: "string", description: "Absolute path to the Mandu project root" },
|
|
160
|
+
base: { type: "string", description: "Git base ref for diff (default: HEAD~1 or main branch)" },
|
|
161
|
+
head: { type: "string", description: "Git head ref for diff (default: current working tree)" },
|
|
104
162
|
},
|
|
105
163
|
required: ["repoRoot"],
|
|
106
164
|
},
|
|
107
165
|
},
|
|
108
166
|
{
|
|
109
167
|
name: "mandu.ate.auto_pipeline",
|
|
110
|
-
description:
|
|
168
|
+
description:
|
|
169
|
+
"ATE Full Pipeline — Run the complete ATE cycle in one call: " +
|
|
170
|
+
"Extract AST → Generate Playwright specs → Run tests → Create report → Suggest heals. " +
|
|
171
|
+
"Recommended for: initial setup, scheduled CI runs, and full regression testing. " +
|
|
172
|
+
"For incremental development, prefer individual steps (extract → generate → run → report → heal). " +
|
|
173
|
+
"Set useImpactAnalysis=true to automatically limit tests to changed routes.",
|
|
111
174
|
inputSchema: {
|
|
112
175
|
type: "object",
|
|
113
176
|
properties: {
|
|
114
|
-
repoRoot: { type: "string" },
|
|
115
|
-
baseURL: { type: "string" },
|
|
116
|
-
oracleLevel: {
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
177
|
+
repoRoot: { type: "string", description: "Absolute path to the Mandu project root" },
|
|
178
|
+
baseURL: { type: "string", description: "Dev server URL (default: http://localhost:3333)" },
|
|
179
|
+
oracleLevel: {
|
|
180
|
+
type: "string",
|
|
181
|
+
enum: ["L0", "L1", "L2", "L3"],
|
|
182
|
+
description: "Assertion depth: L0=smoke, L1=HTTP status, L2=contract schema, L3=full behavioral",
|
|
183
|
+
},
|
|
184
|
+
ci: { type: "boolean", description: "CI mode: stricter timeouts" },
|
|
185
|
+
useImpactAnalysis: {
|
|
186
|
+
type: "boolean",
|
|
187
|
+
description: "Run impact analysis first and only test changed routes (faster in CI)",
|
|
188
|
+
},
|
|
189
|
+
base: { type: "string", description: "Git base ref for impact analysis" },
|
|
190
|
+
head: { type: "string", description: "Git head ref for impact analysis" },
|
|
191
|
+
autoHeal: {
|
|
192
|
+
type: "boolean",
|
|
193
|
+
description: "Automatically run heal analysis after failures (produces diff suggestions, never auto-applies)",
|
|
194
|
+
},
|
|
195
|
+
tsconfigPath: { type: "string", description: "Path to tsconfig.json" },
|
|
196
|
+
routeGlobs: { type: "array", items: { type: "string" }, description: "Limit extraction to specific route patterns" },
|
|
197
|
+
buildSalt: { type: "string", description: "Cache invalidation salt for extraction" },
|
|
125
198
|
},
|
|
126
199
|
required: ["repoRoot"],
|
|
127
200
|
},
|
|
128
201
|
},
|
|
129
202
|
{
|
|
130
203
|
name: "mandu.ate.feedback",
|
|
131
|
-
description:
|
|
204
|
+
description:
|
|
205
|
+
"ATE Feedback — Evaluate heal suggestions from a failed run and classify which fixes are safe to auto-apply. " +
|
|
206
|
+
"Safe-to-auto-apply: selector-map updates (CSS selector changes). " +
|
|
207
|
+
"Requires human review: contract schema changes, handler logic, route restructuring. " +
|
|
208
|
+
"Returns priority ranking of suggestions to guide review order.",
|
|
132
209
|
inputSchema: {
|
|
133
210
|
type: "object",
|
|
134
211
|
properties: {
|
|
135
|
-
repoRoot: { type: "string", description: "
|
|
136
|
-
runId: { type: "string", description: "
|
|
212
|
+
repoRoot: { type: "string", description: "Absolute path to the Mandu project root" },
|
|
213
|
+
runId: { type: "string", description: "Run ID with heal suggestions to evaluate" },
|
|
137
214
|
autoApply: {
|
|
138
215
|
type: "boolean",
|
|
139
|
-
description: "
|
|
216
|
+
description: "If true, auto-apply only selector-map changes (CSS selectors) — other changes always require review",
|
|
140
217
|
},
|
|
141
218
|
},
|
|
142
219
|
required: ["repoRoot", "runId"],
|
|
@@ -144,19 +221,23 @@ export const ateToolDefinitions: Tool[] = [
|
|
|
144
221
|
},
|
|
145
222
|
{
|
|
146
223
|
name: "mandu.ate.apply_heal",
|
|
147
|
-
description:
|
|
224
|
+
description:
|
|
225
|
+
"ATE Apply — Apply a specific heal suggestion diff to the codebase. " +
|
|
226
|
+
"Always creates a backup snapshot first (use mandu_rollback to undo). " +
|
|
227
|
+
"Run mandu.ate.feedback first to get the healIndex and confirm the fix is safe. " +
|
|
228
|
+
"After applying, re-run mandu.ate.run to verify the fix resolved the failure.",
|
|
148
229
|
inputSchema: {
|
|
149
230
|
type: "object",
|
|
150
231
|
properties: {
|
|
151
|
-
repoRoot: { type: "string", description: "
|
|
152
|
-
runId: { type: "string", description: "
|
|
232
|
+
repoRoot: { type: "string", description: "Absolute path to the Mandu project root" },
|
|
233
|
+
runId: { type: "string", description: "Run ID containing the heal suggestion to apply" },
|
|
153
234
|
healIndex: {
|
|
154
235
|
type: "number",
|
|
155
|
-
description: "
|
|
236
|
+
description: "0-based index of the heal suggestion to apply (from mandu.ate.heal or mandu.ate.feedback results)",
|
|
156
237
|
},
|
|
157
238
|
createBackup: {
|
|
158
239
|
type: "boolean",
|
|
159
|
-
description: "
|
|
240
|
+
description: "Create a snapshot before applying (default: true, strongly recommended — enables mandu_rollback)",
|
|
160
241
|
},
|
|
161
242
|
},
|
|
162
243
|
required: ["repoRoot", "runId", "healIndex"],
|
package/src/tools/brain.ts
CHANGED
|
@@ -26,7 +26,7 @@ import {
|
|
|
26
26
|
generateJsonStatus,
|
|
27
27
|
initializeArchitectureAnalyzer,
|
|
28
28
|
getArchitectureAnalyzer,
|
|
29
|
-
} from "
|
|
29
|
+
} from "@mandujs/core";
|
|
30
30
|
import { getProjectPaths } from "../utils/project.js";
|
|
31
31
|
|
|
32
32
|
export const brainToolDefinitions: Tool[] = [
|
package/src/tools/contract.ts
CHANGED
|
@@ -16,7 +16,15 @@ import fs from "fs/promises";
|
|
|
16
16
|
export const contractToolDefinitions: Tool[] = [
|
|
17
17
|
{
|
|
18
18
|
name: "mandu_list_contracts",
|
|
19
|
-
description:
|
|
19
|
+
description:
|
|
20
|
+
"List all routes that have a contract module defined. " +
|
|
21
|
+
"In Mandu, a 'contract' is a Zod-based schema file (spec/contracts/{routeId}.contract.ts) that defines " +
|
|
22
|
+
"the request/response shape for an API route. Contracts enable: " +
|
|
23
|
+
"(1) automatic input validation and sanitization (strip/strict/passthrough normalize modes), " +
|
|
24
|
+
"(2) TypeScript type inference for slot handlers, " +
|
|
25
|
+
"(3) OpenAPI 3.0 spec generation via mandu_generate_openapi, " +
|
|
26
|
+
"(4) ATE L2 (schema validation) and L3 (full behavioral) test generation. " +
|
|
27
|
+
"Also returns a list of API routes that are missing contracts.",
|
|
20
28
|
inputSchema: {
|
|
21
29
|
type: "object",
|
|
22
30
|
properties: {},
|
|
@@ -25,13 +33,17 @@ export const contractToolDefinitions: Tool[] = [
|
|
|
25
33
|
},
|
|
26
34
|
{
|
|
27
35
|
name: "mandu_get_contract",
|
|
28
|
-
description:
|
|
36
|
+
description:
|
|
37
|
+
"Get the full TypeScript source of a contract file for a specific route. " +
|
|
38
|
+
"Returns the raw content of spec/contracts/{routeId}.contract.ts, " +
|
|
39
|
+
"which contains Zod schemas for each HTTP method's request body/query params and response shape. " +
|
|
40
|
+
"If the route has no contract, returns a suggestion to create one with mandu_create_contract.",
|
|
29
41
|
inputSchema: {
|
|
30
42
|
type: "object",
|
|
31
43
|
properties: {
|
|
32
44
|
routeId: {
|
|
33
45
|
type: "string",
|
|
34
|
-
description: "The route ID to retrieve contract for",
|
|
46
|
+
description: "The route ID to retrieve the contract for",
|
|
35
47
|
},
|
|
36
48
|
},
|
|
37
49
|
required: ["routeId"],
|
|
@@ -39,22 +51,27 @@ export const contractToolDefinitions: Tool[] = [
|
|
|
39
51
|
},
|
|
40
52
|
{
|
|
41
53
|
name: "mandu_create_contract",
|
|
42
|
-
description:
|
|
54
|
+
description:
|
|
55
|
+
"Create a new contract file for a route and link it in the manifest. " +
|
|
56
|
+
"Generates spec/contracts/{routeId}.contract.ts with Zod schema stubs for each HTTP method. " +
|
|
57
|
+
"Template includes: request schema (body for POST/PUT/PATCH, query for GET/DELETE) and response schema. " +
|
|
58
|
+
"After creation: edit the Zod schemas to match your actual API shape, " +
|
|
59
|
+
"then run mandu_generate to regenerate typed handlers with validation.",
|
|
43
60
|
inputSchema: {
|
|
44
61
|
type: "object",
|
|
45
62
|
properties: {
|
|
46
63
|
routeId: {
|
|
47
64
|
type: "string",
|
|
48
|
-
description: "The route ID to create contract for",
|
|
65
|
+
description: "The route ID to create a contract for",
|
|
49
66
|
},
|
|
50
67
|
description: {
|
|
51
68
|
type: "string",
|
|
52
|
-
description: "API description
|
|
69
|
+
description: "Human-readable API description added as a comment in the contract file",
|
|
53
70
|
},
|
|
54
71
|
methods: {
|
|
55
72
|
type: "array",
|
|
56
73
|
items: { type: "string" },
|
|
57
|
-
description: "HTTP methods to
|
|
74
|
+
description: "HTTP methods to generate schemas for (default: route's declared methods or ['GET', 'POST'])",
|
|
58
75
|
},
|
|
59
76
|
},
|
|
60
77
|
required: ["routeId"],
|
|
@@ -62,7 +79,11 @@ export const contractToolDefinitions: Tool[] = [
|
|
|
62
79
|
},
|
|
63
80
|
{
|
|
64
81
|
name: "mandu_update_route_contract",
|
|
65
|
-
description:
|
|
82
|
+
description:
|
|
83
|
+
"Update the manifest to link an existing contract file to a route. " +
|
|
84
|
+
"Use this when the contract file already exists but the manifest's contractModule path needs updating, " +
|
|
85
|
+
"or when moving a contract file to a new location. " +
|
|
86
|
+
"Does not modify the contract file itself — only updates the manifest reference and lock file.",
|
|
66
87
|
inputSchema: {
|
|
67
88
|
type: "object",
|
|
68
89
|
properties: {
|
|
@@ -72,7 +93,7 @@ export const contractToolDefinitions: Tool[] = [
|
|
|
72
93
|
},
|
|
73
94
|
contractModule: {
|
|
74
95
|
type: "string",
|
|
75
|
-
description: "
|
|
96
|
+
description: "Relative path to the contract file from project root (e.g., spec/contracts/users.contract.ts)",
|
|
76
97
|
},
|
|
77
98
|
},
|
|
78
99
|
required: ["routeId", "contractModule"],
|
|
@@ -80,7 +101,12 @@ export const contractToolDefinitions: Tool[] = [
|
|
|
80
101
|
},
|
|
81
102
|
{
|
|
82
103
|
name: "mandu_validate_contracts",
|
|
83
|
-
description:
|
|
104
|
+
description:
|
|
105
|
+
"Validate all contracts against their linked slot implementations for consistency. " +
|
|
106
|
+
"Checks that every HTTP method defined in a contract has a matching handler in the slot, " +
|
|
107
|
+
"response types are compatible, and no orphaned contracts exist. " +
|
|
108
|
+
"Run this after modifying contracts or slots, or before running ATE tests to catch mismatches early. " +
|
|
109
|
+
"Returns a list of violations with file locations, descriptions, and fix suggestions.",
|
|
84
110
|
inputSchema: {
|
|
85
111
|
type: "object",
|
|
86
112
|
properties: {},
|
|
@@ -89,18 +115,27 @@ export const contractToolDefinitions: Tool[] = [
|
|
|
89
115
|
},
|
|
90
116
|
{
|
|
91
117
|
name: "mandu_sync_contract_slot",
|
|
92
|
-
description:
|
|
118
|
+
description:
|
|
119
|
+
"Detect and generate code to resolve HTTP method mismatches between a contract and its slot. " +
|
|
120
|
+
"'contract-to-slot': finds HTTP methods defined in the contract but missing from the slot — " +
|
|
121
|
+
"generates handler stub code to add to the slot file. " +
|
|
122
|
+
"'slot-to-contract': finds slot handlers not documented in the contract — " +
|
|
123
|
+
"generates Zod schema stubs to add to the contract. " +
|
|
124
|
+
"Returns generated code snippets to review — does NOT auto-write files. " +
|
|
125
|
+
"Copy the output and use the Edit tool to apply the changes.",
|
|
93
126
|
inputSchema: {
|
|
94
127
|
type: "object",
|
|
95
128
|
properties: {
|
|
96
129
|
routeId: {
|
|
97
130
|
type: "string",
|
|
98
|
-
description: "The route ID to sync",
|
|
131
|
+
description: "The route ID to sync (must have both contractModule and slotModule)",
|
|
99
132
|
},
|
|
100
133
|
direction: {
|
|
101
134
|
type: "string",
|
|
102
135
|
enum: ["contract-to-slot", "slot-to-contract"],
|
|
103
|
-
description:
|
|
136
|
+
description:
|
|
137
|
+
"'contract-to-slot': generate slot handler stubs for undocumented contract methods. " +
|
|
138
|
+
"'slot-to-contract': generate contract schema stubs for undocumented slot handlers.",
|
|
104
139
|
},
|
|
105
140
|
},
|
|
106
141
|
required: ["routeId", "direction"],
|
|
@@ -108,21 +143,25 @@ export const contractToolDefinitions: Tool[] = [
|
|
|
108
143
|
},
|
|
109
144
|
{
|
|
110
145
|
name: "mandu_generate_openapi",
|
|
111
|
-
description:
|
|
146
|
+
description:
|
|
147
|
+
"Generate an OpenAPI 3.0 specification JSON file from all routes with contract modules. " +
|
|
148
|
+
"Only routes with a defined contractModule are included — add contracts with mandu_create_contract first. " +
|
|
149
|
+
"Output is written to openapi.json (or a custom path). " +
|
|
150
|
+
"The generated spec can be served with Swagger UI, Redoc, or imported into any OpenAPI-compatible tooling.",
|
|
112
151
|
inputSchema: {
|
|
113
152
|
type: "object",
|
|
114
153
|
properties: {
|
|
115
154
|
output: {
|
|
116
155
|
type: "string",
|
|
117
|
-
description: "Output file path (default: openapi.json)",
|
|
156
|
+
description: "Output file path relative to project root (default: openapi.json)",
|
|
118
157
|
},
|
|
119
158
|
title: {
|
|
120
159
|
type: "string",
|
|
121
|
-
description: "API title (default: Mandu API)",
|
|
160
|
+
description: "API title shown in the spec (default: 'Mandu API')",
|
|
122
161
|
},
|
|
123
162
|
version: {
|
|
124
163
|
type: "string",
|
|
125
|
-
description: "API version (default: from manifest)",
|
|
164
|
+
description: "API version string (default: taken from the manifest version)",
|
|
126
165
|
},
|
|
127
166
|
},
|
|
128
167
|
required: [],
|
package/src/tools/generate.ts
CHANGED
|
@@ -8,17 +8,27 @@ export const generateToolDefinitions: Tool[] = [
|
|
|
8
8
|
{
|
|
9
9
|
name: "mandu_generate",
|
|
10
10
|
description:
|
|
11
|
-
"Generate
|
|
11
|
+
"Generate all Mandu framework artifacts from the current routes manifest and resource schemas. " +
|
|
12
|
+
"Runs two generation steps: " +
|
|
13
|
+
"(1) Route generation: for every route in .mandu/routes.manifest.json, creates " +
|
|
14
|
+
"a server-side handler in .mandu/generated/server/{routeId}.route.ts and " +
|
|
15
|
+
"a web component in .mandu/generated/web/{routeId}.route.tsx. " +
|
|
16
|
+
"These generated files wire up slots and contracts automatically — do NOT edit them directly. " +
|
|
17
|
+
"Instead, edit source files in app/ (route definition) or spec/ (slots, contracts). " +
|
|
18
|
+
"(2) Resource generation (resources=true, default): scans spec/resources/{name}/schema.ts " +
|
|
19
|
+
"and generates CRUD boilerplate (repository, service, handlers) for each declared resource. " +
|
|
20
|
+
"Run this after adding routes, modifying slot/contract files, or changing resource schemas. " +
|
|
21
|
+
"Use dryRun=true to preview what would be created or overwritten without writing any files.",
|
|
12
22
|
inputSchema: {
|
|
13
23
|
type: "object",
|
|
14
24
|
properties: {
|
|
15
25
|
dryRun: {
|
|
16
26
|
type: "boolean",
|
|
17
|
-
description: "
|
|
27
|
+
description: "Preview what would be generated without writing files (default: false)",
|
|
18
28
|
},
|
|
19
29
|
resources: {
|
|
20
30
|
type: "boolean",
|
|
21
|
-
description: "Include resource artifact generation (default: true)",
|
|
31
|
+
description: "Include resource artifact generation from spec/resources/ (default: true)",
|
|
22
32
|
},
|
|
23
33
|
},
|
|
24
34
|
required: [],
|
|
@@ -26,7 +36,11 @@ export const generateToolDefinitions: Tool[] = [
|
|
|
26
36
|
},
|
|
27
37
|
{
|
|
28
38
|
name: "mandu_generate_status",
|
|
29
|
-
description:
|
|
39
|
+
description:
|
|
40
|
+
"Show the current state of all generated artifacts from .mandu/generated.map.json. " +
|
|
41
|
+
"Returns: generation timestamp, source spec version, total file count, " +
|
|
42
|
+
"and a list of generated files per route with their kinds (server handler, web component, slot stub). " +
|
|
43
|
+
"If no generated.map.json exists, prompts to run mandu_generate first.",
|
|
30
44
|
inputSchema: {
|
|
31
45
|
type: "object",
|
|
32
46
|
properties: {},
|