@mandujs/mcp 0.9.17 → 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 +2 -2
- package/src/activity-monitor.ts +231 -231
- package/src/server.ts +3 -0
- package/src/tools/index.ts +1 -0
- package/src/tools/runtime.ts +497 -0
- package/src/tools/slot.ts +3 -199
- package/src/utils/withWarnings.ts +83 -83
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mandujs/mcp",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.19",
|
|
4
4
|
"description": "Mandu MCP Server - Agent-native interface for Mandu framework operations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/index.ts",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"access": "public"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@mandujs/core": "^0.9.
|
|
35
|
+
"@mandujs/core": "^0.9.25",
|
|
36
36
|
"@modelcontextprotocol/sdk": "^1.25.3"
|
|
37
37
|
},
|
|
38
38
|
"engines": {
|
package/src/activity-monitor.ts
CHANGED
|
@@ -1,231 +1,231 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mandu Activity Monitor
|
|
3
|
-
*
|
|
4
|
-
* Real-time terminal dashboard for MCP server activity.
|
|
5
|
-
* Opens automatically when the MCP server starts.
|
|
6
|
-
* Shows all tool calls, watch events, errors, and agent behavior.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import fs from "fs";
|
|
10
|
-
import path from "path";
|
|
11
|
-
import { spawn, type ChildProcess } from "child_process";
|
|
12
|
-
|
|
13
|
-
const TOOL_ICONS: Record<string, string> = {
|
|
14
|
-
// Spec
|
|
15
|
-
mandu_list_routes: "SPEC",
|
|
16
|
-
mandu_get_route: "SPEC",
|
|
17
|
-
mandu_add_route: "SPEC+",
|
|
18
|
-
mandu_update_route: "SPEC~",
|
|
19
|
-
mandu_delete_route: "SPEC-",
|
|
20
|
-
mandu_validate_spec: "SPEC?",
|
|
21
|
-
// Generate
|
|
22
|
-
mandu_generate: "GEN",
|
|
23
|
-
mandu_generate_status: "GEN?",
|
|
24
|
-
// Guard
|
|
25
|
-
mandu_guard_check: "GUARD",
|
|
26
|
-
// Slot
|
|
27
|
-
mandu_read_slot: "SLOT",
|
|
28
|
-
mandu_write_slot: "SLOT~",
|
|
29
|
-
mandu_validate_slot: "SLOT?",
|
|
30
|
-
// Contract
|
|
31
|
-
mandu_list_contracts: "CONTRACT",
|
|
32
|
-
mandu_get_contract: "CONTRACT",
|
|
33
|
-
mandu_create_contract: "CONTRACT+",
|
|
34
|
-
mandu_validate_contracts: "CONTRACT?",
|
|
35
|
-
mandu_sync_contract_slot: "SYNC",
|
|
36
|
-
mandu_generate_openapi: "OPENAPI",
|
|
37
|
-
mandu_update_route_contract: "CONTRACT~",
|
|
38
|
-
// Transaction
|
|
39
|
-
mandu_begin: "TX-BEGIN",
|
|
40
|
-
mandu_commit: "TX-COMMIT",
|
|
41
|
-
mandu_rollback: "TX-ROLLBACK",
|
|
42
|
-
mandu_tx_status: "TX?",
|
|
43
|
-
// History
|
|
44
|
-
mandu_list_history: "HISTORY",
|
|
45
|
-
mandu_get_snapshot: "SNAPSHOT",
|
|
46
|
-
mandu_prune_history: "PRUNE",
|
|
47
|
-
// Brain
|
|
48
|
-
mandu_doctor: "DOCTOR",
|
|
49
|
-
mandu_watch_start: "WATCH+",
|
|
50
|
-
mandu_watch_status: "WATCH?",
|
|
51
|
-
mandu_watch_stop: "WATCH-",
|
|
52
|
-
mandu_check_location: "ARCH?",
|
|
53
|
-
mandu_check_import: "IMPORT?",
|
|
54
|
-
mandu_get_architecture: "ARCH",
|
|
55
|
-
// Build
|
|
56
|
-
mandu_build: "BUILD",
|
|
57
|
-
mandu_build_status: "BUILD?",
|
|
58
|
-
mandu_list_islands: "ISLAND",
|
|
59
|
-
mandu_set_hydration: "HYDRA~",
|
|
60
|
-
mandu_add_client_slot: "CLIENT+",
|
|
61
|
-
// Error
|
|
62
|
-
mandu_analyze_error: "ERROR",
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
function getTime(): string {
|
|
66
|
-
return new Date().toLocaleTimeString("ko-KR", { hour12: false });
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function summarizeArgs(args: Record<string, unknown> | null | undefined): string {
|
|
70
|
-
if (!args || Object.keys(args).length === 0) return "";
|
|
71
|
-
const entries = Object.entries(args)
|
|
72
|
-
.filter(([_, v]) => v !== undefined && v !== null)
|
|
73
|
-
.map(([k, v]) => {
|
|
74
|
-
const val = typeof v === "string"
|
|
75
|
-
? (v.length > 40 ? v.slice(0, 40) + "..." : v)
|
|
76
|
-
: JSON.stringify(v);
|
|
77
|
-
return `${k}=${val}`;
|
|
78
|
-
});
|
|
79
|
-
return entries.length > 0 ? ` (${entries.join(", ")})` : "";
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
function summarizeResult(result: unknown): string {
|
|
83
|
-
if (!result || typeof result !== "object") return "";
|
|
84
|
-
const obj = result as Record<string, unknown>;
|
|
85
|
-
|
|
86
|
-
// Common patterns
|
|
87
|
-
if (obj.error) return ` >> ERROR: ${obj.error}`;
|
|
88
|
-
if (obj.success === true) return obj.message ? ` >> ${obj.message}` : " >> OK";
|
|
89
|
-
if (obj.success === false) return ` >> FAILED: ${obj.message || "unknown"}`;
|
|
90
|
-
if (Array.isArray(obj.routes)) return ` >> ${obj.routes.length} routes`;
|
|
91
|
-
if (obj.passed === true) return obj.message ? ` >> ${obj.message}` : " >> PASSED";
|
|
92
|
-
if (obj.passed === false) return ` >> FAILED (${(obj.violations as unknown[])?.length || 0} violations)`;
|
|
93
|
-
if (obj.valid === true) return obj.message ? ` >> ${obj.message}` : " >> VALID";
|
|
94
|
-
if (obj.valid === false) return ` >> INVALID (${(obj.violations as unknown[])?.length || 0} violations)`;
|
|
95
|
-
if (obj.generated) return " >> Generated";
|
|
96
|
-
if (obj.status) return ` >> ${JSON.stringify(obj.status).slice(0, 60)}`;
|
|
97
|
-
|
|
98
|
-
return "";
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export class ActivityMonitor {
|
|
102
|
-
private logFile: string;
|
|
103
|
-
private logStream: fs.WriteStream | null = null;
|
|
104
|
-
private tailProcess: ChildProcess | null = null;
|
|
105
|
-
private projectRoot: string;
|
|
106
|
-
private callCount = 0;
|
|
107
|
-
|
|
108
|
-
constructor(projectRoot: string) {
|
|
109
|
-
this.projectRoot = projectRoot;
|
|
110
|
-
const manduDir = path.join(projectRoot, ".mandu");
|
|
111
|
-
if (!fs.existsSync(manduDir)) {
|
|
112
|
-
fs.mkdirSync(manduDir, { recursive: true });
|
|
113
|
-
}
|
|
114
|
-
this.logFile = path.join(manduDir, "activity.log");
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
start(): void {
|
|
118
|
-
// Create/overwrite log file
|
|
119
|
-
this.logStream = fs.createWriteStream(this.logFile, { flags: "w" });
|
|
120
|
-
|
|
121
|
-
const time = getTime();
|
|
122
|
-
const header =
|
|
123
|
-
`\n` +
|
|
124
|
-
` ╔══════════════════════════════════════════════╗\n` +
|
|
125
|
-
` ║ MANDU MCP Activity Monitor ║\n` +
|
|
126
|
-
` ║ ║\n` +
|
|
127
|
-
` ║ ${time} ║\n` +
|
|
128
|
-
` ║ ${this.projectRoot.slice(-40).padEnd(40)} ║\n` +
|
|
129
|
-
` ╚══════════════════════════════════════════════╝\n\n`;
|
|
130
|
-
|
|
131
|
-
this.logStream.write(header);
|
|
132
|
-
|
|
133
|
-
// Auto-open terminal
|
|
134
|
-
this.openTerminal();
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
stop(): void {
|
|
138
|
-
if (this.tailProcess) {
|
|
139
|
-
this.tailProcess.kill();
|
|
140
|
-
this.tailProcess = null;
|
|
141
|
-
}
|
|
142
|
-
if (this.logStream) {
|
|
143
|
-
this.logStream.end();
|
|
144
|
-
this.logStream = null;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/**
|
|
149
|
-
* Log a tool call (invocation)
|
|
150
|
-
*/
|
|
151
|
-
logTool(
|
|
152
|
-
name: string,
|
|
153
|
-
args?: Record<string, unknown> | null,
|
|
154
|
-
_result?: unknown,
|
|
155
|
-
error?: string,
|
|
156
|
-
): void {
|
|
157
|
-
this.callCount++;
|
|
158
|
-
const time = getTime();
|
|
159
|
-
const tag = TOOL_ICONS[name] || name.replace("mandu_", "").toUpperCase();
|
|
160
|
-
const argsStr = summarizeArgs(args);
|
|
161
|
-
|
|
162
|
-
let line: string;
|
|
163
|
-
if (error) {
|
|
164
|
-
line = `${time} ✗ [${tag}]${argsStr}\n ERROR: ${error}\n`;
|
|
165
|
-
} else {
|
|
166
|
-
line = `${time} → [${tag}]${argsStr}\n`;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
this.write(line);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
/**
|
|
173
|
-
* Log a tool result
|
|
174
|
-
*/
|
|
175
|
-
logResult(name: string, result: unknown): void {
|
|
176
|
-
const time = getTime();
|
|
177
|
-
const tag = TOOL_ICONS[name] || name.replace("mandu_", "").toUpperCase();
|
|
178
|
-
const summary = summarizeResult(result);
|
|
179
|
-
|
|
180
|
-
if (summary) {
|
|
181
|
-
this.write(`${time} ✓ [${tag}]${summary}\n`);
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
/**
|
|
186
|
-
* Log a watch event (called from watcher)
|
|
187
|
-
*/
|
|
188
|
-
logWatch(level: string, ruleId: string, file: string, message: string): void {
|
|
189
|
-
const time = getTime();
|
|
190
|
-
const icon = level === "info" ? "ℹ" : "⚠";
|
|
191
|
-
this.write(`${time} ${icon} [WATCH:${ruleId}] ${file}\n ${message}\n`);
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/**
|
|
195
|
-
* Log a custom event
|
|
196
|
-
*/
|
|
197
|
-
logEvent(category: string, message: string): void {
|
|
198
|
-
const time = getTime();
|
|
199
|
-
this.write(`${time} [${category}] ${message}\n`);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
private write(text: string): void {
|
|
203
|
-
if (this.logStream) {
|
|
204
|
-
this.logStream.write(text);
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
private openTerminal(): void {
|
|
209
|
-
try {
|
|
210
|
-
if (process.platform === "win32") {
|
|
211
|
-
this.tailProcess = spawn("cmd", [
|
|
212
|
-
"/c", "start",
|
|
213
|
-
"Mandu Activity Monitor",
|
|
214
|
-
"powershell", "-NoExit", "-Command",
|
|
215
|
-
`[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; chcp 65001 | Out-Null; Get-Content '${this.logFile}' -Wait -Encoding UTF8`,
|
|
216
|
-
], { cwd: this.projectRoot, detached: true, stdio: "ignore" });
|
|
217
|
-
} else if (process.platform === "darwin") {
|
|
218
|
-
this.tailProcess = spawn("osascript", [
|
|
219
|
-
"-e", `tell application "Terminal" to do script "tail -f '${this.logFile}'"`,
|
|
220
|
-
], { detached: true, stdio: "ignore" });
|
|
221
|
-
} else {
|
|
222
|
-
this.tailProcess = spawn("x-terminal-emulator", [
|
|
223
|
-
"-e", `tail -f '${this.logFile}'`,
|
|
224
|
-
], { cwd: this.projectRoot, detached: true, stdio: "ignore" });
|
|
225
|
-
}
|
|
226
|
-
this.tailProcess?.unref();
|
|
227
|
-
} catch {
|
|
228
|
-
// Terminal auto-open failed silently
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Mandu Activity Monitor
|
|
3
|
+
*
|
|
4
|
+
* Real-time terminal dashboard for MCP server activity.
|
|
5
|
+
* Opens automatically when the MCP server starts.
|
|
6
|
+
* Shows all tool calls, watch events, errors, and agent behavior.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import fs from "fs";
|
|
10
|
+
import path from "path";
|
|
11
|
+
import { spawn, type ChildProcess } from "child_process";
|
|
12
|
+
|
|
13
|
+
const TOOL_ICONS: Record<string, string> = {
|
|
14
|
+
// Spec
|
|
15
|
+
mandu_list_routes: "SPEC",
|
|
16
|
+
mandu_get_route: "SPEC",
|
|
17
|
+
mandu_add_route: "SPEC+",
|
|
18
|
+
mandu_update_route: "SPEC~",
|
|
19
|
+
mandu_delete_route: "SPEC-",
|
|
20
|
+
mandu_validate_spec: "SPEC?",
|
|
21
|
+
// Generate
|
|
22
|
+
mandu_generate: "GEN",
|
|
23
|
+
mandu_generate_status: "GEN?",
|
|
24
|
+
// Guard
|
|
25
|
+
mandu_guard_check: "GUARD",
|
|
26
|
+
// Slot
|
|
27
|
+
mandu_read_slot: "SLOT",
|
|
28
|
+
mandu_write_slot: "SLOT~",
|
|
29
|
+
mandu_validate_slot: "SLOT?",
|
|
30
|
+
// Contract
|
|
31
|
+
mandu_list_contracts: "CONTRACT",
|
|
32
|
+
mandu_get_contract: "CONTRACT",
|
|
33
|
+
mandu_create_contract: "CONTRACT+",
|
|
34
|
+
mandu_validate_contracts: "CONTRACT?",
|
|
35
|
+
mandu_sync_contract_slot: "SYNC",
|
|
36
|
+
mandu_generate_openapi: "OPENAPI",
|
|
37
|
+
mandu_update_route_contract: "CONTRACT~",
|
|
38
|
+
// Transaction
|
|
39
|
+
mandu_begin: "TX-BEGIN",
|
|
40
|
+
mandu_commit: "TX-COMMIT",
|
|
41
|
+
mandu_rollback: "TX-ROLLBACK",
|
|
42
|
+
mandu_tx_status: "TX?",
|
|
43
|
+
// History
|
|
44
|
+
mandu_list_history: "HISTORY",
|
|
45
|
+
mandu_get_snapshot: "SNAPSHOT",
|
|
46
|
+
mandu_prune_history: "PRUNE",
|
|
47
|
+
// Brain
|
|
48
|
+
mandu_doctor: "DOCTOR",
|
|
49
|
+
mandu_watch_start: "WATCH+",
|
|
50
|
+
mandu_watch_status: "WATCH?",
|
|
51
|
+
mandu_watch_stop: "WATCH-",
|
|
52
|
+
mandu_check_location: "ARCH?",
|
|
53
|
+
mandu_check_import: "IMPORT?",
|
|
54
|
+
mandu_get_architecture: "ARCH",
|
|
55
|
+
// Build
|
|
56
|
+
mandu_build: "BUILD",
|
|
57
|
+
mandu_build_status: "BUILD?",
|
|
58
|
+
mandu_list_islands: "ISLAND",
|
|
59
|
+
mandu_set_hydration: "HYDRA~",
|
|
60
|
+
mandu_add_client_slot: "CLIENT+",
|
|
61
|
+
// Error
|
|
62
|
+
mandu_analyze_error: "ERROR",
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
function getTime(): string {
|
|
66
|
+
return new Date().toLocaleTimeString("ko-KR", { hour12: false });
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function summarizeArgs(args: Record<string, unknown> | null | undefined): string {
|
|
70
|
+
if (!args || Object.keys(args).length === 0) return "";
|
|
71
|
+
const entries = Object.entries(args)
|
|
72
|
+
.filter(([_, v]) => v !== undefined && v !== null)
|
|
73
|
+
.map(([k, v]) => {
|
|
74
|
+
const val = typeof v === "string"
|
|
75
|
+
? (v.length > 40 ? v.slice(0, 40) + "..." : v)
|
|
76
|
+
: JSON.stringify(v);
|
|
77
|
+
return `${k}=${val}`;
|
|
78
|
+
});
|
|
79
|
+
return entries.length > 0 ? ` (${entries.join(", ")})` : "";
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function summarizeResult(result: unknown): string {
|
|
83
|
+
if (!result || typeof result !== "object") return "";
|
|
84
|
+
const obj = result as Record<string, unknown>;
|
|
85
|
+
|
|
86
|
+
// Common patterns
|
|
87
|
+
if (obj.error) return ` >> ERROR: ${obj.error}`;
|
|
88
|
+
if (obj.success === true) return obj.message ? ` >> ${obj.message}` : " >> OK";
|
|
89
|
+
if (obj.success === false) return ` >> FAILED: ${obj.message || "unknown"}`;
|
|
90
|
+
if (Array.isArray(obj.routes)) return ` >> ${obj.routes.length} routes`;
|
|
91
|
+
if (obj.passed === true) return obj.message ? ` >> ${obj.message}` : " >> PASSED";
|
|
92
|
+
if (obj.passed === false) return ` >> FAILED (${(obj.violations as unknown[])?.length || 0} violations)`;
|
|
93
|
+
if (obj.valid === true) return obj.message ? ` >> ${obj.message}` : " >> VALID";
|
|
94
|
+
if (obj.valid === false) return ` >> INVALID (${(obj.violations as unknown[])?.length || 0} violations)`;
|
|
95
|
+
if (obj.generated) return " >> Generated";
|
|
96
|
+
if (obj.status) return ` >> ${JSON.stringify(obj.status).slice(0, 60)}`;
|
|
97
|
+
|
|
98
|
+
return "";
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export class ActivityMonitor {
|
|
102
|
+
private logFile: string;
|
|
103
|
+
private logStream: fs.WriteStream | null = null;
|
|
104
|
+
private tailProcess: ChildProcess | null = null;
|
|
105
|
+
private projectRoot: string;
|
|
106
|
+
private callCount = 0;
|
|
107
|
+
|
|
108
|
+
constructor(projectRoot: string) {
|
|
109
|
+
this.projectRoot = projectRoot;
|
|
110
|
+
const manduDir = path.join(projectRoot, ".mandu");
|
|
111
|
+
if (!fs.existsSync(manduDir)) {
|
|
112
|
+
fs.mkdirSync(manduDir, { recursive: true });
|
|
113
|
+
}
|
|
114
|
+
this.logFile = path.join(manduDir, "activity.log");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
start(): void {
|
|
118
|
+
// Create/overwrite log file
|
|
119
|
+
this.logStream = fs.createWriteStream(this.logFile, { flags: "w" });
|
|
120
|
+
|
|
121
|
+
const time = getTime();
|
|
122
|
+
const header =
|
|
123
|
+
`\n` +
|
|
124
|
+
` ╔══════════════════════════════════════════════╗\n` +
|
|
125
|
+
` ║ MANDU MCP Activity Monitor ║\n` +
|
|
126
|
+
` ║ ║\n` +
|
|
127
|
+
` ║ ${time} ║\n` +
|
|
128
|
+
` ║ ${this.projectRoot.slice(-40).padEnd(40)} ║\n` +
|
|
129
|
+
` ╚══════════════════════════════════════════════╝\n\n`;
|
|
130
|
+
|
|
131
|
+
this.logStream.write(header);
|
|
132
|
+
|
|
133
|
+
// Auto-open terminal
|
|
134
|
+
this.openTerminal();
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
stop(): void {
|
|
138
|
+
if (this.tailProcess) {
|
|
139
|
+
this.tailProcess.kill();
|
|
140
|
+
this.tailProcess = null;
|
|
141
|
+
}
|
|
142
|
+
if (this.logStream) {
|
|
143
|
+
this.logStream.end();
|
|
144
|
+
this.logStream = null;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Log a tool call (invocation)
|
|
150
|
+
*/
|
|
151
|
+
logTool(
|
|
152
|
+
name: string,
|
|
153
|
+
args?: Record<string, unknown> | null,
|
|
154
|
+
_result?: unknown,
|
|
155
|
+
error?: string,
|
|
156
|
+
): void {
|
|
157
|
+
this.callCount++;
|
|
158
|
+
const time = getTime();
|
|
159
|
+
const tag = TOOL_ICONS[name] || name.replace("mandu_", "").toUpperCase();
|
|
160
|
+
const argsStr = summarizeArgs(args);
|
|
161
|
+
|
|
162
|
+
let line: string;
|
|
163
|
+
if (error) {
|
|
164
|
+
line = `${time} ✗ [${tag}]${argsStr}\n ERROR: ${error}\n`;
|
|
165
|
+
} else {
|
|
166
|
+
line = `${time} → [${tag}]${argsStr}\n`;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
this.write(line);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Log a tool result
|
|
174
|
+
*/
|
|
175
|
+
logResult(name: string, result: unknown): void {
|
|
176
|
+
const time = getTime();
|
|
177
|
+
const tag = TOOL_ICONS[name] || name.replace("mandu_", "").toUpperCase();
|
|
178
|
+
const summary = summarizeResult(result);
|
|
179
|
+
|
|
180
|
+
if (summary) {
|
|
181
|
+
this.write(`${time} ✓ [${tag}]${summary}\n`);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Log a watch event (called from watcher)
|
|
187
|
+
*/
|
|
188
|
+
logWatch(level: string, ruleId: string, file: string, message: string): void {
|
|
189
|
+
const time = getTime();
|
|
190
|
+
const icon = level === "info" ? "ℹ" : "⚠";
|
|
191
|
+
this.write(`${time} ${icon} [WATCH:${ruleId}] ${file}\n ${message}\n`);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Log a custom event
|
|
196
|
+
*/
|
|
197
|
+
logEvent(category: string, message: string): void {
|
|
198
|
+
const time = getTime();
|
|
199
|
+
this.write(`${time} [${category}] ${message}\n`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
private write(text: string): void {
|
|
203
|
+
if (this.logStream) {
|
|
204
|
+
this.logStream.write(text);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
private openTerminal(): void {
|
|
209
|
+
try {
|
|
210
|
+
if (process.platform === "win32") {
|
|
211
|
+
this.tailProcess = spawn("cmd", [
|
|
212
|
+
"/c", "start",
|
|
213
|
+
"Mandu Activity Monitor",
|
|
214
|
+
"powershell", "-NoExit", "-Command",
|
|
215
|
+
`[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; chcp 65001 | Out-Null; Get-Content '${this.logFile}' -Wait -Encoding UTF8`,
|
|
216
|
+
], { cwd: this.projectRoot, detached: true, stdio: "ignore" });
|
|
217
|
+
} else if (process.platform === "darwin") {
|
|
218
|
+
this.tailProcess = spawn("osascript", [
|
|
219
|
+
"-e", `tell application "Terminal" to do script "tail -f '${this.logFile}'"`,
|
|
220
|
+
], { detached: true, stdio: "ignore" });
|
|
221
|
+
} else {
|
|
222
|
+
this.tailProcess = spawn("x-terminal-emulator", [
|
|
223
|
+
"-e", `tail -f '${this.logFile}'`,
|
|
224
|
+
], { cwd: this.projectRoot, detached: true, stdio: "ignore" });
|
|
225
|
+
}
|
|
226
|
+
this.tailProcess?.unref();
|
|
227
|
+
} catch {
|
|
228
|
+
// Terminal auto-open failed silently
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
package/src/server.ts
CHANGED
|
@@ -18,6 +18,7 @@ import { slotTools, slotToolDefinitions } from "./tools/slot.js";
|
|
|
18
18
|
import { hydrationTools, hydrationToolDefinitions } from "./tools/hydration.js";
|
|
19
19
|
import { contractTools, contractToolDefinitions } from "./tools/contract.js";
|
|
20
20
|
import { brainTools, brainToolDefinitions } from "./tools/brain.js";
|
|
21
|
+
import { runtimeTools, runtimeToolDefinitions } from "./tools/runtime.js";
|
|
21
22
|
import { resourceHandlers, resourceDefinitions } from "./resources/handlers.js";
|
|
22
23
|
import { findProjectRoot } from "./utils/project.js";
|
|
23
24
|
import { applyWarningInjection } from "./utils/withWarnings.js";
|
|
@@ -61,6 +62,7 @@ export class ManduMcpServer {
|
|
|
61
62
|
...hydrationToolDefinitions,
|
|
62
63
|
...contractToolDefinitions,
|
|
63
64
|
...brainToolDefinitions,
|
|
65
|
+
...runtimeToolDefinitions,
|
|
64
66
|
];
|
|
65
67
|
}
|
|
66
68
|
|
|
@@ -75,6 +77,7 @@ export class ManduMcpServer {
|
|
|
75
77
|
...hydrationTools(this.projectRoot),
|
|
76
78
|
...contractTools(this.projectRoot),
|
|
77
79
|
...brainTools(this.projectRoot, this.server, this.monitor),
|
|
80
|
+
...runtimeTools(this.projectRoot),
|
|
78
81
|
};
|
|
79
82
|
|
|
80
83
|
return applyWarningInjection(handlers);
|
package/src/tools/index.ts
CHANGED
|
@@ -7,3 +7,4 @@ export { slotTools, slotToolDefinitions } from "./slot.js";
|
|
|
7
7
|
export { hydrationTools, hydrationToolDefinitions } from "./hydration.js";
|
|
8
8
|
export { contractTools, contractToolDefinitions } from "./contract.js";
|
|
9
9
|
export { brainTools, brainToolDefinitions } from "./brain.js";
|
|
10
|
+
export { runtimeTools, runtimeToolDefinitions } from "./runtime.js";
|