@mandujs/mcp 0.19.3 β 0.19.5
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 +48 -11
- package/package.json +44 -44
- package/src/activity-monitor.ts +24 -10
- package/src/new-resources.ts +145 -119
package/README.md
CHANGED
|
@@ -34,18 +34,34 @@ Add to your MCP configuration (`.mcp.json` or `.claude.json`):
|
|
|
34
34
|
"mcpServers": {
|
|
35
35
|
"mandu": {
|
|
36
36
|
"command": "bunx",
|
|
37
|
-
"args": ["
|
|
37
|
+
"args": ["mandu-mcp"],
|
|
38
38
|
"cwd": "/path/to/your/project"
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
+
> **Note**: Use `mandu-mcp` (not `@mandujs/mcp`) to avoid conflicts with Python's `mcp` CLI on PATH (#174).
|
|
45
|
+
|
|
44
46
|
### Direct Execution
|
|
45
47
|
|
|
46
48
|
```bash
|
|
47
49
|
cd /path/to/project
|
|
48
|
-
bunx
|
|
50
|
+
bunx mandu-mcp
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### Tool Profiles
|
|
54
|
+
|
|
55
|
+
Filter available tools via the `MANDU_MCP_PROFILE` env var:
|
|
56
|
+
|
|
57
|
+
| Profile | Tools | Use Case |
|
|
58
|
+
|---------|-------|----------|
|
|
59
|
+
| `minimal` | ~15 | Read-only operations, safe for autonomous agents |
|
|
60
|
+
| `standard` | ~50 | Default β most common operations |
|
|
61
|
+
| `full` | 85+ | All tools including destructive operations |
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
MANDU_MCP_PROFILE=minimal bunx mandu-mcp
|
|
49
65
|
```
|
|
50
66
|
|
|
51
67
|
### Global Mode
|
|
@@ -64,7 +80,7 @@ bunx @mandujs/mcp --root /path/to/project
|
|
|
64
80
|
|
|
65
81
|
---
|
|
66
82
|
|
|
67
|
-
## Tools (
|
|
83
|
+
## Tools (85+)
|
|
68
84
|
|
|
69
85
|
### Spec Management
|
|
70
86
|
|
|
@@ -167,7 +183,7 @@ bunx @mandujs/mcp --root /path/to/project
|
|
|
167
183
|
| `mandu_list_changes` | View change history |
|
|
168
184
|
| `mandu_prune_history` | Clean old snapshots |
|
|
169
185
|
|
|
170
|
-
### ATE (Automation Test Engine)
|
|
186
|
+
### ATE (Automation Test Engine) β 9 tools
|
|
171
187
|
|
|
172
188
|
| Tool | Description |
|
|
173
189
|
|------|-------------|
|
|
@@ -177,19 +193,40 @@ bunx @mandujs/mcp --root /path/to/project
|
|
|
177
193
|
| `mandu.ate.report` | Generate test summary report |
|
|
178
194
|
| `mandu.ate.heal` | Auto-suggest fixes for failed tests |
|
|
179
195
|
| `mandu.ate.impact` | Compute affected routes (subset testing) |
|
|
196
|
+
| `mandu.ate.auto_pipeline` | Run full pipeline (extract β generate β run β report β heal) |
|
|
197
|
+
| `mandu.ate.feedback` | Analyze failures with 7-category classification |
|
|
198
|
+
| `mandu.ate.apply_heal` | Apply heal diffs safely (with backup) |
|
|
199
|
+
|
|
200
|
+
### Test Selection (Phase 5) β 3 tools π
|
|
201
|
+
|
|
202
|
+
| Tool | Description |
|
|
203
|
+
|------|-------------|
|
|
204
|
+
| `mandu.test.smart` | Smart test selection from git diff with priority scoring |
|
|
205
|
+
| `mandu.test.coverage` | Detect coverage gaps in interaction graph |
|
|
206
|
+
| `mandu.test.precommit` | Pre-commit hook: should we test before committing? |
|
|
207
|
+
|
|
208
|
+
### Composite β 7 tools
|
|
209
|
+
|
|
210
|
+
| Tool | Description |
|
|
211
|
+
|------|-------------|
|
|
212
|
+
| `mandu.feature.create` | Scaffold full feature (route + contract + slot + island) |
|
|
213
|
+
| `mandu.diagnose` | Multi-aspect project health check |
|
|
214
|
+
| `mandu.island.add` | Add interactive island to route |
|
|
215
|
+
| `mandu.middleware.add` | Add middleware to route |
|
|
216
|
+
| `mandu.test.route` | Quick smoke test for a route |
|
|
217
|
+
| `mandu.deploy.check` | Pre-deploy production readiness check |
|
|
218
|
+
| `mandu.cache.manage` | Manage ISR/SWR cache (list, invalidate, stats) |
|
|
180
219
|
|
|
181
220
|
---
|
|
182
221
|
|
|
183
|
-
## Resources
|
|
222
|
+
## Resources (4)
|
|
184
223
|
|
|
185
224
|
| URI | Description |
|
|
186
225
|
|-----|-------------|
|
|
187
|
-
| `mandu://
|
|
188
|
-
| `mandu://
|
|
189
|
-
| `mandu://
|
|
190
|
-
| `mandu://
|
|
191
|
-
| `mandu://watch/warnings` | Recent architecture violation warnings |
|
|
192
|
-
| `mandu://watch/status` | Watcher status (active, uptime, count) |
|
|
226
|
+
| `mandu://routes` | Current routes manifest |
|
|
227
|
+
| `mandu://config` | Parsed `mandu.config.ts` settings |
|
|
228
|
+
| `mandu://errors` | Recent build and runtime errors |
|
|
229
|
+
| `mandu://activity` | **NEW**: Recent observability events + 5-minute stats from EventBus |
|
|
193
230
|
|
|
194
231
|
---
|
|
195
232
|
|
package/package.json
CHANGED
|
@@ -1,44 +1,44 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@mandujs/mcp",
|
|
3
|
-
"version": "0.19.
|
|
4
|
-
"description": "Mandu MCP Server - Agent-native interface for Mandu framework operations",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./src/index.ts",
|
|
7
|
-
"bin": {
|
|
8
|
-
"mandu-mcp": "./src/index.ts",
|
|
9
|
-
"mandujs-mcp": "./src/index.ts",
|
|
10
|
-
"mcp": "./src/index.ts"
|
|
11
|
-
},
|
|
12
|
-
"exports": {
|
|
13
|
-
".": "./src/index.ts"
|
|
14
|
-
},
|
|
15
|
-
"files": [
|
|
16
|
-
"src/**/*"
|
|
17
|
-
],
|
|
18
|
-
"keywords": [
|
|
19
|
-
"mandu",
|
|
20
|
-
"mcp",
|
|
21
|
-
"model-context-protocol",
|
|
22
|
-
"ai",
|
|
23
|
-
"agent",
|
|
24
|
-
"code-generation"
|
|
25
|
-
],
|
|
26
|
-
"repository": {
|
|
27
|
-
"type": "git",
|
|
28
|
-
"url": "https://github.com/konamgil/mandu.git",
|
|
29
|
-
"directory": "packages/mcp"
|
|
30
|
-
},
|
|
31
|
-
"author": "konamgil",
|
|
32
|
-
"license": "MPL-2.0",
|
|
33
|
-
"publishConfig": {
|
|
34
|
-
"access": "public"
|
|
35
|
-
},
|
|
36
|
-
"dependencies": {
|
|
37
|
-
"@mandujs/core": "^0.
|
|
38
|
-
"@mandujs/ate": "^0.18.0",
|
|
39
|
-
"@modelcontextprotocol/sdk": "^1.25.3"
|
|
40
|
-
},
|
|
41
|
-
"engines": {
|
|
42
|
-
"bun": ">=1.0.0"
|
|
43
|
-
}
|
|
44
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@mandujs/mcp",
|
|
3
|
+
"version": "0.19.5",
|
|
4
|
+
"description": "Mandu MCP Server - Agent-native interface for Mandu framework operations",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./src/index.ts",
|
|
7
|
+
"bin": {
|
|
8
|
+
"mandu-mcp": "./src/index.ts",
|
|
9
|
+
"mandujs-mcp": "./src/index.ts",
|
|
10
|
+
"mcp": "./src/index.ts"
|
|
11
|
+
},
|
|
12
|
+
"exports": {
|
|
13
|
+
".": "./src/index.ts"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"src/**/*"
|
|
17
|
+
],
|
|
18
|
+
"keywords": [
|
|
19
|
+
"mandu",
|
|
20
|
+
"mcp",
|
|
21
|
+
"model-context-protocol",
|
|
22
|
+
"ai",
|
|
23
|
+
"agent",
|
|
24
|
+
"code-generation"
|
|
25
|
+
],
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "https://github.com/konamgil/mandu.git",
|
|
29
|
+
"directory": "packages/mcp"
|
|
30
|
+
},
|
|
31
|
+
"author": "konamgil",
|
|
32
|
+
"license": "MPL-2.0",
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@mandujs/core": "^0.21.0",
|
|
38
|
+
"@mandujs/ate": "^0.18.0",
|
|
39
|
+
"@modelcontextprotocol/sdk": "^1.25.3"
|
|
40
|
+
},
|
|
41
|
+
"engines": {
|
|
42
|
+
"bun": ">=1.0.0"
|
|
43
|
+
}
|
|
44
|
+
}
|
package/src/activity-monitor.ts
CHANGED
|
@@ -277,6 +277,10 @@ export class ActivityMonitor {
|
|
|
277
277
|
private summaryTimer: NodeJS.Timeout | null = null;
|
|
278
278
|
private summaryCounts = { total: 0, info: 0, warn: 0, error: 0 };
|
|
279
279
|
private lastToolArgs = new Map<string, Record<string, unknown> | null>();
|
|
280
|
+
// Phase 1-3: λꡬ νΈμΆ μμ μκ° μΆμ (duration κ³μ°μ©)
|
|
281
|
+
private toolStartTimes = new Map<string, number>();
|
|
282
|
+
// Phase 5-1: μμ΄μ νΈ μΈμ
μλ³ (MCP ν΄λΌμ΄μΈνΈλ³ μΆμ )
|
|
283
|
+
public sessionId: string = crypto.randomUUID();
|
|
280
284
|
|
|
281
285
|
constructor(projectRoot: string) {
|
|
282
286
|
this.projectRoot = projectRoot;
|
|
@@ -380,17 +384,23 @@ export class ActivityMonitor {
|
|
|
380
384
|
fingerprint: `tool:error:${name}:${argsStr}`,
|
|
381
385
|
data: { tool: name, tag, args, argsSummary: argsStr, error },
|
|
382
386
|
});
|
|
383
|
-
// Phase 1-3: MCP λꡬ μλ¬ β EventBus
|
|
387
|
+
// Phase 1-3: MCP λꡬ μλ¬ β EventBus (sessionId + duration ν¬ν¨)
|
|
388
|
+
const startTime = this.toolStartTimes.get(name);
|
|
389
|
+
this.toolStartTimes.delete(name);
|
|
384
390
|
eventBus.emit({
|
|
385
391
|
type: "mcp",
|
|
386
392
|
severity: "error",
|
|
387
393
|
source: "mcp",
|
|
388
394
|
message: `${name} β ${error}`,
|
|
389
|
-
|
|
395
|
+
duration: startTime ? Date.now() - startTime : undefined,
|
|
396
|
+
data: { tool: name, args, error, sessionId: this.sessionId },
|
|
390
397
|
});
|
|
391
398
|
return;
|
|
392
399
|
}
|
|
393
400
|
|
|
401
|
+
// Phase 1-3: λꡬ νΈμΆ μμ μκ° κΈ°λ‘ (logResultμμ duration κ³μ°)
|
|
402
|
+
this.toolStartTimes.set(name, Date.now());
|
|
403
|
+
|
|
394
404
|
this.enqueue({
|
|
395
405
|
ts: new Date().toISOString(),
|
|
396
406
|
type: "tool.call",
|
|
@@ -398,14 +408,6 @@ export class ActivityMonitor {
|
|
|
398
408
|
source: "tool",
|
|
399
409
|
data: { tool: name, tag, args, argsSummary: argsStr },
|
|
400
410
|
});
|
|
401
|
-
// Phase 1-3: MCP λꡬ νΈμΆ β EventBus
|
|
402
|
-
eventBus.emit({
|
|
403
|
-
type: "mcp",
|
|
404
|
-
severity: "info",
|
|
405
|
-
source: "mcp",
|
|
406
|
-
message: `${name} β
`,
|
|
407
|
-
data: { tool: name, args },
|
|
408
|
-
});
|
|
409
411
|
}
|
|
410
412
|
|
|
411
413
|
/**
|
|
@@ -419,6 +421,18 @@ export class ActivityMonitor {
|
|
|
419
421
|
const summary = summarizeResult(result);
|
|
420
422
|
const tag = TOOL_ICONS[name] || name.replace("mandu_", "").toUpperCase();
|
|
421
423
|
|
|
424
|
+
// Phase 1-3: λꡬ μλ£ μ duration κ³μ° λ° EventBus emit (Phase 5-1: sessionId ν¬ν¨)
|
|
425
|
+
const startTime = this.toolStartTimes.get(name);
|
|
426
|
+
this.toolStartTimes.delete(name);
|
|
427
|
+
eventBus.emit({
|
|
428
|
+
type: "mcp",
|
|
429
|
+
severity: "info",
|
|
430
|
+
source: "mcp",
|
|
431
|
+
message: `${name} β
`,
|
|
432
|
+
duration: startTime ? Date.now() - startTime : undefined,
|
|
433
|
+
data: { tool: name, args: lastArgs, sessionId: this.sessionId },
|
|
434
|
+
});
|
|
435
|
+
|
|
422
436
|
if (summary) {
|
|
423
437
|
this.enqueue({
|
|
424
438
|
ts: new Date().toISOString(),
|
package/src/new-resources.ts
CHANGED
|
@@ -1,119 +1,145 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* MCP Resources for Mandu Framework
|
|
3
|
-
*
|
|
4
|
-
* Project state data exposed via the MCP resource protocol.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { Resource } from "@modelcontextprotocol/sdk/types.js";
|
|
8
|
-
import path from "path";
|
|
9
|
-
import { readConfig, readJsonFile } from "./utils/project.js";
|
|
10
|
-
import { loadManduConfig, loadManifest } from "@mandujs/core";
|
|
11
|
-
import {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
1
|
+
/**
|
|
2
|
+
* MCP Resources for Mandu Framework
|
|
3
|
+
*
|
|
4
|
+
* Project state data exposed via the MCP resource protocol.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { Resource } from "@modelcontextprotocol/sdk/types.js";
|
|
8
|
+
import path from "path";
|
|
9
|
+
import { readConfig, readJsonFile } from "./utils/project.js";
|
|
10
|
+
import { loadManduConfig, loadManifest } from "@mandujs/core";
|
|
11
|
+
import { eventBus } from "@mandujs/core/observability";
|
|
12
|
+
import { getDevServerState } from "./tools/project.js";
|
|
13
|
+
|
|
14
|
+
export const manduResourceDefinitions: Resource[] = [
|
|
15
|
+
{
|
|
16
|
+
uri: "mandu://routes",
|
|
17
|
+
name: "Route Manifest",
|
|
18
|
+
description: "Current project route manifest (JSON)",
|
|
19
|
+
mimeType: "application/json",
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
uri: "mandu://config",
|
|
23
|
+
name: "Mandu Config",
|
|
24
|
+
description: "Parsed mandu.config.ts settings",
|
|
25
|
+
mimeType: "application/json",
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
uri: "mandu://errors",
|
|
29
|
+
name: "Recent Errors",
|
|
30
|
+
description: "Recent build and runtime errors",
|
|
31
|
+
mimeType: "application/json",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
uri: "mandu://activity",
|
|
35
|
+
name: "Recent Activity",
|
|
36
|
+
description: "Recent observability events (HTTP, MCP, Guard) from EventBus + 5-minute stats",
|
|
37
|
+
mimeType: "application/json",
|
|
38
|
+
},
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
type ResourceReadResult = { uri: string; mimeType: string; text: string };
|
|
42
|
+
type ResourceHandler = () => Promise<ResourceReadResult>;
|
|
43
|
+
|
|
44
|
+
function jsonResult(uri: string, data: unknown): ResourceReadResult {
|
|
45
|
+
return { uri, mimeType: "application/json", text: JSON.stringify(data, null, 2) };
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function manduResourceHandlers(projectRoot: string): Record<string, ResourceHandler> {
|
|
49
|
+
const manifestPath = path.join(projectRoot, ".mandu", "routes.manifest.json");
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
"mandu://routes": async () => {
|
|
53
|
+
const result = await loadManifest(manifestPath);
|
|
54
|
+
if (!result.success || !result.data) {
|
|
55
|
+
return jsonResult("mandu://routes", {
|
|
56
|
+
error: "Failed to load route manifest",
|
|
57
|
+
details: result.errors,
|
|
58
|
+
hint: "Run 'mandu generate' or 'mandu dev' to create the manifest.",
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
return jsonResult("mandu://routes", {
|
|
62
|
+
version: result.data.version,
|
|
63
|
+
routeCount: result.data.routes.length,
|
|
64
|
+
routes: result.data.routes.map((r) => ({
|
|
65
|
+
id: r.id, pattern: r.pattern, kind: r.kind, module: r.module,
|
|
66
|
+
slotModule: r.slotModule ?? null, clientModule: r.clientModule ?? null,
|
|
67
|
+
})),
|
|
68
|
+
});
|
|
69
|
+
},
|
|
70
|
+
|
|
71
|
+
"mandu://config": async () => {
|
|
72
|
+
try {
|
|
73
|
+
const config = await loadManduConfig(projectRoot);
|
|
74
|
+
return jsonResult("mandu://config", {
|
|
75
|
+
server: config.server ?? {},
|
|
76
|
+
guard: config.guard ?? {},
|
|
77
|
+
build: config.build ?? {},
|
|
78
|
+
dev: config.dev ?? {},
|
|
79
|
+
fsRoutes: config.fsRoutes ?? {},
|
|
80
|
+
seo: config.seo ?? {},
|
|
81
|
+
});
|
|
82
|
+
} catch {
|
|
83
|
+
const raw = await readConfig(projectRoot);
|
|
84
|
+
return jsonResult("mandu://config", raw ?? {
|
|
85
|
+
error: "No mandu.config.ts/js/json found",
|
|
86
|
+
hint: "Create a mandu.config.ts in the project root.",
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
"mandu://activity": async () => {
|
|
92
|
+
// Phase 5-3: AI μμ΄μ νΈκ° EventBus νλμ μ§μ μ‘°ν κ°λ₯
|
|
93
|
+
const recent = eventBus.getRecent(20);
|
|
94
|
+
const stats = eventBus.getStats(5 * 60 * 1000); // last 5 minutes
|
|
95
|
+
return jsonResult("mandu://activity", {
|
|
96
|
+
recent: recent.map((e) => ({
|
|
97
|
+
ts: new Date(e.timestamp).toISOString(),
|
|
98
|
+
type: e.type,
|
|
99
|
+
severity: e.severity,
|
|
100
|
+
source: e.source,
|
|
101
|
+
message: e.message,
|
|
102
|
+
duration: e.duration,
|
|
103
|
+
correlationId: e.correlationId,
|
|
104
|
+
})),
|
|
105
|
+
stats,
|
|
106
|
+
windowMs: 5 * 60 * 1000,
|
|
107
|
+
});
|
|
108
|
+
},
|
|
109
|
+
|
|
110
|
+
"mandu://errors": async () => {
|
|
111
|
+
const errors: unknown[] = [];
|
|
112
|
+
|
|
113
|
+
// Try Kitchen DevTools error log from running dev server
|
|
114
|
+
let port: number | undefined;
|
|
115
|
+
const serverState = getDevServerState();
|
|
116
|
+
if (serverState) {
|
|
117
|
+
for (const line of serverState.output) {
|
|
118
|
+
const m = line.match(/https?:\/\/localhost:(\d+)/);
|
|
119
|
+
if (m) port = parseInt(m[1], 10);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (port) {
|
|
123
|
+
try {
|
|
124
|
+
const res = await fetch(`http://localhost:${port}/__kitchen/api/errors`);
|
|
125
|
+
if (res.ok) {
|
|
126
|
+
const body = (await res.json()) as { errors: unknown[] };
|
|
127
|
+
if (body.errors?.length) errors.push(...body.errors);
|
|
128
|
+
}
|
|
129
|
+
} catch { /* dev server not reachable */ }
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Read local error log file
|
|
133
|
+
const loggedErrors = await readJsonFile<unknown[]>(
|
|
134
|
+
path.join(projectRoot, ".mandu", "errors.json"),
|
|
135
|
+
);
|
|
136
|
+
if (Array.isArray(loggedErrors)) errors.push(...loggedErrors);
|
|
137
|
+
|
|
138
|
+
return jsonResult("mandu://errors", {
|
|
139
|
+
count: errors.length,
|
|
140
|
+
errors,
|
|
141
|
+
source: port ? "kitchen+log" : "log",
|
|
142
|
+
});
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|