@mandujs/core 0.53.0 → 0.53.2
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 +38 -2
- package/src/a11y/run-audit.ts +6 -6
- package/src/brain/adapters/oauth-flow.ts +1 -1
- package/src/brain/architecture/analyzer.ts +0 -2
- package/src/brain/credentials.ts +2 -2
- package/src/bundler/__tests__/build-runner.ts +13 -1
- package/src/bundler/__tests__/extended-watch.test.ts +3 -2
- package/src/bundler/__tests__/fast-refresh.test.ts +10 -12
- package/src/bundler/build.test.ts +30 -33
- package/src/bundler/build.ts +56 -27
- package/src/bundler/dev.ts +44 -39
- package/src/bundler/prerender.ts +63 -0
- package/src/bundler/safe-build.test.ts +2 -1
- package/src/bundler/types.ts +13 -6
- package/src/change/history.ts +1 -1
- package/src/change/snapshot.ts +18 -9
- package/src/client/Link.tsx +9 -9
- package/src/client/globals.ts +3 -2
- package/src/client/hooks.ts +0 -4
- package/src/client/hydrate.ts +1 -1
- package/src/client/router.ts +12 -12
- package/src/client/rpc.ts +1 -1
- package/src/client/use-fetch.ts +6 -6
- package/src/client/use-sse.ts +5 -5
- package/src/config/mcp-status.ts +0 -1
- package/src/config/validate.ts +4 -4
- package/src/config/watcher.ts +1 -1
- package/src/content/collection.ts +8 -12
- package/src/content/content-layer.ts +5 -5
- package/src/content/data-store.ts +2 -2
- package/src/content/loader-context.ts +0 -1
- package/src/content/loaders/file.ts +1 -1
- package/src/content/loaders/glob.ts +4 -4
- package/src/content/loaders/types.ts +1 -1
- package/src/content/meta-store.ts +1 -1
- package/src/content/types.ts +1 -1
- package/src/contract/define.ts +11 -12
- package/src/contract/index.ts +3 -3
- package/src/contract/protection.ts +2 -2
- package/src/contract/types.ts +1 -1
- package/src/contract/validator.ts +0 -1
- package/src/db/__tests__/db.test.ts +4 -7
- package/src/db/index.ts +138 -51
- package/src/db/migrations/index.ts +3 -0
- package/src/db/migrations/lock.ts +78 -23
- package/src/db/migrations/runner.ts +118 -101
- package/src/deploy/cache.ts +1 -0
- package/src/design/extract.ts +2 -1
- package/src/design/patch.ts +0 -1
- package/src/devtools/ai/mcp-connector.ts +24 -24
- package/src/devtools/client/components/kitchen-root.tsx +1 -1
- package/src/devtools/client/components/panel/errors-panel.tsx +1 -1
- package/src/devtools/client/state-manager.ts +1 -1
- package/src/devtools/init.ts +2 -3
- package/src/devtools/server/source-context.ts +1 -1
- package/src/devtools/worker/redaction-worker.ts +8 -4
- package/src/devtools/worker/worker-manager.ts +4 -3
- package/src/error/classifier.ts +1 -1
- package/src/error/domains.ts +1 -1
- package/src/filling/sse.ts +5 -5
- package/src/generator/generate.ts +2 -2
- package/src/guard/analyzer.ts +1 -1
- package/src/guard/ast-analyzer.ts +7 -7
- package/src/guard/auto-correct.ts +2 -2
- package/src/guard/config-guard.ts +0 -2
- package/src/guard/contract-guard.ts +1 -1
- package/src/guard/decision-memory.ts +2 -2
- package/src/guard/design-inline-class.ts +2 -1
- package/src/guard/graph.ts +1 -1
- package/src/guard/healing.ts +36 -41
- package/src/guard/negotiation.ts +3 -3
- package/src/guard/reporter.ts +1 -4
- package/src/guard/semantic-slots.ts +2 -2
- package/src/guard/suggestions.ts +2 -2
- package/src/guard/watcher.ts +5 -4
- package/src/index.ts +5 -5
- package/src/intent/index.ts +1 -1
- package/src/kitchen/api/agent-devtools-api.ts +544 -0
- package/src/kitchen/api/contract-api.ts +1 -1
- package/src/kitchen/api/file-api.ts +3 -3
- package/src/kitchen/kitchen-handler.ts +63 -38
- package/src/kitchen/kitchen-ui.ts +346 -62
- package/src/lockfile/validate.ts +0 -1
- package/src/openapi/generator.ts +2 -1
- package/src/openapi/openapi.test.ts +43 -14
- package/src/perf/user-marks.ts +1 -1
- package/src/plugins/registry.ts +1 -2
- package/src/plugins/types.ts +1 -1
- package/src/resource/__tests__/generator.test.ts +32 -15
- package/src/resource/ddl/__tests__/emit.test.ts +24 -0
- package/src/resource/ddl/diff.ts +0 -1
- package/src/resource/ddl/emit.ts +12 -1
- package/src/resource/generator-repo.ts +40 -20
- package/src/resource/generator.ts +1 -1
- package/src/resource/generators/contract.ts +1 -1
- package/src/resource/schema.ts +2 -1
- package/src/router/fs-routes.ts +6 -6
- package/src/router/fs-scanner.ts +1 -1
- package/src/runtime/env.ts +1 -1
- package/src/runtime/image-handler.ts +2 -1
- package/src/runtime/middleware.ts +2 -1
- package/src/runtime/server.ts +67 -60
- package/src/runtime/ssr.ts +3 -3
- package/src/runtime/streaming-ssr.ts +25 -27
- package/src/scheduler/validate.ts +1 -1
- package/src/seo/integration/ssr.ts +2 -3
- package/src/seo/render/opengraph.ts +1 -1
- package/src/seo/resolve/index.ts +0 -4
- package/src/slot/corrector.ts +1 -1
- package/src/slot/validator.ts +4 -4
- package/src/watcher/reporter.ts +1 -1
- package/src/watcher/watcher.ts +19 -19
|
@@ -11,17 +11,26 @@ import { getGlobalCache, getCacheStoreStats } from "../runtime/cache";
|
|
|
11
11
|
import { ActivitySSEBroadcaster } from "./stream/activity-sse";
|
|
12
12
|
import { GuardAPI } from "./api/guard-api";
|
|
13
13
|
import { handleRoutesRequest } from "./api/routes-api";
|
|
14
|
-
import { FileAPI } from "./api/file-api";
|
|
15
|
-
import { GuardDecisionManager } from "./api/guard-decisions";
|
|
16
|
-
import { ContractPlaygroundAPI } from "./api/contract-api";
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import
|
|
20
|
-
import
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
14
|
+
import { FileAPI } from "./api/file-api";
|
|
15
|
+
import { GuardDecisionManager } from "./api/guard-decisions";
|
|
16
|
+
import { ContractPlaygroundAPI } from "./api/contract-api";
|
|
17
|
+
import { handleAgentContextRequest } from "./api/agent-devtools-api";
|
|
18
|
+
import { renderKitchenHTML } from "./kitchen-ui";
|
|
19
|
+
import { eventBus } from "../observability/event-bus";
|
|
20
|
+
import fs from "fs/promises";
|
|
21
|
+
import path from "path";
|
|
22
|
+
|
|
23
|
+
export const KITCHEN_PREFIX = "/__kitchen";
|
|
24
|
+
|
|
25
|
+
function reverseCopy<T>(items: readonly T[]): T[] {
|
|
26
|
+
const reversed: T[] = [];
|
|
27
|
+
for (let index = items.length - 1; index >= 0; index -= 1) {
|
|
28
|
+
reversed.push(items[index] as T);
|
|
29
|
+
}
|
|
30
|
+
return reversed;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface KitchenOptions {
|
|
25
34
|
rootDir: string;
|
|
26
35
|
manifest: RoutesManifest;
|
|
27
36
|
guardConfig: GuardConfig | null;
|
|
@@ -74,9 +83,9 @@ export function recordRequest(entry: RequestEntry): void {
|
|
|
74
83
|
if (recentRequests.length > MAX_REQUESTS) recentRequests.shift();
|
|
75
84
|
}
|
|
76
85
|
|
|
77
|
-
export function getRecentRequests(): RequestEntry[] {
|
|
78
|
-
return
|
|
79
|
-
}
|
|
86
|
+
export function getRecentRequests(): RequestEntry[] {
|
|
87
|
+
return reverseCopy(recentRequests);
|
|
88
|
+
}
|
|
80
89
|
|
|
81
90
|
/** Parse a window string like "5m", "30s", "1h" into milliseconds. */
|
|
82
91
|
function parseWindow(input: string): number {
|
|
@@ -220,10 +229,11 @@ export class KitchenHandler {
|
|
|
220
229
|
this.contractAPI.updateManifest(manifest);
|
|
221
230
|
}
|
|
222
231
|
|
|
223
|
-
/** Update guard config when mandu.config.ts changes */
|
|
224
|
-
updateGuardConfig(config: GuardConfig | null): void {
|
|
225
|
-
this.
|
|
226
|
-
|
|
232
|
+
/** Update guard config when mandu.config.ts changes */
|
|
233
|
+
updateGuardConfig(config: GuardConfig | null): void {
|
|
234
|
+
this.options.guardConfig = config;
|
|
235
|
+
this.guardAPI.updateConfig(config);
|
|
236
|
+
}
|
|
227
237
|
|
|
228
238
|
/** Get the SSE broadcaster for external event injection */
|
|
229
239
|
get broadcaster(): ActivitySSEBroadcaster {
|
|
@@ -322,11 +332,11 @@ export class KitchenHandler {
|
|
|
322
332
|
// Requests API — recent HTTP events from eventBus (fallback: ring buffer)
|
|
323
333
|
if (sub === "/api/requests" && req.method === "GET") {
|
|
324
334
|
const url = new URL(req.url);
|
|
325
|
-
const limit = Math.min(parseInt(url.searchParams.get("limit") || "100", 10) || 100, 500);
|
|
326
|
-
const busEvents = eventBus.getRecent(limit, { type: "http" });
|
|
327
|
-
if (busEvents.length > 0) {
|
|
328
|
-
return Response.json({ requests: busEvents
|
|
329
|
-
}
|
|
335
|
+
const limit = Math.min(parseInt(url.searchParams.get("limit") || "100", 10) || 100, 500);
|
|
336
|
+
const busEvents = eventBus.getRecent(limit, { type: "http" });
|
|
337
|
+
if (busEvents.length > 0) {
|
|
338
|
+
return Response.json({ requests: reverseCopy(busEvents) });
|
|
339
|
+
}
|
|
330
340
|
return Response.json({ requests: getRecentRequests().slice(0, limit) });
|
|
331
341
|
}
|
|
332
342
|
|
|
@@ -343,21 +353,36 @@ export class KitchenHandler {
|
|
|
343
353
|
// Activity API — recent MCP events from eventBus (fallback: activity.jsonl)
|
|
344
354
|
if (sub === "/api/activity" && req.method === "GET") {
|
|
345
355
|
const url = new URL(req.url);
|
|
346
|
-
const limit = Math.min(parseInt(url.searchParams.get("limit") || "100", 10) || 100, 500);
|
|
347
|
-
const busEvents = eventBus.getRecent(limit, { type: "mcp" });
|
|
348
|
-
if (busEvents.length > 0) {
|
|
349
|
-
return Response.json({ events: busEvents
|
|
350
|
-
}
|
|
356
|
+
const limit = Math.min(parseInt(url.searchParams.get("limit") || "100", 10) || 100, 500);
|
|
357
|
+
const busEvents = eventBus.getRecent(limit, { type: "mcp" });
|
|
358
|
+
if (busEvents.length > 0) {
|
|
359
|
+
return Response.json({ events: reverseCopy(busEvents) });
|
|
360
|
+
}
|
|
351
361
|
const events = await this.readRecentActivity();
|
|
352
362
|
return Response.json({ events });
|
|
353
363
|
}
|
|
354
364
|
|
|
355
365
|
// Agent Stats API — per-agent (sessionId) aggregation of MCP events
|
|
356
|
-
if (sub === "/api/agent-stats" && req.method === "GET") {
|
|
357
|
-
return Response.json(computeAgentStats());
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
//
|
|
366
|
+
if (sub === "/api/agent-stats" && req.method === "GET") {
|
|
367
|
+
return Response.json(computeAgentStats());
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// Agent DevTools API — read-only context pack for supervised coding sessions
|
|
371
|
+
if (sub === "/api/agent-context" && req.method === "GET") {
|
|
372
|
+
return handleAgentContextRequest({
|
|
373
|
+
rootDir: this.options.rootDir,
|
|
374
|
+
manifest: this.manifest,
|
|
375
|
+
guardEnabled: !!this.options.guardConfig,
|
|
376
|
+
errors: getKitchenErrors(),
|
|
377
|
+
requests: getRecentRequests().slice(0, 100),
|
|
378
|
+
httpEvents: eventBus.getRecent(100, { type: "http" }),
|
|
379
|
+
mcpEvents: eventBus.getRecent(100, { type: "mcp" }),
|
|
380
|
+
guardEvents: eventBus.getRecent(100, { type: "guard" }),
|
|
381
|
+
agentStats: computeAgentStats(),
|
|
382
|
+
});
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Cache API — cache store stats
|
|
361
386
|
if ((sub === "/api/cache" || sub === "/api/cache-stats") && req.method === "GET") {
|
|
362
387
|
const store = getGlobalCache();
|
|
363
388
|
return Response.json({
|
|
@@ -488,11 +513,11 @@ export class KitchenHandler {
|
|
|
488
513
|
private async readRecentActivity(): Promise<unknown[]> {
|
|
489
514
|
const logPath = path.join(this.options.rootDir, ".mandu", "activity.jsonl");
|
|
490
515
|
try {
|
|
491
|
-
const content = await fs.readFile(logPath, "utf-8");
|
|
492
|
-
const lines = content.trim().split("\n").filter(Boolean);
|
|
493
|
-
return lines.slice(-50)
|
|
494
|
-
try { return JSON.parse(line); } catch { return null; }
|
|
495
|
-
}).filter(Boolean);
|
|
516
|
+
const content = await fs.readFile(logPath, "utf-8");
|
|
517
|
+
const lines = content.trim().split("\n").filter(Boolean);
|
|
518
|
+
return reverseCopy(lines.slice(-50)).map((line) => {
|
|
519
|
+
try { return JSON.parse(line); } catch { return null; }
|
|
520
|
+
}).filter(Boolean);
|
|
496
521
|
} catch { return []; }
|
|
497
522
|
}
|
|
498
523
|
}
|
|
@@ -57,12 +57,13 @@ export function renderKitchenHTML(): string {
|
|
|
57
57
|
</div>
|
|
58
58
|
</section>
|
|
59
59
|
|
|
60
|
-
<nav class="tabs">
|
|
61
|
-
<button class="tab" data-panel="activity">Activity</button>
|
|
62
|
-
<button class="tab
|
|
63
|
-
<button class="tab" data-panel="
|
|
64
|
-
<button class="tab" data-panel="
|
|
65
|
-
<button class="tab" data-panel="
|
|
60
|
+
<nav class="tabs">
|
|
61
|
+
<button class="tab" data-panel="activity">Activity</button>
|
|
62
|
+
<button class="tab" data-panel="agent">Agent</button>
|
|
63
|
+
<button class="tab active" data-panel="routes">Routes</button>
|
|
64
|
+
<button class="tab" data-panel="guard">Guard</button>
|
|
65
|
+
<button class="tab" data-panel="preview">Preview</button>
|
|
66
|
+
<button class="tab" data-panel="contracts">Contracts</button>
|
|
66
67
|
<button class="tab" data-panel="requests">Requests</button>
|
|
67
68
|
<button class="tab" data-panel="mcp-activity">MCP</button>
|
|
68
69
|
<button class="tab" data-panel="cache">Cache</button>
|
|
@@ -70,24 +71,37 @@ export function renderKitchenHTML(): string {
|
|
|
70
71
|
</nav>
|
|
71
72
|
|
|
72
73
|
<main class="panels">
|
|
73
|
-
<section id="panel-activity" class="panel">
|
|
74
|
-
<div class="panel-header">
|
|
75
|
-
<div>
|
|
76
|
-
<h2>Activity Stream</h2>
|
|
77
|
-
<p class="panel-subtitle">Recent Kitchen events and MCP activity.</p>
|
|
74
|
+
<section id="panel-activity" class="panel">
|
|
75
|
+
<div class="panel-header">
|
|
76
|
+
<div>
|
|
77
|
+
<h2>Activity Stream</h2>
|
|
78
|
+
<p class="panel-subtitle">Recent Kitchen events and MCP activity.</p>
|
|
78
79
|
</div>
|
|
79
80
|
<button id="clear-activity" class="btn-sm">Clear</button>
|
|
80
81
|
</div>
|
|
81
82
|
<div id="activity-list" class="activity-list">
|
|
82
83
|
<div class="empty-state">Waiting for MCP activity...</div>
|
|
83
|
-
</div>
|
|
84
|
-
</section>
|
|
85
|
-
|
|
86
|
-
<section id="panel-
|
|
87
|
-
<div class="panel-header">
|
|
88
|
-
<div>
|
|
89
|
-
<h2>
|
|
90
|
-
<p class="panel-subtitle">
|
|
84
|
+
</div>
|
|
85
|
+
</section>
|
|
86
|
+
|
|
87
|
+
<section id="panel-agent" class="panel">
|
|
88
|
+
<div class="panel-header">
|
|
89
|
+
<div>
|
|
90
|
+
<h2>Agent Supervisor</h2>
|
|
91
|
+
<p class="panel-subtitle">Situation brief, tool routing, prompt pack, and next safe action for supervised agents.</p>
|
|
92
|
+
</div>
|
|
93
|
+
<button id="refresh-agent" class="btn-sm">Refresh</button>
|
|
94
|
+
</div>
|
|
95
|
+
<div id="agent-content" class="agent-content">
|
|
96
|
+
<div class="empty-state">Open Agent to build a context pack.</div>
|
|
97
|
+
</div>
|
|
98
|
+
</section>
|
|
99
|
+
|
|
100
|
+
<section id="panel-routes" class="panel active">
|
|
101
|
+
<div class="panel-header">
|
|
102
|
+
<div>
|
|
103
|
+
<h2>Routes</h2>
|
|
104
|
+
<p class="panel-subtitle">Current filesystem routes, slots, contracts, and hydration hints.</p>
|
|
91
105
|
</div>
|
|
92
106
|
<div id="routes-summary" class="summary"></div>
|
|
93
107
|
</div>
|
|
@@ -1188,11 +1202,141 @@ const CSS = /* css */ `
|
|
|
1188
1202
|
box-shadow: 0 12px 28px rgba(30, 42, 58, 0.22);
|
|
1189
1203
|
}
|
|
1190
1204
|
|
|
1191
|
-
.requests-list, .mcp-list, .cache-content, .metrics-content {
|
|
1192
|
-
display: flex;
|
|
1193
|
-
flex-direction: column;
|
|
1194
|
-
gap: 6px;
|
|
1195
|
-
}
|
|
1205
|
+
.requests-list, .mcp-list, .cache-content, .metrics-content, .agent-content {
|
|
1206
|
+
display: flex;
|
|
1207
|
+
flex-direction: column;
|
|
1208
|
+
gap: 6px;
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
.agent-grid {
|
|
1212
|
+
display: grid;
|
|
1213
|
+
grid-template-columns: minmax(0, 1.1fr) minmax(320px, 0.9fr);
|
|
1214
|
+
gap: 14px;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
.agent-stack {
|
|
1218
|
+
display: flex;
|
|
1219
|
+
flex-direction: column;
|
|
1220
|
+
gap: 12px;
|
|
1221
|
+
}
|
|
1222
|
+
|
|
1223
|
+
.agent-card {
|
|
1224
|
+
padding: 14px;
|
|
1225
|
+
border: 1px solid var(--line);
|
|
1226
|
+
border-radius: 8px;
|
|
1227
|
+
background: rgba(255, 255, 255, 0.72);
|
|
1228
|
+
}
|
|
1229
|
+
|
|
1230
|
+
.agent-card-title {
|
|
1231
|
+
display: flex;
|
|
1232
|
+
align-items: center;
|
|
1233
|
+
justify-content: space-between;
|
|
1234
|
+
gap: 10px;
|
|
1235
|
+
margin-bottom: 8px;
|
|
1236
|
+
color: var(--ink);
|
|
1237
|
+
font-size: 14px;
|
|
1238
|
+
font-weight: 700;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
.agent-card-body {
|
|
1242
|
+
color: var(--muted);
|
|
1243
|
+
font-size: 13px;
|
|
1244
|
+
line-height: 1.55;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
.agent-pill-row {
|
|
1248
|
+
display: flex;
|
|
1249
|
+
flex-wrap: wrap;
|
|
1250
|
+
gap: 6px;
|
|
1251
|
+
margin-top: 10px;
|
|
1252
|
+
}
|
|
1253
|
+
|
|
1254
|
+
.agent-pill {
|
|
1255
|
+
padding: 4px 8px;
|
|
1256
|
+
border-radius: 6px;
|
|
1257
|
+
background: rgba(30, 42, 58, 0.08);
|
|
1258
|
+
color: var(--ink);
|
|
1259
|
+
font-family: "IBM Plex Mono", "Cascadia Code", monospace;
|
|
1260
|
+
font-size: 11px;
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
.agent-severity {
|
|
1264
|
+
padding: 3px 7px;
|
|
1265
|
+
border-radius: 6px;
|
|
1266
|
+
font-size: 11px;
|
|
1267
|
+
font-weight: 700;
|
|
1268
|
+
text-transform: uppercase;
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
.agent-severity.info { background: rgba(46, 102, 184, 0.12); color: var(--info); }
|
|
1272
|
+
.agent-severity.warn { background: rgba(173, 122, 18, 0.14); color: var(--warning); }
|
|
1273
|
+
.agent-severity.error { background: rgba(188, 61, 61, 0.12); color: var(--danger); }
|
|
1274
|
+
|
|
1275
|
+
.agent-stat-grid {
|
|
1276
|
+
display: grid;
|
|
1277
|
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
1278
|
+
gap: 8px;
|
|
1279
|
+
margin-top: 12px;
|
|
1280
|
+
}
|
|
1281
|
+
|
|
1282
|
+
.agent-stat {
|
|
1283
|
+
padding: 10px;
|
|
1284
|
+
border-radius: 8px;
|
|
1285
|
+
border: 1px solid rgba(220, 207, 186, 0.7);
|
|
1286
|
+
background: rgba(255, 253, 250, 0.84);
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
.agent-stat-label {
|
|
1290
|
+
color: var(--muted);
|
|
1291
|
+
font-size: 11px;
|
|
1292
|
+
}
|
|
1293
|
+
|
|
1294
|
+
.agent-stat-value {
|
|
1295
|
+
color: var(--ink);
|
|
1296
|
+
font-size: 19px;
|
|
1297
|
+
font-weight: 700;
|
|
1298
|
+
margin-top: 3px;
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1301
|
+
.agent-rec {
|
|
1302
|
+
display: grid;
|
|
1303
|
+
grid-template-columns: 150px 1fr;
|
|
1304
|
+
gap: 10px;
|
|
1305
|
+
padding: 10px 0;
|
|
1306
|
+
border-top: 1px solid rgba(220, 207, 186, 0.65);
|
|
1307
|
+
}
|
|
1308
|
+
|
|
1309
|
+
.agent-rec:first-child {
|
|
1310
|
+
border-top: 0;
|
|
1311
|
+
padding-top: 0;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
.agent-rec-title {
|
|
1315
|
+
color: var(--ink);
|
|
1316
|
+
font-weight: 700;
|
|
1317
|
+
font-size: 13px;
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
.agent-rec-detail {
|
|
1321
|
+
color: var(--muted);
|
|
1322
|
+
font-size: 12px;
|
|
1323
|
+
line-height: 1.5;
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
.agent-prompt {
|
|
1327
|
+
width: 100%;
|
|
1328
|
+
min-height: 220px;
|
|
1329
|
+
margin-top: 10px;
|
|
1330
|
+
padding: 12px;
|
|
1331
|
+
resize: vertical;
|
|
1332
|
+
border-radius: 8px;
|
|
1333
|
+
border: 1px solid var(--line);
|
|
1334
|
+
background: #fffdfa;
|
|
1335
|
+
color: var(--ink);
|
|
1336
|
+
font-family: "IBM Plex Mono", "Cascadia Code", monospace;
|
|
1337
|
+
font-size: 12px;
|
|
1338
|
+
line-height: 1.45;
|
|
1339
|
+
}
|
|
1196
1340
|
|
|
1197
1341
|
.req-row {
|
|
1198
1342
|
display: grid;
|
|
@@ -1313,13 +1457,17 @@ const CSS = /* css */ `
|
|
|
1313
1457
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
1314
1458
|
}
|
|
1315
1459
|
|
|
1316
|
-
.contracts-layout {
|
|
1317
|
-
grid-template-columns: 1fr;
|
|
1318
|
-
}
|
|
1319
|
-
|
|
1320
|
-
.
|
|
1321
|
-
grid-template-columns:
|
|
1322
|
-
}
|
|
1460
|
+
.contracts-layout {
|
|
1461
|
+
grid-template-columns: 1fr;
|
|
1462
|
+
}
|
|
1463
|
+
|
|
1464
|
+
.agent-grid {
|
|
1465
|
+
grid-template-columns: 1fr;
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1468
|
+
.guard-summary {
|
|
1469
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
1470
|
+
}
|
|
1323
1471
|
}
|
|
1324
1472
|
|
|
1325
1473
|
@media (max-width: 720px) {
|
|
@@ -1345,12 +1493,20 @@ const CSS = /* css */ `
|
|
|
1345
1493
|
width: calc(50% - 4px);
|
|
1346
1494
|
justify-content: center;
|
|
1347
1495
|
}
|
|
1348
|
-
|
|
1349
|
-
.panel-header {
|
|
1350
|
-
flex-direction: column;
|
|
1351
|
-
}
|
|
1352
|
-
|
|
1353
|
-
|
|
1496
|
+
|
|
1497
|
+
.panel-header {
|
|
1498
|
+
flex-direction: column;
|
|
1499
|
+
}
|
|
1500
|
+
|
|
1501
|
+
.agent-stat-grid {
|
|
1502
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
1503
|
+
}
|
|
1504
|
+
|
|
1505
|
+
.agent-rec {
|
|
1506
|
+
grid-template-columns: 1fr;
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
`;
|
|
1354
1510
|
|
|
1355
1511
|
// ─── JavaScript ──────────────────────────────────
|
|
1356
1512
|
|
|
@@ -1367,12 +1523,12 @@ const JS = /* js */ `
|
|
|
1367
1523
|
console.log('[Kitchen]', msg);
|
|
1368
1524
|
}
|
|
1369
1525
|
|
|
1370
|
-
function escapeHtml(str) {
|
|
1371
|
-
if (
|
|
1372
|
-
var d = document.createElement('div');
|
|
1373
|
-
d.appendChild(document.createTextNode(String(str)));
|
|
1374
|
-
return d.innerHTML;
|
|
1375
|
-
}
|
|
1526
|
+
function escapeHtml(str) {
|
|
1527
|
+
if (str === null || str === undefined) return '';
|
|
1528
|
+
var d = document.createElement('div');
|
|
1529
|
+
d.appendChild(document.createTextNode(String(str)));
|
|
1530
|
+
return d.innerHTML;
|
|
1531
|
+
}
|
|
1376
1532
|
|
|
1377
1533
|
function setMetric(id, value) {
|
|
1378
1534
|
var el = document.getElementById(id);
|
|
@@ -1893,9 +2049,10 @@ const JS = /* js */ `
|
|
|
1893
2049
|
|
|
1894
2050
|
loadContracts();
|
|
1895
2051
|
|
|
1896
|
-
// ─── Requests Tab ─────────────────────────────
|
|
1897
|
-
var requestsListEl = document.getElementById('requests-list');
|
|
1898
|
-
var requestsDetailEl = document.getElementById('requests-detail');
|
|
2052
|
+
// ─── Requests Tab ─────────────────────────────
|
|
2053
|
+
var requestsListEl = document.getElementById('requests-list');
|
|
2054
|
+
var requestsDetailEl = document.getElementById('requests-detail');
|
|
2055
|
+
var agentContentEl = document.getElementById('agent-content');
|
|
1899
2056
|
|
|
1900
2057
|
function fetchJson(url, cb) {
|
|
1901
2058
|
var xhr = new XMLHttpRequest();
|
|
@@ -1910,16 +2067,142 @@ const JS = /* js */ `
|
|
|
1910
2067
|
xhr.send();
|
|
1911
2068
|
}
|
|
1912
2069
|
|
|
1913
|
-
function statusClass(s) {
|
|
1914
|
-
if (!s) return '';
|
|
1915
|
-
if (s >= 500) return 's5';
|
|
1916
|
-
if (s >= 400) return 's4';
|
|
1917
|
-
if (s >= 300) return 's3';
|
|
1918
|
-
return 's2';
|
|
1919
|
-
}
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
2070
|
+
function statusClass(s) {
|
|
2071
|
+
if (!s) return '';
|
|
2072
|
+
if (s >= 500) return 's5';
|
|
2073
|
+
if (s >= 400) return 's4';
|
|
2074
|
+
if (s >= 300) return 's3';
|
|
2075
|
+
return 's2';
|
|
2076
|
+
}
|
|
2077
|
+
|
|
2078
|
+
// ─── Agent Supervisor Tab ─────────────────────
|
|
2079
|
+
function renderAgentPills(items) {
|
|
2080
|
+
if (!items || !items.length) return '';
|
|
2081
|
+
var html = '<div class="agent-pill-row">';
|
|
2082
|
+
for (var i = 0; i < items.length; i++) {
|
|
2083
|
+
html += '<span class="agent-pill">' + escapeHtml(items[i]) + '</span>';
|
|
2084
|
+
}
|
|
2085
|
+
return html + '</div>';
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
function renderAgentDetails(items) {
|
|
2089
|
+
if (!items || !items.length) return '';
|
|
2090
|
+
var html = '<ul>';
|
|
2091
|
+
for (var i = 0; i < items.length; i++) {
|
|
2092
|
+
html += '<li>' + escapeHtml(items[i]) + '</li>';
|
|
2093
|
+
}
|
|
2094
|
+
return html + '</ul>';
|
|
2095
|
+
}
|
|
2096
|
+
|
|
2097
|
+
function renderAgentContext(data) {
|
|
2098
|
+
var situation = data.situation || {};
|
|
2099
|
+
var summary = data.summary || {};
|
|
2100
|
+
var routes = summary.routes || {};
|
|
2101
|
+
var status = data.agentStatus || {};
|
|
2102
|
+
var brain = status.brain || {};
|
|
2103
|
+
var action = data.nextSafeAction || {};
|
|
2104
|
+
var prompt = data.prompt || {};
|
|
2105
|
+
var recs = data.toolRecommendations || [];
|
|
2106
|
+
var cards = data.knowledgeCards || [];
|
|
2107
|
+
var promptText = prompt.copyText || '';
|
|
2108
|
+
|
|
2109
|
+
var html = '<div class="agent-grid">' +
|
|
2110
|
+
'<div class="agent-stack">' +
|
|
2111
|
+
'<div class="agent-card">' +
|
|
2112
|
+
'<div class="agent-card-title">' +
|
|
2113
|
+
'<span>' + escapeHtml(situation.title || 'No situation') + '</span>' +
|
|
2114
|
+
'<span class="agent-severity ' + escapeHtml(situation.severity || 'info') + '">' + escapeHtml(situation.category || 'agent') + '</span>' +
|
|
2115
|
+
'</div>' +
|
|
2116
|
+
'<div class="agent-card-body">' + renderAgentDetails(situation.details || []) + '</div>' +
|
|
2117
|
+
'<div class="agent-stat-grid">' +
|
|
2118
|
+
'<div class="agent-stat"><div class="agent-stat-label">Routes</div><div class="agent-stat-value">' + escapeHtml(routes.total || 0) + '</div></div>' +
|
|
2119
|
+
'<div class="agent-stat"><div class="agent-stat-label">Islands</div><div class="agent-stat-value">' + escapeHtml(routes.islands || 0) + '</div></div>' +
|
|
2120
|
+
'<div class="agent-stat"><div class="agent-stat-label">Contracts</div><div class="agent-stat-value">' + escapeHtml(routes.contracts || 0) + '</div></div>' +
|
|
2121
|
+
'<div class="agent-stat"><div class="agent-stat-label">MCP Calls</div><div class="agent-stat-value">' + escapeHtml(status.observedToolCalls || 0) + '</div></div>' +
|
|
2122
|
+
'</div>' +
|
|
2123
|
+
'</div>' +
|
|
2124
|
+
'<div class="agent-card">' +
|
|
2125
|
+
'<div class="agent-card-title"><span>Next Safe Action</span><span class="agent-severity info">' + escapeHtml(action.mode || 'observe') + '</span></div>' +
|
|
2126
|
+
'<div class="agent-card-body"><strong>' + escapeHtml(action.title || '-') + '</strong><br>' + escapeHtml(action.reason || '') + '</div>' +
|
|
2127
|
+
renderAgentPills([action.tool || '', action.command || ''].filter(Boolean)) +
|
|
2128
|
+
renderAgentPills(action.validation || []) +
|
|
2129
|
+
'</div>' +
|
|
2130
|
+
'<div class="agent-card">' +
|
|
2131
|
+
'<div class="agent-card-title"><span>Prompt Pack</span><button id="copy-agent-prompt" class="btn-sm">Copy</button></div>' +
|
|
2132
|
+
'<textarea id="agent-prompt-text" class="agent-prompt" readonly>' + escapeHtml(promptText) + '</textarea>' +
|
|
2133
|
+
'</div>' +
|
|
2134
|
+
'</div>' +
|
|
2135
|
+
'<div class="agent-stack">' +
|
|
2136
|
+
'<div class="agent-card">' +
|
|
2137
|
+
'<div class="agent-card-title"><span>Brain</span><span class="agent-severity info">' + escapeHtml(brain.oauth || 'unknown') + '</span></div>' +
|
|
2138
|
+
'<div class="agent-card-body">' + escapeHtml(brain.note || '') + '</div>' +
|
|
2139
|
+
renderAgentPills([brain.statusTool || 'mandu.brain.status']) +
|
|
2140
|
+
'</div>' +
|
|
2141
|
+
'<div class="agent-card">' +
|
|
2142
|
+
'<div class="agent-card-title"><span>Tool Router</span></div>';
|
|
2143
|
+
|
|
2144
|
+
for (var i = 0; i < recs.length; i++) {
|
|
2145
|
+
var r = recs[i];
|
|
2146
|
+
html += '<div class="agent-rec">' +
|
|
2147
|
+
'<div class="agent-rec-title">' + escapeHtml(r.skill) + '</div>' +
|
|
2148
|
+
'<div class="agent-rec-detail">' +
|
|
2149
|
+
'<strong>' + escapeHtml(r.task) + '</strong><br>' +
|
|
2150
|
+
escapeHtml(r.useWhen) +
|
|
2151
|
+
renderAgentPills(r.mcpTools || []) +
|
|
2152
|
+
'<div style="margin-top:6px;">Fallback: <code>' + escapeHtml(r.cliFallback) + '</code></div>' +
|
|
2153
|
+
'</div>' +
|
|
2154
|
+
'</div>';
|
|
2155
|
+
}
|
|
2156
|
+
|
|
2157
|
+
html += '</div><div class="agent-card">' +
|
|
2158
|
+
'<div class="agent-card-title"><span>Knowledge</span></div>';
|
|
2159
|
+
|
|
2160
|
+
for (var c = 0; c < cards.length; c++) {
|
|
2161
|
+
var card = cards[c];
|
|
2162
|
+
html += '<div class="agent-rec">' +
|
|
2163
|
+
'<div class="agent-rec-title">' + escapeHtml(card.title) + '</div>' +
|
|
2164
|
+
'<div class="agent-rec-detail">' + escapeHtml(card.body) + renderAgentPills(card.references || []) + '</div>' +
|
|
2165
|
+
'</div>';
|
|
2166
|
+
}
|
|
2167
|
+
|
|
2168
|
+
html += '</div></div></div>';
|
|
2169
|
+
agentContentEl.innerHTML = html;
|
|
2170
|
+
|
|
2171
|
+
var copyBtn = document.getElementById('copy-agent-prompt');
|
|
2172
|
+
if (copyBtn) {
|
|
2173
|
+
copyBtn.addEventListener('click', function() {
|
|
2174
|
+
var textEl = document.getElementById('agent-prompt-text');
|
|
2175
|
+
var text = textEl ? textEl.value : promptText;
|
|
2176
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
2177
|
+
navigator.clipboard.writeText(text).then(function() {
|
|
2178
|
+
copyBtn.textContent = 'Copied';
|
|
2179
|
+
setTimeout(function() { copyBtn.textContent = 'Copy'; }, 900);
|
|
2180
|
+
}).catch(function() {
|
|
2181
|
+
textEl && textEl.select();
|
|
2182
|
+
});
|
|
2183
|
+
} else if (textEl) {
|
|
2184
|
+
textEl.select();
|
|
2185
|
+
}
|
|
2186
|
+
});
|
|
2187
|
+
}
|
|
2188
|
+
}
|
|
2189
|
+
|
|
2190
|
+
function loadAgentContext() {
|
|
2191
|
+
if (!agentContentEl) return;
|
|
2192
|
+
agentContentEl.innerHTML = '<div class="empty-state">Building agent context...</div>';
|
|
2193
|
+
fetchJson('/__kitchen/api/agent-context', function(err, data) {
|
|
2194
|
+
if (err) {
|
|
2195
|
+
agentContentEl.innerHTML = '<div class="empty-state">Failed: ' + escapeHtml(err.message) + '</div>';
|
|
2196
|
+
return;
|
|
2197
|
+
}
|
|
2198
|
+
renderAgentContext(data);
|
|
2199
|
+
});
|
|
2200
|
+
}
|
|
2201
|
+
|
|
2202
|
+
document.getElementById('refresh-agent').addEventListener('click', loadAgentContext);
|
|
2203
|
+
|
|
2204
|
+
function loadRequests() {
|
|
2205
|
+
requestsListEl.innerHTML = '<div class="empty-state">Loading requests...</div>';
|
|
1923
2206
|
fetchJson('/__kitchen/api/requests?limit=100', function(err, data) {
|
|
1924
2207
|
if (err) {
|
|
1925
2208
|
requestsListEl.innerHTML = '<div class="empty-state">Failed: ' + escapeHtml(err.message) + '</div>';
|
|
@@ -2116,12 +2399,13 @@ const JS = /* js */ `
|
|
|
2116
2399
|
document.getElementById('refresh-metrics').addEventListener('click', loadMetrics);
|
|
2117
2400
|
|
|
2118
2401
|
// Lazy-load new tab data when clicked (avoids loading everything up front)
|
|
2119
|
-
var tabLoaders = {
|
|
2120
|
-
'
|
|
2121
|
-
'
|
|
2122
|
-
'
|
|
2123
|
-
'
|
|
2124
|
-
|
|
2402
|
+
var tabLoaders = {
|
|
2403
|
+
'agent': loadAgentContext,
|
|
2404
|
+
'requests': loadRequests,
|
|
2405
|
+
'mcp-activity': loadMcpActivity,
|
|
2406
|
+
'cache': loadCacheStats,
|
|
2407
|
+
'metrics': loadMetrics
|
|
2408
|
+
};
|
|
2125
2409
|
var loadedTabs = {};
|
|
2126
2410
|
for (var t = 0; t < tabs.length; t++) {
|
|
2127
2411
|
tabs[t].addEventListener('click', function() {
|
package/src/lockfile/validate.ts
CHANGED
package/src/openapi/generator.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type * as __ManduNodeCryptoTypes0 from "node:crypto";
|
|
1
2
|
/**
|
|
2
3
|
* Mandu OpenAPI Generator
|
|
3
4
|
* Contract에서 OpenAPI 3.0 스펙 자동 생성
|
|
@@ -893,7 +894,7 @@ function sha256Hex(input: string): string {
|
|
|
893
894
|
// path (it would turn `hoistSharedSchemas` into an unnecessarily async
|
|
894
895
|
// cascade on the hot path).
|
|
895
896
|
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
896
|
-
const nodeCrypto = require("node:crypto") as typeof
|
|
897
|
+
const nodeCrypto = require("node:crypto") as typeof __ManduNodeCryptoTypes0;
|
|
897
898
|
return nodeCrypto.createHash("sha256").update(input).digest("hex");
|
|
898
899
|
}
|
|
899
900
|
|