@hazeljs/inspector 2.0.0 → 2.0.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/README.md CHANGED
@@ -9,6 +9,7 @@ Framework-aware runtime inspector for HazelJS. Explore metadata, routes, modules
9
9
  - **DevTools UI** – Overview dashboard, search, filters, detail views, runtime stats
10
10
  - **JSON API** – Consume inspector data programmatically
11
11
  - **Agent OS timelines** – SSE live stream + JSON replay for agent execution steps
12
+ - **Agent Runs** – Durable `AgentRunRepository` list/detail/cancel + in-process metrics/cost strip
12
13
 
13
14
  ## Installation
14
15
 
@@ -53,13 +54,18 @@ Then run your app and open:
53
54
 
54
55
  When agents are registered, Inspector exposes live debugging endpoints:
55
56
 
56
- | Endpoint | Description |
57
- | ------------------------------------ | ------------------------------------------------- |
58
- | `GET /__hazel/agents/:name/stream` | SSE stream of timeline steps while the agent runs |
59
- | `GET /__hazel/agents/:name/timeline` | JSON replay of recorded timeline steps |
60
- | `POST /__hazel/agents/:name/run` | Run the agent from the UI (optional input prompt) |
61
-
62
- In the Agents panel, use **Run** (executes + streams) or **Timeline** (loads history and opens the live SSE feed).
57
+ | Endpoint | Description |
58
+ | ------------------------------------ | ------------------------------------------------------------- |
59
+ | `GET /__hazel/agents/:name/stream` | SSE stream of timeline steps while the agent runs |
60
+ | `GET /__hazel/agents/:name/timeline` | JSON replay of recorded timeline steps |
61
+ | `POST /__hazel/agents/:name/run` | Run the agent from the UI (optional input prompt) |
62
+ | `GET /__hazel/runs` | List durable `AgentRun` records (`agentName`, `status` query) |
63
+ | `GET /__hazel/runs/:runId` | Run detail + timeline steps for that execution |
64
+ | `POST /__hazel/runs/:runId/cancel` | Cancel in-flight + mark run cancelled |
65
+ | `GET /__hazel/agents/metrics` | In-process metrics / cost summary |
66
+
67
+ In the Agents panel, use **Run** (executes + streams) or **Timeline** (loads history and opens the live SSE feed).
68
+ Open **Agent Runs** for durable repository records and the cost/metrics strip.
63
69
 
64
70
  ```bash
65
71
  # Replay last timeline
@@ -297,6 +297,123 @@ function createInspectorHandler(service, config, app) {
297
297
  res.end(JSON.stringify({ entries: agents }));
298
298
  return;
299
299
  }
300
+ // Agent OS durable runs (AgentRunRepository)
301
+ if ((pathSeg === '/runs' || pathSeg === '/runs/') && req.method === 'GET') {
302
+ try {
303
+ const { AgentService } = require('@hazeljs/agent');
304
+ const container = app.getContainer();
305
+ const svc = container.resolve(AgentService);
306
+ const runtime = svc?.getRuntime?.();
307
+ if (!runtime?.getRunRepository) {
308
+ res.writeHead(503);
309
+ res.end(JSON.stringify({
310
+ error: 'AgentRunRepository not available. Ensure AgentModule + AgentRuntime are configured.',
311
+ }));
312
+ return;
313
+ }
314
+ const url = new URL(req.url ?? '/', 'http://localhost');
315
+ const agentName = url.searchParams.get('agentName') ?? undefined;
316
+ const status = url.searchParams.get('status') ?? undefined;
317
+ const runs = await runtime.getRunRepository().list(agentName || status
318
+ ? {
319
+ ...(agentName ? { agentName } : {}),
320
+ ...(status ? { status: status } : {}),
321
+ }
322
+ : undefined);
323
+ res.writeHead(200);
324
+ res.end(JSON.stringify({ runs }));
325
+ }
326
+ catch (err) {
327
+ res.writeHead(500);
328
+ res.end(JSON.stringify({ error: String(err) }));
329
+ }
330
+ return;
331
+ }
332
+ const runCancelMatch = pathSeg.match(/^\/runs\/([^/]+)\/cancel\/?$/);
333
+ if (runCancelMatch && req.method === 'POST') {
334
+ const runId = decodeURIComponent(runCancelMatch[1]);
335
+ try {
336
+ const { AgentService, AgentRunStatus } = require('@hazeljs/agent');
337
+ const container = app.getContainer();
338
+ const svc = container.resolve(AgentService);
339
+ const runtime = svc?.getRuntime?.();
340
+ if (!runtime?.getRunRepository) {
341
+ res.writeHead(503);
342
+ res.end(JSON.stringify({ error: 'AgentRunRepository not available' }));
343
+ return;
344
+ }
345
+ runtime.cancel?.(runId);
346
+ const existing = await runtime.getRunRepository().get(runId);
347
+ if (!existing) {
348
+ res.writeHead(404);
349
+ res.end(JSON.stringify({ error: `Run not found: ${runId}` }));
350
+ return;
351
+ }
352
+ const updated = await runtime
353
+ .getRunRepository()
354
+ .updateStatus(runId, AgentRunStatus.CANCELLED);
355
+ res.writeHead(200);
356
+ res.end(JSON.stringify({ run: updated }));
357
+ }
358
+ catch (err) {
359
+ res.writeHead(500);
360
+ res.end(JSON.stringify({ error: String(err) }));
361
+ }
362
+ return;
363
+ }
364
+ const runMatch = pathSeg.match(/^\/runs\/([^/]+)\/?$/);
365
+ if (runMatch && req.method === 'GET') {
366
+ const runId = decodeURIComponent(runMatch[1]);
367
+ try {
368
+ const { AgentService } = require('@hazeljs/agent');
369
+ const container = app.getContainer();
370
+ const svc = container.resolve(AgentService);
371
+ const runtime = svc?.getRuntime?.();
372
+ if (!runtime?.getRunRepository) {
373
+ res.writeHead(503);
374
+ res.end(JSON.stringify({ error: 'AgentRunRepository not available' }));
375
+ return;
376
+ }
377
+ const run = await runtime.getRunRepository().get(runId);
378
+ if (!run) {
379
+ res.writeHead(404);
380
+ res.end(JSON.stringify({ error: `Run not found: ${runId}` }));
381
+ return;
382
+ }
383
+ const steps = svc.getTimeline?.({ executionId: runId }) ?? [];
384
+ res.writeHead(200);
385
+ res.end(JSON.stringify({ run, steps }));
386
+ }
387
+ catch (err) {
388
+ res.writeHead(500);
389
+ res.end(JSON.stringify({ error: String(err) }));
390
+ }
391
+ return;
392
+ }
393
+ if ((pathSeg === '/agents/metrics' || pathSeg === '/agents/metrics/') &&
394
+ req.method === 'GET') {
395
+ try {
396
+ const { AgentService } = require('@hazeljs/agent');
397
+ const container = app.getContainer();
398
+ const svc = container.resolve(AgentService);
399
+ const runtime = svc?.getRuntime?.();
400
+ if (!runtime) {
401
+ res.writeHead(503);
402
+ res.end(JSON.stringify({ error: 'AgentRuntime not available' }));
403
+ return;
404
+ }
405
+ res.writeHead(200);
406
+ res.end(JSON.stringify({
407
+ metrics: runtime.getMetrics?.() ?? null,
408
+ summary: runtime.getMetricsSummary?.() ?? null,
409
+ }));
410
+ }
411
+ catch (err) {
412
+ res.writeHead(500);
413
+ res.end(JSON.stringify({ error: String(err) }));
414
+ }
415
+ return;
416
+ }
300
417
  const agentRunMatch = pathSeg.match(/^\/agents\/([^/]+)\/run\/?$/);
301
418
  if (agentRunMatch && req.method === 'POST') {
302
419
  const agentName = decodeURIComponent(agentRunMatch[1]);
@@ -554,8 +671,12 @@ function createInspectorHandler(service, config, app) {
554
671
  '/queues',
555
672
  '/websocket',
556
673
  '/agents',
674
+ '/agents/metrics',
557
675
  '/agents/:name/stream',
558
676
  '/agents/:name/timeline',
677
+ '/runs',
678
+ '/runs/:runId',
679
+ '/runs/:runId/cancel',
559
680
  '/rag',
560
681
  '/prompts',
561
682
  '/aifunctions',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hazeljs/inspector",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Framework-aware runtime inspector for HazelJS - metadata explorer and DevTools UI",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -22,22 +22,22 @@
22
22
  "reflect-metadata": "^0.2.2"
23
23
  },
24
24
  "peerDependencies": {
25
- "@hazeljs/agent": "^2.0.0",
26
- "@hazeljs/ai": "^2.0.0",
27
- "@hazeljs/core": "^2.0.0",
28
- "@hazeljs/cron": "^2.0.0",
29
- "@hazeljs/data": "^2.0.0",
30
- "@hazeljs/event-emitter": "^2.0.0",
31
- "@hazeljs/flow": "^2.0.0",
32
- "@hazeljs/graphql": "^2.0.0",
33
- "@hazeljs/grpc": "^2.0.0",
34
- "@hazeljs/kafka": "^2.0.0",
35
- "@hazeljs/ml": "^2.0.0",
36
- "@hazeljs/prompts": "^2.0.0",
37
- "@hazeljs/queue": "^2.0.0",
38
- "@hazeljs/rag": "^2.0.0",
39
- "@hazeljs/serverless": "^2.0.0",
40
- "@hazeljs/websocket": "^2.0.0"
25
+ "@hazeljs/agent": "^2.0.2",
26
+ "@hazeljs/ai": "^2.0.2",
27
+ "@hazeljs/core": "^2.0.2",
28
+ "@hazeljs/cron": "^2.0.2",
29
+ "@hazeljs/data": "^2.0.2",
30
+ "@hazeljs/event-emitter": "^2.0.2",
31
+ "@hazeljs/flow": "^2.0.2",
32
+ "@hazeljs/graphql": "^2.0.2",
33
+ "@hazeljs/grpc": "^2.0.2",
34
+ "@hazeljs/kafka": "^2.0.2",
35
+ "@hazeljs/ml": "^2.0.2",
36
+ "@hazeljs/prompts": "^2.0.2",
37
+ "@hazeljs/queue": "^2.0.2",
38
+ "@hazeljs/rag": "^2.0.2",
39
+ "@hazeljs/serverless": "^2.0.2",
40
+ "@hazeljs/websocket": "^2.0.2"
41
41
  },
42
42
  "peerDependenciesMeta": {
43
43
  "@hazeljs/cron": {
@@ -87,7 +87,7 @@
87
87
  }
88
88
  },
89
89
  "devDependencies": {
90
- "@hazeljs/core": "^2.0.0",
90
+ "@hazeljs/core": "^2.0.2",
91
91
  "@types/jest": "^29.5.14",
92
92
  "@types/node": "^20.19.39",
93
93
  "@typescript-eslint/eslint-plugin": "^8.58.0",
@@ -0,0 +1,87 @@
1
+ (function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e=(()=>{let e=window.location.pathname.match(/^\/[^/]+/);return e?e[0]:`/__hazel`})(),t=window.location.origin,n=null,r=!1,i=[],a=60;async function o(t=!1){let n=`${e}/inspect${t?`?refresh=1`:``}`,r=await fetch(n);if(!r.ok)throw Error(`Failed to fetch: ${r.status}`);return r.json()}async function s(){let t=await fetch(`${e}/stats`);return t.ok?t.json():{}}async function c(){let t=await fetch(`${e}/env`);return t.ok?t.json():{}}async function l(e){try{let n=await fetch(`${t}${e}`),r=n.ok,i;return i=n.headers.get(`content-type`)?.includes(`application/json`)?await n.json():await n.text(),{status:r?`up`:`down`,ok:r,data:i}}catch{return{status:`down`,ok:!1}}}function u(e){let t=document.getElementById(`loading-overlay`);t&&t.classList.toggle(`hidden`,!e)}function d(e,t){let n=document.getElementById(`status-dot`),r=document.getElementById(`status-text`),i=document.getElementById(`status-uptime`);if(!n||!r||!i)return;let a=e?.health?.ok&&e?.ready?.ok&&e?.startup?.ok,o=e?.health?.ok||e?.ready?.ok||e?.startup?.ok;n.className=`status-dot`+(a?` healthy`:o?``:` unhealthy`),r.textContent=a?`All systems operational`:o?`Degraded`:`Offline`,i.textContent=t.uptimeSeconds==null?``:`Uptime: ${m(t.uptimeSeconds)}`}function f(e){let t=document.getElementById(`quick-stats`);if(!t)return;let n=e&&typeof e==`object`?e:{},r=[];(n.route??0)>0&&r.push(`<span class="quick-stat"><strong>${n.route}</strong> routes</span>`),(n.module??0)>0&&r.push(`<span class="quick-stat"><strong>${n.module}</strong> modules</span>`),(n.provider??0)>0&&r.push(`<span class="quick-stat"><strong>${n.provider}</strong> providers</span>`),(n.cron??0)>0&&r.push(`<span class="quick-stat"><strong>${n.cron}</strong> jobs</span>`),t.innerHTML=r.join(``)||`<span class="quick-stat muted">No data</span>`}function p(e){let t=document.getElementById(`offline-banner`);e&&!t&&(t=document.createElement(`div`),t.id=`offline-banner`,t.className=`offline-banner`,t.innerHTML=`<span>App not running. Check that your server is started.</span><button id="retry-btn">Retry</button>`,document.querySelector(`.content`)?.insertBefore(t,document.querySelector(`.toolbar`)),t.querySelector(`#retry-btn`)?.addEventListener(`click`,()=>X(!0))),t&&t.classList.toggle(`hidden`,!e)}function m(e){return e<60?`${Math.floor(e)}s`:e<3600?`${Math.floor(e/60)}m ${e%60}s`:`${Math.floor(e/3600)}h ${Math.floor(e%3600/60)}m`}function h(e){let t=String(e||``).toUpperCase();return`<span class="badge badge-${t===`GET`?`get`:t===`POST`?`post`:t===`PUT`?`put`:t===`PATCH`?`patch`:t===`DELETE`?`delete`:`default`}">${t||`?`}</span>`}function g(e){return JSON.stringify(e,null,2).replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)/g,e=>{let t=`json-number`;return/^"/.test(e)?t=e.endsWith(`:`)?`json-key`:`json-string`:/true|false/.test(e)?t=`json-boolean`:/null/.test(e)&&(t=`json-null`),`<span class="${t}">${_(e)}</span>`})}function _(e){let t=document.createElement(`div`);return t.textContent=e,t.innerHTML}var v={route:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>`,module:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>`,provider:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/></svg>`,cron:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>`,queue:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>`,websocket:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>`,agent:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="10" rx="2"/><circle cx="12" cy="5" r="2"/><path d="M12 7v4"/></svg>`,rag:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/><path d="M8 7h8"/><path d="M8 11h8"/></svg>`,prompt:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>`,aifunction:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/></svg>`,event:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2v4"/><path d="M16 2v4"/><rect x="3" y="4" width="18" height="18" rx="2"/><path d="M3 10h18"/><path d="M8 14h.01"/><path d="M12 14h.01"/><path d="M16 14h.01"/></svg>`,graphql:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v18"/><path d="M5 12h14"/><path d="M3 8l9-5 9 5"/><path d="M3 16l9 5 9-5"/></svg>`,grpc:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="M12 5l7 7-7 7"/></svg>`,kafka:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><path d="M9 9h6"/><path d="M9 13h6"/><path d="M9 17h4"/></svg>`,flow:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>`,data:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>`,serverless:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"/></svg>`,ml:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v4"/><path d="M12 18v4"/><path d="m4.93 4.93 2.83 2.83"/><path d="m16.24 16.24 2.83 2.83"/><path d="M2 12h4"/><path d="M18 12h4"/><path d="m4.93 19.07 2.83-2.83"/><path d="m16.24 7.76 2.83-2.83"/><circle cx="12" cy="12" r="4"/></svg>`,decorator:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"/><line x1="7" y1="7" x2="7.01" y2="7"/></svg>`},y=[{title:`Framework`,items:[{key:`route`,label:`Routes`},{key:`module`,label:`Modules`},{key:`provider`,label:`Providers`},{key:`decorator`,label:`Decorators`}]},{title:`Scheduled & Async`,items:[{key:`cron`,label:`Cron Jobs`},{key:`queue`,label:`Queues`}]},{title:`AI & Intelligence`,items:[{key:`agent`,label:`Agents`},{key:`aifunction`,label:`AI Functions`},{key:`rag`,label:`RAG`},{key:`prompt`,label:`Prompts`},{key:`ml`,label:`ML`}]},{title:`APIs & Messaging`,items:[{key:`graphql`,label:`GraphQL`},{key:`grpc`,label:`gRPC`},{key:`kafka`,label:`Kafka`},{key:`websocket`,label:`WebSockets`},{key:`event`,label:`Events`}]},{title:`Workflows & Data`,items:[{key:`flow`,label:`Flows`},{key:`data`,label:`Data`},{key:`serverless`,label:`Serverless`}]}];function b(e){let t=document.getElementById(`summary-cards`),n=e&&typeof e==`object`?e:{};t.innerHTML=y.map(e=>`
2
+ <section class="overview-section">
3
+ <h3 class="overview-section-title">${_(e.title)}</h3>
4
+ <div class="overview-section-cards">
5
+ ${(Array.isArray(e.items)?e.items:[]).map(e=>`<div class="card" data-kind="${_(e.key)}">
6
+ <div class="card-icon">${v[e.key]??``}</div>
7
+ <div class="card-label">${_(e.label)}</div>
8
+ <div class="card-value">${n[e.key]??0}</div>
9
+ </div>`).join(``)}
10
+ </div>
11
+ </section>
12
+ `).join(``)}var x={heap:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2v4"/><path d="M12 18v4"/><path d="m4.93 4.93 2.83 2.83"/><path d="m16.24 16.24 2.83 2.83"/><path d="M2 12h4"/><path d="M18 12h4"/><path d="m4.93 19.07 2.83-2.83"/><path d="m16.24 7.76 2.83-2.83"/><circle cx="12" cy="12" r="4"/></svg>`,rss:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8"/><path d="M12 17v4"/></svg>`,uptime:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>`};function S(e){let t=document.getElementById(`env-info`);t&&(t.innerHTML=`
13
+ <div class="env-item"><strong>Node</strong> ${_(e.nodeVersion??`—`)}</div>
14
+ <div class="env-item"><strong>NODE_ENV</strong> ${_(e.nodeEnv??`—`)}</div>
15
+ <div class="env-item"><strong>Inspector</strong> ${_(e.inspectorVersion??`—`)}</div>
16
+ <div class="env-item"><strong>Platform</strong> ${_(e.platform??`—`)}</div>
17
+ <div class="env-item"><strong>Arch</strong> ${_(e.arch??`—`)}</div>
18
+ `)}function C(e){let t=document.getElementById(`overview-gateway`);if(!t)return;let n=Array.isArray(e.routes)?e.routes:[],r=e.metrics;t.innerHTML=`
19
+ <h3 class="overview-block-title">Gateway</h3>
20
+ <div class="overview-gateway-stats">
21
+ <div class="overview-stat"><span class="stat-value">${n.length}</span><span class="stat-label">Routes</span></div>
22
+ ${r?`
23
+ <div class="overview-stat"><span class="stat-value">${r.totalCalls}</span><span class="stat-label">Total Calls</span></div>
24
+ <div class="overview-stat"><span class="stat-value">${r.successCalls}</span><span class="stat-label">Success</span></div>
25
+ <div class="overview-stat"><span class="stat-value">${(r.failureRate??0).toFixed(1)}%</span><span class="stat-label">Failure Rate</span></div>
26
+ <div class="overview-stat"><span class="stat-value">${(r.averageResponseTime??0).toFixed(0)}ms</span><span class="stat-label">Avg Latency</span></div>
27
+ `:``}
28
+ </div>
29
+ ${n.length?`<div class="overview-gateway-routes"><strong>Routes:</strong> ${n.slice(0,8).map(e=>`<code>${_(e)}</code>`).join(`, `)}${n.length>8?` <span class="muted">+${n.length-8} more</span>`:``}</div>`:``}
30
+ `,t.classList.remove(`hidden`)}function w(e){let t=document.getElementById(`overview-discovery`);if(!t)return;let n=Array.isArray(e.services)?e.services:[],r=e.instancesByService&&typeof e.instancesByService==`object`?e.instancesByService:{},i=n.slice(0,6).map(e=>`<span class="discovery-service"><code>${_(e)}</code>: ${r[e]??0} instance(s)</span>`).join(`, `);t.innerHTML=`
31
+ <h3 class="overview-block-title">Discovery</h3>
32
+ <div class="overview-discovery-stats">
33
+ <div class="overview-stat"><span class="stat-value">${e.totalServices??0}</span><span class="stat-label">Services</span></div>
34
+ <div class="overview-stat"><span class="stat-value">${e.totalInstances??0}</span><span class="stat-label">Connected Instances</span></div>
35
+ </div>
36
+ ${n.length?`<div class="overview-discovery-services">${i}${n.length>6?` <span class="muted">+${n.length-6} more</span>`:``}</div>`:`<p class="muted">No services registered</p>`}
37
+ `,t.classList.remove(`hidden`)}function ee(e){let t=document.getElementById(`overview-resilience`);if(!t)return;let n=Array.isArray(e.circuitBreakerStates)?e.circuitBreakerStates:[],r=n.map(e=>`<span class="cb-state ${(e.state||``).toLowerCase()}"><code>${_(e.name)}</code>: ${_(e.state)}</span>`).join(`, `);t.innerHTML=`
38
+ <h3 class="overview-block-title">Resilience</h3>
39
+ <div class="overview-resilience-stats">
40
+ <div class="overview-stat"><span class="stat-value">${e.circuitBreakers??0}</span><span class="stat-label">Circuit Breakers</span></div>
41
+ </div>
42
+ ${n.length?`<div class="overview-resilience-states">${r}</div>`:``}
43
+ `,t.classList.remove(`hidden`)}function te(e){let t=document.getElementById(`health-cards`);t&&(t.innerHTML=[{key:`health`,endpoint:`/health`,label:`Health`,data:e.health},{key:`ready`,endpoint:`/ready`,label:`Ready`,data:e.ready},{key:`startup`,endpoint:`/startup`,label:`Startup`,data:e.startup}].map(e=>{let t=e.data??{status:`unknown`,ok:!1};return`
44
+ <div class="health-card ${t.ok?`healthy`:t.status===`unknown`?`unknown`:`unhealthy`}">
45
+ <h3>${_(e.label)}</h3>
46
+ <div class="status">${t.ok?`Up`:t.status===`unknown`?`Unknown`:`Down`}</div>
47
+ <div class="endpoint">${_(e.endpoint)}</div>
48
+ </div>
49
+ `}).join(``))}function ne(e){let t=document.getElementById(`runtime-cards`),n=e=>(e/1024/1024).toFixed(2);e.memory&&(i.push({heap:e.memory.heapUsed,rss:e.memory.rss,t:Date.now()}),i.length>a&&i.shift()),t.innerHTML=`
50
+ <div class="card">
51
+ <div class="card-icon">${x.heap}</div>
52
+ <div class="card-label">Heap Used</div>
53
+ <div class="card-value">${e.memory?.heapUsed?n(e.memory.heapUsed)+` MB`:`—`}</div>
54
+ </div>
55
+ <div class="card">
56
+ <div class="card-icon">${x.rss}</div>
57
+ <div class="card-label">RSS Memory</div>
58
+ <div class="card-value">${e.memory?.rss?n(e.memory.rss)+` MB`:`—`}</div>
59
+ </div>
60
+ <div class="card">
61
+ <div class="card-icon">${x.uptime}</div>
62
+ <div class="card-label">Uptime</div>
63
+ <div class="card-value highlight">${e.uptimeSeconds==null?`—`:m(e.uptimeSeconds)}</div>
64
+ </div>
65
+ `,T()}function T(){let e=document.getElementById(`memory-chart-container`);if(!e||i.length<2){e?.classList.add(`hidden`);return}e.classList.remove(`hidden`);let t=Math.max(...i.map(e=>e.heap)),n=Math.max(...i.map(e=>e.rss)),r=Math.max(t,n,1),a=e=>e/1024/1024/r*100;e.innerHTML=`
66
+ <svg width="100%" height="100%" viewBox="0 0 400 180" preserveAspectRatio="none">
67
+ <polyline fill="none" stroke="var(--accent)" stroke-width="2" points="${i.map((e,t)=>`${t/(i.length-1)*100},${100-a(e.heap)}`).join(` `)}"/>
68
+ </svg>
69
+ <div style="font-size:11px;color:var(--text-muted);margin-top:0.5rem">Heap over time (last ${i.length} samples)</div>
70
+ `}var E={},D=50;function O(e){let t=new Map;for(let n of e){let e=String(n.flowId??``);t.has(e)||t.set(e,[]),t.get(e).push(n)}let n=new Map;for(let[e,r]of t){let t=r.find(e=>!!String(e.nodes??``).trim())??r[0],i=(t.nodes??``).split(/[,]/).map(e=>e.trim()).filter(Boolean);i.length===0&&(i=r.map(e=>e.nodeName).filter(e=>!!e));let a=(t.edges??``).toString().split(/[;,]/).map(e=>e.trim()).filter(Boolean).map(e=>{let t=e.indexOf(`→`);if(t<0)return null;let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();return n&&r?{from:n,to:r}:null}).filter(e=>e!=null);for(let e of r){let t=(e.edges??``).toString().split(/[;,]/);for(let e of t){let t=e.indexOf(`→`);if(t>=0){let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();n&&r&&!a.some(e=>e.from===n&&e.to===r)&&a.push({from:n,to:r})}}}let o=String(t.entryNode??i[0]??``);n.set(e,{nodes:[...new Set(i)],edges:a,entryNode:o})}return n}var k=48,A=24,j=6;function M(e){let t=new Map,n=new Map,r=e.entryNode||e.nodes[0];if(!r)return t;n.set(r,0);let i=[r],a=new Set([r]);for(;i.length>0;){let t=i.shift(),r=n.get(t)??0;for(let o of e.edges)if(o.from===t)if(!a.has(o.to))a.add(o.to),n.set(o.to,r+1),i.push(o.to);else{let e=n.get(o.to)??0;r+1>e&&n.set(o.to,r+1)}}let o=Math.max(0,...Array.from(n.values()));for(let t of e.nodes)n.has(t)||n.set(t,o+1);let s=new Map;for(let[e,t]of n)s.has(t)||s.set(t,[]),s.get(t).push(e);let c=[...s.keys()].sort((e,t)=>e-t);for(let e=0;e<c.length;e++){let n=c[e],r=s.get(n)??[];for(let n=0;n<r.length;n++){let i=r[n],a=j+e*54,o=j+n*28;t.set(i,{x:a,y:o})}}return t}function N(e){let t=document.getElementById(`flow-diagram`),n=Array.isArray(e)?e:[];if(!t||!n.length){t?.classList.add(`hidden`);return}let r=O(n);if(r.size===0){t?.classList.add(`hidden`);return}let i=k,a=A,o=``;for(let[e,t]of r){let n=M(t);if(n.size===0)continue;let r=Math.max(...Array.from(n.values()).map(e=>e.x))+i+j*2,s=Math.max(...Array.from(n.values()).map(e=>e.y))+a+j*2,c=`<svg class="flow-diagram-svg" viewBox="0 0 ${Math.max(240,r)} ${Math.max(48,s)}" xmlns="http://www.w3.org/2000/svg">`;for(let{from:e,to:r}of t.edges){let t=n.get(e),o=n.get(r);if(t&&o){let e=t.x+i,n=t.y+a/2,r=o.x,s=o.y+a/2,l=(e+r)/2;c+=`<path d="M ${e} ${n} C ${l} ${n} ${l} ${s} ${r} ${s}" fill="none" stroke="var(--flow-edge)" stroke-width="1" class="flow-edge"/>`;let u=r-4*Math.cos(Math.PI/6),d=s-4*Math.sin(Math.PI/6),f=r-4*Math.cos(-Math.PI/6),p=s-4*Math.sin(-Math.PI/6);c+=`<polygon points="${r},${s} ${u},${d} ${f},${p}" fill="var(--flow-edge)" class="flow-arrow"/>`}}for(let[e,r]of n){let n=e===t.entryNode?`flow-diagram-node entry`:`flow-diagram-node`,o=e.length>10?e.slice(0,8)+`…`:e;c+=`<g class="flow-node-group"><rect class="${n}" x="${r.x}" y="${r.y}" width="${i}" height="${a}" rx="4"/><text x="${r.x+i/2}" y="${r.y+a/2+3}" text-anchor="middle" font-size="9" fill="var(--text-primary)" class="flow-node-label">${_(o)}</text></g>`}c+=`</svg>`,o+=`<div class="flow-diagram-card"><span class="flow-diagram-badge" title="${_(e)}">${_(e)}</span><div class="flow-diagram-svg-wrap">${c}</div></div>`}t.innerHTML=o,t.classList.remove(`hidden`)}function re(e){let t=document.getElementById(`rag-explorer`),n=document.getElementById(`rag-pipeline-select`),r=document.getElementById(`rag-results`);if(!t||!n||!r)return;let i=Array.isArray(e)?e:[];if(!i.length){t.classList.add(`hidden`);return}t.classList.remove(`hidden`),n.innerHTML=i.map(e=>`<option value="${_(String(e.pipelineName??``))}">${_(String(e.pipelineName??``))}</option>`).join(``),r.innerHTML=``}async function P(){let t=document.getElementById(`rag-pipeline-select`),n=document.getElementById(`rag-search-input`),r=document.getElementById(`rag-results`);if(!t||!n||!r)return;let i=t.value,a=n.value.trim();if(a){r.innerHTML=`<p>Searching...</p>`;try{let t=await fetch(`${e}/rag/${encodeURIComponent(i)}/search?q=${encodeURIComponent(a)}`),n=await t.json();if(!t.ok){r.innerHTML=`<p class="error">${_(n.error??`Search failed`)}</p>`;return}let o=n.results??[];if(!o.length){r.innerHTML=`<p>No results found.</p>`;return}r.innerHTML=o.map(e=>`<div class="rag-result-item"><span class="score">${e.score==null?`—`:(e.score*100).toFixed(1)+`%`}</span> ${_(String(e.content??``).slice(0,200))}${String(e.content??``).length>200?`...`:``}</div>`).join(``)}catch(e){r.innerHTML=`<p class="error">${_(String(e))}</p>`}}}function F(e){let t=document.getElementById(`module-graph-container`),n=Array.isArray(e)?e:[];if(!t||!n.length){t?.classList.add(`hidden`);return}let r=new Map,i=[],a=n.map(e=>String(e.moduleName??``)).filter(Boolean),o=[...new Set(a)];o.forEach((e,t)=>{let n=Math.floor(t/4),i=t%4;r.set(e,{x:80+i*120,y:40+n*60})});for(let e of n){let t=String(e.moduleName??``),n=e.imports,a=Array.isArray(n)?n:typeof n==`string`?n.split(/[,;]/).map(e=>e.trim()):[];for(let e of a){let n=String(e).trim();n&&(o.includes(n)||r.has(n))&&(i.push({from:t,to:n}),r.has(n)||r.set(n,{x:80+r.size%4*120,y:40+Math.floor(r.size/4)*60}))}}let s=`<svg class="module-graph-svg" viewBox="0 0 500 ${Math.max(200,Math.ceil(o.length/4)*70)}" xmlns="http://www.w3.org/2000/svg">`;for(let{from:e,to:t}of i){let n=r.get(e),i=r.get(t);n&&i&&(s+=`<line x1="${n.x+50}" y1="${n.y+15}" x2="${i.x+50}" y2="${i.y+15}" stroke="var(--border)" stroke-width="1"/>`)}for(let[e,t]of r)s+=`<rect x="${t.x}" y="${t.y}" width="100" height="30" rx="4" fill="var(--bg-tertiary)" stroke="var(--border)"/>`,s+=`<text x="${t.x+50}" y="${t.y+20}" text-anchor="middle" font-size="11" fill="var(--text-primary)">${_(e.length>12?e.slice(0,10)+`..`:e)}</text>`;s+=`</svg>`,t.innerHTML=s,t.classList.remove(`hidden`)}function I(e,t,n,r,i,a){let o=document.getElementById(e),s=E[e]??{col:n[0],dir:`asc`},c=[...t];a?.sortable&&c.length>0&&c.sort((e,t)=>{let n=e[s.col],r=t[s.col],i=String(n??``).localeCompare(String(r??``),void 0,{numeric:!0});return s.dir===`asc`?i:-i});let l=c.length>D?c.slice(0,D):c,u=c.length>D;if(!t.length){o.innerHTML=`<thead></thead><tbody><tr><td colspan="${n.length+(a?.tryRoute||a?.runAgent?1:0)}" class="empty-state"><p>No entries found</p></td></tr></tbody>`;return}let d=i??{},f=n.map(e=>{let t=e.replace(/([A-Z])/g,` $1`).trim();return`<th class="${a?.sortable?` sortable ${s.col===e?s.dir:``}`:``}" data-col="${e}">${t}</th>`});if(a?.tryRoute&&f.push(`<th>Actions</th>`),a?.runAgent&&f.push(`<th>Actions</th>`),a?.previewPrompt&&f.push(`<th>Actions</th>`),o.innerHTML=`
71
+ <thead><tr>${f.join(``)}</tr></thead>
72
+ <tbody>
73
+ ${l.map(e=>{let t=``;if(a?.tryRoute&&e.fullPath!=null){let n=String(e.fullPath);t=`<td><button class="btn btn-sm try-route" data-method="${String(e.httpMethod??`GET`).toUpperCase()}" data-path="${_(n)}">Try</button></td>`}else if(a?.runAgent&&e.agentName!=null){let n=_(String(e.agentName));t=`<td><button class="btn btn-sm run-agent" data-name="${n}">Run</button> <button class="btn btn-sm timeline-agent" data-name="${n}">Timeline</button></td>`}else a?.previewPrompt&&e.promptKey!=null?t=`<td><button class="btn btn-sm preview-prompt" data-key="${_(String(e.promptKey))}">Preview</button></td>`:(a?.tryRoute||a?.runAgent||a?.previewPrompt)&&(t=`<td></td>`);return`<tr data-id="${e.id??``}" data-json='${JSON.stringify(e).replace(/'/g,`\\'`)}'>
74
+ ${n.map(t=>{let n=e[t],r=d[t];return`<td>${r?r(n,e):String(n??`—`)}</td>`}).join(``)}
75
+ ${t}
76
+ </tr>`}).join(``)}
77
+ </tbody>
78
+ `,u){let e=document.createElement(`tr`);e.innerHTML=`<td colspan="${n.length+(a?.tryRoute||a?.runAgent?1:0)}" class="empty-state"><p>Showing ${D} of ${c.length}. Use search to filter.</p></td>`,o.querySelector(`tbody`).appendChild(e)}o.querySelectorAll(`tbody tr[data-json]`).forEach(e=>{e.addEventListener(`click`,t=>{if(t.target.closest(`button`))return;let n=e.dataset.json;n&&U(JSON.parse(n))})}),o.querySelectorAll(`th.sortable`).forEach(o=>{o.addEventListener(`click`,()=>{let c=o.dataset.col;E[e]={col:c,dir:s.col===c&&s.dir===`asc`?`desc`:`asc`},I(e,t,n,r,i,a)})}),o.querySelectorAll(`.try-route`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),L(e.dataset.method??`GET`,e.dataset.path??`/`)})}),o.querySelectorAll(`.run-agent`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),ie(e.dataset.name??``)})}),o.querySelectorAll(`.timeline-agent`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),B(e.dataset.name??``)})}),o.querySelectorAll(`.preview-prompt`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),ue(e.dataset.key??``)})})}function L(e,n){let r=document.getElementById(`route-test-modal`),i=document.getElementById(`test-url`),a=document.getElementById(`test-method`),o=document.getElementById(`test-body-group`),s=document.getElementById(`test-result`);i.value=`${t}${n}`,a.value=e,o.classList.toggle(`hidden`,e===`GET`),s.classList.add(`hidden`),r.classList.remove(`hidden`)}var R=null;function z(e){let t=document.getElementById(`agent-timeline`);if(t){if(!e.length){t.innerHTML=`<p class="muted">No timeline events yet. Run an agent to stream steps.</p>`;return}t.innerHTML=e.map(e=>{let t=_(String(e.type??``)),n=e.state?`<span class="badge">${_(String(e.state))}</span>`:``,r=e.durationMs==null?``:`<span class="muted">${_(String(e.durationMs))}ms</span>`,i=e.confidence==null?``:`<span class="muted">confidence ${_(String(e.confidence))}</span>`,a=e.tokens==null?``:`<span class="muted">${_(String(e.tokens))} tok</span>`,o=e.cost==null?``:`<span class="muted">$${_(String(e.cost))}</span>`,s=e.prompt?`<pre class="timeline-prompt">${_(String(e.prompt).slice(0,400))}</pre>`:``;return`<div class="timeline-step" data-id="${_(String(e.id??``))}">
79
+ <div class="timeline-step-head"><strong>${t}</strong> ${n} ${r} ${i} ${a} ${o}</div>
80
+ ${s}
81
+ </div>`}).join(``)}}async function B(t){let n=document.getElementById(`agent-timeline`);n&&(n.innerHTML=`<p class="muted">Loading timeline…</p>`);try{let r=await fetch(`${e}/agents/${encodeURIComponent(t)}/timeline`),i=await r.json();if(!r.ok){n&&(n.innerHTML=`<p class="muted">${_(i.error??`Failed`)}</p>`);return}z(i.steps??[])}catch(e){n&&(n.innerHTML=`<p class="muted">${_(String(e))}</p>`)}R&&=(R.close(),null);let r=[];R=new EventSource(`${e}/agents/${encodeURIComponent(t)}/stream`),R.onmessage=e=>{try{let t=JSON.parse(e.data);r.push(t),z(r.slice(-100))}catch{}}}async function ie(t){let n=prompt(`Enter input for agent (or leave empty for empty string):`)??``;B(t);try{let r=await fetch(`${e}/agents/${encodeURIComponent(t)}/run`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({input:n})}),i=await r.json();if(!r.ok){U({error:i.error??`Agent run failed`,status:r.status});return}U({agentName:t,result:i.result});let a=await fetch(`${e}/agents/${encodeURIComponent(t)}/timeline`);a.ok&&z((await a.json()).steps??[])}catch(e){U({error:String(e),agentName:t})}}function ae(e){let t=document.getElementById(`agent-run-timeline`);if(t){if(!e.length){t.innerHTML=`<p class="muted">No timeline steps for this run.</p>`;return}t.innerHTML=e.map(e=>`<div class="timeline-step"><div class="timeline-step-head"><strong>${_(String(e.type??``))}</strong> ${e.state?`<span class="badge">${_(String(e.state))}</span>`:``} ${e.durationMs==null?``:`<span class="muted">${_(String(e.durationMs))}ms</span>`} ${e.cost==null?``:`<span class="muted">$${_(String(e.cost))}</span>`}</div></div>`).join(``)}}async function oe(){let t=document.getElementById(`agent-runs-cost`);if(t)try{let n=await fetch(`${e}/agents/metrics`),r=await n.json();if(!n.ok){t.textContent=r.error??`Metrics unavailable`;return}let i=r.metrics??{},a=i.executions??{},o=i.performance??{},s=i.llm??{};t.innerHTML=[`<strong>Cost / metrics</strong>`,a.total==null?``:`executions: ${_(String(a.total))}`,a.successRate==null?``:`success: ${_(String(a.successRate))}`,o.averageDuration==null?``:`avg latency: ${_(String(o.averageDuration))}ms`,s.totalTokens==null?``:`tokens: ${_(String(s.totalTokens))}`,r.summary?`<span class="muted">${_(String(r.summary))}</span>`:``].filter(Boolean).join(` · `)}catch(e){t.textContent=String(e)}}async function V(){let t=document.getElementById(`agent-runs-table`);if(!t)return;let n=document.getElementById(`agent-runs-filter-agent`)?.value.trim(),r=document.getElementById(`agent-runs-filter-status`)?.value.trim(),i=new URLSearchParams;n&&i.set(`agentName`,n),r&&i.set(`status`,r),t.innerHTML=`<tr><td class="muted">Loading runs…</td></tr>`,await oe();try{let n=await fetch(`${e}/runs${i.toString()?`?${i}`:``}`),r=await n.json();if(!n.ok){t.innerHTML=`<tr><td class="muted">${_(r.error??`Failed`)}</td></tr>`;return}let a=r.runs??[];if(!a.length){t.innerHTML=`<tr><td class="muted">No AgentRun records. Execute an agent with a durable run store configured.</td></tr>`;return}t.innerHTML=`<thead><tr><th>id</th><th>agent</th><th>status</th><th>updated</th><th></th></tr></thead><tbody>${a.map(e=>{let t=String(e.id??``);return`<tr class="agent-run-row" data-id="${_(t)}" style="cursor:pointer">
82
+ <td><code>${_(t.slice(0,8))}…</code></td>
83
+ <td>${_(String(e.agentName??``))}</td>
84
+ <td><span class="badge">${_(String(e.status??``))}</span></td>
85
+ <td class="muted">${_(String(e.updatedAt??``))}</td>
86
+ <td><button type="button" class="btn btn-sm cancel-run" data-id="${_(t)}">Cancel</button></td>
87
+ </tr>`}).join(``)}</tbody>`,t.querySelectorAll(`.agent-run-row`).forEach(e=>{e.addEventListener(`click`,t=>{t.target.closest(`.cancel-run`)||se(e.dataset.id??``)})}),t.querySelectorAll(`.cancel-run`).forEach(t=>{t.addEventListener(`click`,async n=>{n.stopPropagation();let r=t.dataset.id??``;await fetch(`${e}/runs/${encodeURIComponent(r)}/cancel`,{method:`POST`}),await V()})})}catch(e){t.innerHTML=`<tr><td class="muted">${_(String(e))}</td></tr>`}}async function se(t){let n=document.getElementById(`agent-run-detail`),r=document.getElementById(`agent-run-timeline`);n&&(n.innerHTML=`<p class="muted">Loading…</p>`),r&&(r.innerHTML=``);try{let r=await fetch(`${e}/runs/${encodeURIComponent(t)}`),i=await r.json();if(!r.ok){n&&(n.innerHTML=`<p class="muted">${_(i.error??`Failed`)}</p>`);return}n&&(n.innerHTML=`<pre class="detail-json">${_(JSON.stringify(i.run,null,2))}</pre>`),ae(i.steps??[])}catch(e){n&&(n.innerHTML=`<p class="muted">${_(String(e))}</p>`)}}document.getElementById(`agent-runs-refresh`)?.addEventListener(`click`,()=>{V()});function ce(e){let t=document.getElementById(`prompt-playground-modal`),n=document.getElementById(`playground-key`),r=document.getElementById(`playground-vars`),i=document.getElementById(`playground-output`),a=document.getElementById(`playground-tokens`);n.value=e,r.value=`{}`,i.textContent=``,a.textContent=`—`,t.classList.remove(`hidden`)}async function le(t,n){let r=await fetch(`${e}/prompts/render`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({key:t,variables:n})});if(!r.ok){let e=await r.json().catch(()=>({error:r.statusText}));throw Error(e.error??`Failed to render`)}return r.json()}function ue(e){ce(e)}var H=null;function U(e){H=e;let t=document.getElementById(`detail-panel`),n=document.getElementById(`detail-title`),r=document.getElementById(`detail-content`);n.textContent=String(e.kind??`Entry`),r.innerHTML=g(e),t.classList.remove(`hidden`)}function de(){H=null,document.getElementById(`detail-panel`).classList.add(`hidden`)}function fe(){if(!H)return;let e=JSON.stringify(H,null,2);navigator.clipboard.writeText(e).then(()=>{let e=document.getElementById(`detail-copy`);if(e){let t=e.textContent;e.textContent=`Copied!`,setTimeout(()=>{e.textContent=t},1500)}})}function pe(e,t){let n=Array.isArray(e)?e:[];if(!t.trim())return n;let r=t.toLowerCase();return n.filter(e=>JSON.stringify(e).toLowerCase().includes(r))}var W={httpMethod:e=>h(String(e??``))},G={enabled:e=>`<span class="badge ${e?`badge-get`:`badge-default`}">${e?`Enabled`:`Disabled`}</span>`,nextRuns:(e,t)=>{let n=Array.isArray(e)?e:[];return n.length?n.slice(0,3).map(e=>{try{return new Date(e).toLocaleString(void 0,{month:`short`,day:`numeric`,hour:`2-digit`,minute:`2-digit`})}catch{return e}}).join(`, `)+(n.length>3?`...`:``):`—`}},K={moduleName:e=>String(e??`—`),scope:e=>{let t=String(e??`singleton`);return`<span class="badge ${t===`singleton`?`badge-get`:t===`request`?`badge-post`:`badge-default`}">${t}</span>`}},q={tools:e=>Array.isArray(e)?e.join(`, `):String(e??`—`)},J={streaming:e=>`<span class="badge ${e?`badge-get`:`badge-default`}">${e?`Yes`:`No`}</span>`};function Y(e,t){try{t()}catch(t){console.error(`[Inspector] ${e} failed:`,t)}}async function X(e=!1){if(!r){r=!0,u(!0),p(!1);try{let t=await o(e),r=Array.isArray(t?.entries)?t.entries:[],i=t?.summary&&typeof t.summary==`object`?t.summary:{},a=t?.overview&&typeof t.overview==`object`?t.overview:{};n={entries:r,summary:i,overview:a},Y(`overview`,()=>b(i)),a.gateway&&Y(`gatewayOverview`,()=>C(a.gateway)),a.discovery&&Y(`discoveryOverview`,()=>w(a.discovery)),a.resilience&&Y(`resilienceOverview`,()=>ee(a.resilience)),[`overview-gateway`,`overview-discovery`,`overview-resilience`].forEach(e=>{let t=document.getElementById(e);t&&!a[e.replace(`overview-`,``)]&&t.classList.add(`hidden`)});let[u,p,m]=await Promise.all([c(),Promise.all([l(`/health`),l(`/ready`),l(`/startup`)]).then(([e,t,n])=>({health:e,ready:t,startup:n})),s()]);S(u),te(p),ne(m),d(p,m),f(i);let h=n.entries.filter(e=>e.kind===`route`),g=n.entries.filter(e=>e.kind===`module`),_=n.entries.filter(e=>e.kind===`provider`),v=n.entries.filter(e=>e.kind===`cron`),y=n.entries.filter(e=>e.kind===`queue`),x=n.entries.filter(e=>e.kind===`websocket`),T=n.entries.filter(e=>e.kind===`agent`),E=n.entries.filter(e=>e.kind===`rag`),D=n.entries.filter(e=>e.kind===`prompt`),O=n.entries.filter(e=>e.kind===`aifunction`),k=n.entries.filter(e=>e.kind===`event`),A=n.entries.filter(e=>e.kind===`graphql`),j=n.entries.filter(e=>e.kind===`grpc`),M=n.entries.filter(e=>e.kind===`kafka`),P=n.entries.filter(e=>e.kind===`flow`),L=n.entries.filter(e=>e.kind===`data`),R=n.entries.filter(e=>e.kind===`serverless`),z=n.entries.filter(e=>e.kind===`ml`);I(`routes-table`,h,[`httpMethod`,`fullPath`,`controllerPath`,`className`],`route`,W,{sortable:!0,tryRoute:!0}),Y(`moduleGraph`,()=>F(g)),I(Z.modules,g,[`moduleName`,`dynamicModule`,`imports`],`module`,void 0,{sortable:!0}),I(Z.providers,_,[`providerName`,`moduleName`,`scope`],`provider`,K,{sortable:!0}),I(Z.jobs,v,[`jobName`,`cronExpression`,`enabled`,`nextRuns`],`cron`,G),I(Z.queues,y,[`queueName`,`consumerName`,`className`],`queue`),I(Z.websocket,x,[`gatewayName`,`eventName`,`namespace`],`websocket`),I(Z.agents,T,[`agentName`,`className`,`model`,`tools`],`agent`,q,{sortable:!0,runAgent:!0}),I(Z.ai,O,[`className`,`methodName`,`provider`,`model`,`streaming`],`aifunction`,J),Y(`ragExplorer`,()=>re(E)),I(Z.rag,E,[`pipelineName`,`vectorStore`,`embeddingProvider`,`chunkingStrategy`],`rag`,void 0,{sortable:!0}),I(Z.prompts,D,[`promptKey`,`scope`],`prompt`,void 0,{sortable:!0,previewPrompt:!0}),I(Z.events,k,[`eventName`,`className`,`methodName`],`event`),I(Z.graphql,A,[`operationType`,`operationName`,`resolverName`,`className`],`graphql`),I(Z.grpc,j,[`serviceName`,`methodName`,`className`],`grpc`),I(Z.kafka,M,[`consumerName`,`topic`,`groupId`,`methodName`],`kafka`);let B=document.getElementById(`flow-runtime-info`);B&&B.classList.toggle(`hidden`,P.length===0),Y(`flowDiagram`,()=>N(P)),I(Z.flows,P,[`flowId`,`version`,`sourceType`,`nodeName`,`entryNode`,`edges`,`className`],`flow`),I(Z.data,L,[`pipelineName`,`className`],`data`),I(Z.serverless,R,[`controllerName`,`runtime`,`memory`,`timeout`],`serverless`),I(Z.ml,z,[`modelName`,`version`,`className`],`ml`)}catch(e){let t=String(e),n=t.includes(`Failed to fetch`)||t.includes(`NetworkError`)||t.includes(`Load failed`);p(n),d({health:{ok:!1},ready:{ok:!1},startup:{ok:!1}},{}),f({});let r=document.getElementById(`summary-cards`);if(r){let t=n?`Is the app running?`:`A rendering error occurred. Check the console for details.`;r.innerHTML=`<div class="overview-error"><p>Error: ${_(String(e))}</p><p>${_(t)} <button class="btn btn-sm btn-primary" id="retry-load">Retry</button></p></div>`,document.getElementById(`retry-load`)?.addEventListener(`click`,()=>X(!0))}}finally{r=!1,u(!1)}}}var Z={routes:`routes-table`,modules:`modules-table`,providers:`providers-table`,jobs:`jobs-table`,queues:`queues-table`,websocket:`websocket-table`,agents:`agents-table`,ai:`ai-table`,rag:`rag-table`,prompts:`prompts-table`,events:`events-table`,graphql:`graphql-table`,grpc:`grpc-table`,kafka:`kafka-table`,flows:`flows-table`,data:`data-table`,serverless:`serverless-table`,ml:`ml-table`},me={route:`routes`,module:`modules`,provider:`providers`,cron:`jobs`,queue:`queues`,websocket:`websocket`,agent:`agents`,aifunction:`ai`,rag:`rag`,prompt:`prompts`,event:`events`,graphql:`graphql`,grpc:`grpc`,kafka:`kafka`,flow:`flows`,data:`data`,serverless:`serverless`,ml:`ml`};function Q(e){let t=document.querySelector(`.sidebar nav a[data-tab="${e}"]`);if(t){document.querySelectorAll(`.sidebar nav a`).forEach(e=>e.classList.remove(`active`)),document.querySelectorAll(`.tab-panel`).forEach(e=>e.classList.remove(`active`)),t.classList.add(`active`),document.getElementById(e)?.classList.add(`active`);let n=new URLSearchParams(window.location.search);n.set(`tab`,e),window.history.replaceState({},``,`${window.location.pathname}?${n}`),e===`agent-runs`&&V()}}document.querySelectorAll(`.sidebar nav a`).forEach(e=>{e.addEventListener(`click`,t=>{t.preventDefault();let n=e.dataset.tab;Q(n)})}),document.getElementById(`summary-cards`)?.addEventListener(`click`,e=>{let t=e.target.closest(`.card[data-kind]`);if(t){let e=t.dataset.kind,n=e?me[e]:null;n&&Q(n)}});function he(){X(!0)}document.getElementById(`refresh`)?.addEventListener(`click`,he),document.getElementById(`refresh-sidebar`)?.addEventListener(`click`,he),document.getElementById(`detail-close`).addEventListener(`click`,de),document.getElementById(`detail-copy`)?.addEventListener(`click`,fe),document.getElementById(`export-btn`)?.addEventListener(`click`,()=>{if(!n)return;let e=new Blob([JSON.stringify(n,null,2)],{type:`application/json`}),t=document.createElement(`a`);t.href=URL.createObjectURL(e),t.download=`inspector-snapshot-${new Date().toISOString().slice(0,19).replace(/[T:]/g,`-`)}.json`,t.click(),URL.revokeObjectURL(t.href)});var ge=document.getElementById(`auto-refresh`),$=null;ge?.addEventListener(`change`,()=>{$&&clearInterval($),$=null,ge?.checked&&($=setInterval(()=>X(!1),15e3))}),document.getElementById(`test-route-btn`)?.addEventListener(`click`,async()=>{let e=document.getElementById(`test-url`).value,t=document.getElementById(`test-method`).value,n=document.getElementById(`test-body`),r=document.getElementById(`test-result`);r.classList.remove(`hidden`),r.className=`test-result`,r.textContent=`Sending...`;try{let i={method:t};if(t!==`GET`&&n?.value)try{JSON.parse(n.value),i.body=n.value,i.headers={"Content-Type":`application/json`}}catch{r.className=`test-result error`,r.textContent=`Invalid JSON body`;return}let a=await fetch(e,i),o=await a.text();r.className=`test-result ${a.ok?`success`:`error`}`,r.textContent=`Status: ${a.status}\n\n${o.slice(0,500)}${o.length>500?`...`:``}`}catch(e){r.className=`test-result error`,r.textContent=String(e)}}),document.getElementById(`test-route-cancel`)?.addEventListener(`click`,()=>{document.getElementById(`route-test-modal`).classList.add(`hidden`)}),document.getElementById(`test-method`)?.addEventListener(`change`,e=>{let t=e.target.value;document.getElementById(`test-body-group`).classList.toggle(`hidden`,t===`GET`)}),document.getElementById(`playground-render`)?.addEventListener(`click`,async()=>{let e=document.getElementById(`playground-key`).value,t=document.getElementById(`playground-vars`).value,n=document.getElementById(`playground-output`),r=document.getElementById(`playground-tokens`),i={};try{i=t.trim()?JSON.parse(t):{}}catch{n.textContent=`Invalid JSON in variables`,r.textContent=`—`;return}try{let{rendered:t,tokenEstimate:a}=await le(e,i);n.textContent=t,r.textContent=String(a)}catch(e){n.textContent=String(e),r.textContent=`—`}}),document.getElementById(`playground-close`)?.addEventListener(`click`,()=>{document.getElementById(`prompt-playground-modal`).classList.add(`hidden`)}),document.getElementById(`diff-btn`)?.addEventListener(`click`,()=>{document.getElementById(`diff-modal`).classList.remove(`hidden`)}),document.getElementById(`diff-close`)?.addEventListener(`click`,()=>{document.getElementById(`diff-modal`).classList.add(`hidden`)}),document.getElementById(`diff-load-file`)?.addEventListener(`click`,()=>{document.getElementById(`diff-file`).click()}),document.getElementById(`diff-file`)?.addEventListener(`change`,e=>{let t=e.target.files?.[0];if(!t)return;let n=new FileReader;n.onload=()=>{document.getElementById(`diff-snapshot-b`).value=String(n.result)},n.readAsText(t)}),document.getElementById(`rag-search-btn`)?.addEventListener(`click`,P),document.getElementById(`diff-compare-btn`)?.addEventListener(`click`,()=>{let e=document.getElementById(`diff-snapshot-b`).value.trim(),t=document.getElementById(`diff-result`);if(!n){t.innerHTML=`<p class="error">No current snapshot. Refresh first.</p>`,t.classList.remove(`hidden`);return}let r;try{r=e?JSON.parse(e):{entries:[],summary:{}}}catch{t.innerHTML=`<p class="error">Invalid JSON in Snapshot B.</p>`,t.classList.remove(`hidden`);return}let i=n.entries??[],a=r.entries??[],o=new Set(i.map(e=>e.id)),s=new Set(a.map(e=>e.id)),c=a.filter(e=>!o.has(e.id)),l=i.filter(e=>!s.has(e.id)),u=i.filter(e=>{let t=a.find(t=>t.id===e.id);return t&&JSON.stringify(e)!==JSON.stringify(t)}),d=``;c.length&&(d+=`<p class="added">+ ${c.length} added</p><ul>${c.map(e=>`<li>${_(String(e.kind))}: ${_(String(e.id??``))}</li>`).join(``)}</ul>`),l.length&&(d+=`<p class="removed">− ${l.length} removed</p><ul>${l.map(e=>`<li>${_(String(e.kind))}: ${_(String(e.id??``))}</li>`).join(``)}</ul>`),u.length&&(d+=`<p class="changed">~ ${u.length} changed</p><ul>${u.map(e=>`<li>${_(String(e.kind))}: ${_(String(e.id??``))}</li>`).join(``)}</ul>`),d||=`<p>No differences.</p>`,t.innerHTML=d,t.classList.remove(`hidden`)}),document.getElementById(`search`).addEventListener(`input`,e=>{let t=e.target.value;if(!n)return;let r=pe(n.entries,t),i=n.summary&&typeof n.summary==`object`?n.summary:{};b(Object.fromEntries(Object.entries(i).map(([e])=>[e,r.filter(t=>t.kind===e).length])));let a=r.filter(e=>e.kind===`route`),o=r.filter(e=>e.kind===`module`),s=r.filter(e=>e.kind===`provider`),c=r.filter(e=>e.kind===`cron`),l=r.filter(e=>e.kind===`queue`),u=r.filter(e=>e.kind===`websocket`),d=r.filter(e=>e.kind===`agent`),f=r.filter(e=>e.kind===`rag`),p=r.filter(e=>e.kind===`prompt`),m=r.filter(e=>e.kind===`aifunction`),h=r.filter(e=>e.kind===`event`),g=r.filter(e=>e.kind===`graphql`),_=r.filter(e=>e.kind===`grpc`),v=r.filter(e=>e.kind===`kafka`),y=r.filter(e=>e.kind===`flow`),x=r.filter(e=>e.kind===`data`),S=r.filter(e=>e.kind===`serverless`),C=r.filter(e=>e.kind===`ml`);I(`routes-table`,a,[`httpMethod`,`fullPath`,`controllerPath`,`className`],`route`,W,{sortable:!0,tryRoute:!0}),F(o),I(`modules-table`,o,[`moduleName`,`dynamicModule`,`imports`],`module`,void 0,{sortable:!0}),I(`providers-table`,s,[`providerName`,`moduleName`,`scope`],`provider`,K,{sortable:!0}),I(`jobs-table`,c,[`jobName`,`cronExpression`,`enabled`,`nextRuns`],`cron`,G),I(`queues-table`,l,[`queueName`,`consumerName`,`className`],`queue`),I(`websocket-table`,u,[`gatewayName`,`eventName`,`namespace`],`websocket`),I(`agents-table`,d,[`agentName`,`className`,`model`,`tools`],`agent`,q,{sortable:!0,runAgent:!0}),I(`ai-table`,m,[`className`,`methodName`,`provider`,`model`,`streaming`],`aifunction`,J),re(f),I(`rag-table`,f,[`pipelineName`,`vectorStore`,`embeddingProvider`,`chunkingStrategy`],`rag`,void 0,{sortable:!0}),I(`prompts-table`,p,[`promptKey`,`scope`],`prompt`,void 0,{sortable:!0,previewPrompt:!0}),I(`events-table`,h,[`eventName`,`className`,`methodName`],`event`),I(`graphql-table`,g,[`operationType`,`operationName`,`resolverName`,`className`],`graphql`),I(`grpc-table`,_,[`serviceName`,`methodName`,`className`],`grpc`),I(`kafka-table`,v,[`consumerName`,`topic`,`groupId`,`methodName`],`kafka`);let w=document.getElementById(`flow-runtime-info`);w&&w.classList.toggle(`hidden`,y.length===0),N(y),I(`flows-table`,y,[`flowId`,`version`,`sourceType`,`nodeName`,`entryNode`,`edges`,`className`],`flow`,void 0,{sortable:!0}),I(`data-table`,x,[`pipelineName`,`className`],`data`),I(`serverless-table`,S,[`controllerName`,`runtime`,`memory`,`timeout`],`serverless`),I(`ml-table`,C,[`modelName`,`version`,`className`],`ml`)}),X().then(()=>{let e=new URLSearchParams(window.location.search).get(`tab`);e&&Q(e)});
@@ -4,7 +4,7 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1" />
6
6
  <title>HazelJS Inspector</title>
7
- <script type="module" crossorigin src="/__hazel/assets/index-WT8tdMSx.js"></script>
7
+ <script type="module" crossorigin src="/__hazel/assets/index-BMiGVZZN.js"></script>
8
8
  <link rel="stylesheet" crossorigin href="/__hazel/assets/index-DsSZSL8P.css">
9
9
  </head>
10
10
  <body>
@@ -55,6 +55,7 @@
55
55
  <div class="nav-section">
56
56
  <span class="nav-section-title">AI & Intelligence</span>
57
57
  <a href="#" data-tab="agents"><span class="nav-icon"></span>Agents</a>
58
+ <a href="#" data-tab="agent-runs"><span class="nav-icon"></span>Agent Runs</a>
58
59
  <a href="#" data-tab="ai"><span class="nav-icon"></span>AI</a>
59
60
  <a href="#" data-tab="rag"><span class="nav-icon"></span>RAG</a>
60
61
  <a href="#" data-tab="prompts"><span class="nav-icon"></span>Prompts</a>
@@ -164,6 +165,24 @@
164
165
  <div id="agent-timeline" class="agent-timeline"></div>
165
166
  </div>
166
167
  </div>
168
+ <div id="agent-runs" class="tab-panel">
169
+ <h2 class="section-title">Agent Runs</h2>
170
+ <p class="muted" style="font-size:12px;margin:0 0 8px">
171
+ Durable <code>AgentRun</code> records from the runtime repository. Click a row for detail + timeline.
172
+ </p>
173
+ <div id="agent-runs-cost" class="agent-runs-cost muted" style="font-size:12px;margin:0 0 12px"></div>
174
+ <div class="form-group" style="display:flex;gap:8px;flex-wrap:wrap;margin-bottom:12px">
175
+ <input type="text" id="agent-runs-filter-agent" placeholder="Filter agentName" style="min-width:160px" />
176
+ <input type="text" id="agent-runs-filter-status" placeholder="Filter status" style="min-width:120px" />
177
+ <button id="agent-runs-refresh" class="btn btn-sm btn-primary" type="button">Refresh</button>
178
+ </div>
179
+ <div class="table-container"><table id="agent-runs-table"></table></div>
180
+ <div id="agent-run-detail" class="agent-run-detail" style="margin-top:16px"></div>
181
+ <div class="agent-timeline-panel" style="margin-top:12px">
182
+ <h3 class="section-title">Run Timeline</h3>
183
+ <div id="agent-run-timeline" class="agent-timeline"></div>
184
+ </div>
185
+ </div>
167
186
  <div id="ai" class="tab-panel">
168
187
  <h2 class="section-title">AI Functions</h2>
169
188
  <div class="table-container"><table id="ai-table"></table></div>
@@ -1,81 +0,0 @@
1
- (function(){let e=document.createElement(`link`).relList;if(e&&e.supports&&e.supports(`modulepreload`))return;for(let e of document.querySelectorAll(`link[rel="modulepreload"]`))n(e);new MutationObserver(e=>{for(let t of e)if(t.type===`childList`)for(let e of t.addedNodes)e.tagName===`LINK`&&e.rel===`modulepreload`&&n(e)}).observe(document,{childList:!0,subtree:!0});function t(e){let t={};return e.integrity&&(t.integrity=e.integrity),e.referrerPolicy&&(t.referrerPolicy=e.referrerPolicy),e.crossOrigin===`use-credentials`?t.credentials=`include`:e.crossOrigin===`anonymous`?t.credentials=`omit`:t.credentials=`same-origin`,t}function n(e){if(e.ep)return;e.ep=!0;let n=t(e);fetch(e.href,n)}})();var e=(()=>{let e=window.location.pathname.match(/^\/[^/]+/);return e?e[0]:`/__hazel`})(),t=window.location.origin,n=null,r=!1,i=[],a=60;async function o(t=!1){let n=`${e}/inspect${t?`?refresh=1`:``}`,r=await fetch(n);if(!r.ok)throw Error(`Failed to fetch: ${r.status}`);return r.json()}async function s(){let t=await fetch(`${e}/stats`);return t.ok?t.json():{}}async function c(){let t=await fetch(`${e}/env`);return t.ok?t.json():{}}async function l(e){try{let n=await fetch(`${t}${e}`),r=n.ok,i;return i=n.headers.get(`content-type`)?.includes(`application/json`)?await n.json():await n.text(),{status:r?`up`:`down`,ok:r,data:i}}catch{return{status:`down`,ok:!1}}}function u(e){let t=document.getElementById(`loading-overlay`);t&&t.classList.toggle(`hidden`,!e)}function d(e,t){let n=document.getElementById(`status-dot`),r=document.getElementById(`status-text`),i=document.getElementById(`status-uptime`);if(!n||!r||!i)return;let a=e?.health?.ok&&e?.ready?.ok&&e?.startup?.ok,o=e?.health?.ok||e?.ready?.ok||e?.startup?.ok;n.className=`status-dot`+(a?` healthy`:o?``:` unhealthy`),r.textContent=a?`All systems operational`:o?`Degraded`:`Offline`,i.textContent=t.uptimeSeconds==null?``:`Uptime: ${m(t.uptimeSeconds)}`}function f(e){let t=document.getElementById(`quick-stats`);if(!t)return;let n=e&&typeof e==`object`?e:{},r=[];(n.route??0)>0&&r.push(`<span class="quick-stat"><strong>${n.route}</strong> routes</span>`),(n.module??0)>0&&r.push(`<span class="quick-stat"><strong>${n.module}</strong> modules</span>`),(n.provider??0)>0&&r.push(`<span class="quick-stat"><strong>${n.provider}</strong> providers</span>`),(n.cron??0)>0&&r.push(`<span class="quick-stat"><strong>${n.cron}</strong> jobs</span>`),t.innerHTML=r.join(``)||`<span class="quick-stat muted">No data</span>`}function p(e){let t=document.getElementById(`offline-banner`);e&&!t&&(t=document.createElement(`div`),t.id=`offline-banner`,t.className=`offline-banner`,t.innerHTML=`<span>App not running. Check that your server is started.</span><button id="retry-btn">Retry</button>`,document.querySelector(`.content`)?.insertBefore(t,document.querySelector(`.toolbar`)),t.querySelector(`#retry-btn`)?.addEventListener(`click`,()=>Y(!0))),t&&t.classList.toggle(`hidden`,!e)}function m(e){return e<60?`${Math.floor(e)}s`:e<3600?`${Math.floor(e/60)}m ${e%60}s`:`${Math.floor(e/3600)}h ${Math.floor(e%3600/60)}m`}function h(e){let t=String(e||``).toUpperCase();return`<span class="badge badge-${t===`GET`?`get`:t===`POST`?`post`:t===`PUT`?`put`:t===`PATCH`?`patch`:t===`DELETE`?`delete`:`default`}">${t||`?`}</span>`}function g(e){return JSON.stringify(e,null,2).replace(/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+-]?\d+)?)/g,e=>{let t=`json-number`;return/^"/.test(e)?t=e.endsWith(`:`)?`json-key`:`json-string`:/true|false/.test(e)?t=`json-boolean`:/null/.test(e)&&(t=`json-null`),`<span class="${t}">${_(e)}</span>`})}function _(e){let t=document.createElement(`div`);return t.textContent=e,t.innerHTML}var v={route:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/></svg>`,module:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/><polyline points="3.27 6.96 12 12.01 20.73 6.96"/><line x1="12" y1="22.08" x2="12" y2="12"/></svg>`,provider:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3"/><path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5"/></svg>`,cron:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>`,queue:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/></svg>`,websocket:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>`,agent:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="11" width="18" height="10" rx="2"/><circle cx="12" cy="5" r="2"/><path d="M12 7v4"/></svg>`,rag:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/><path d="M8 7h8"/><path d="M8 11h8"/></svg>`,prompt:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"/></svg>`,aifunction:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.663 17h4.673M12 3v1m6.364 1.636l-.707.707M21 12h-1M4 12H3m3.343-5.657l-.707-.707m2.828 9.9a5 5 0 117.072 0l-.548.547A3.374 3.374 0 0014 18.469V19a2 2 0 11-4 0v-.531c0-.895-.356-1.754-.988-2.386l-.548-.547z"/></svg>`,event:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 2v4"/><path d="M16 2v4"/><rect x="3" y="4" width="18" height="18" rx="2"/><path d="M3 10h18"/><path d="M8 14h.01"/><path d="M12 14h.01"/><path d="M16 14h.01"/></svg>`,graphql:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 3v18"/><path d="M5 12h14"/><path d="M3 8l9-5 9 5"/><path d="M3 16l9 5 9-5"/></svg>`,grpc:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="M12 5l7 7-7 7"/></svg>`,kafka:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><path d="M9 9h6"/><path d="M9 13h6"/><path d="M9 17h4"/></svg>`,flow:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="22 12 18 12 15 21 9 3 6 12 2 12"/></svg>`,data:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><line x1="18" y1="20" x2="18" y2="10"/><line x1="12" y1="20" x2="12" y2="4"/><line x1="6" y1="20" x2="6" y2="14"/></svg>`,serverless:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"/></svg>`,ml:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 2v4"/><path d="M12 18v4"/><path d="m4.93 4.93 2.83 2.83"/><path d="m16.24 16.24 2.83 2.83"/><path d="M2 12h4"/><path d="M18 12h4"/><path d="m4.93 19.07 2.83-2.83"/><path d="m16.24 7.76 2.83-2.83"/><circle cx="12" cy="12" r="4"/></svg>`,decorator:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"/><line x1="7" y1="7" x2="7.01" y2="7"/></svg>`},y=[{title:`Framework`,items:[{key:`route`,label:`Routes`},{key:`module`,label:`Modules`},{key:`provider`,label:`Providers`},{key:`decorator`,label:`Decorators`}]},{title:`Scheduled & Async`,items:[{key:`cron`,label:`Cron Jobs`},{key:`queue`,label:`Queues`}]},{title:`AI & Intelligence`,items:[{key:`agent`,label:`Agents`},{key:`aifunction`,label:`AI Functions`},{key:`rag`,label:`RAG`},{key:`prompt`,label:`Prompts`},{key:`ml`,label:`ML`}]},{title:`APIs & Messaging`,items:[{key:`graphql`,label:`GraphQL`},{key:`grpc`,label:`gRPC`},{key:`kafka`,label:`Kafka`},{key:`websocket`,label:`WebSockets`},{key:`event`,label:`Events`}]},{title:`Workflows & Data`,items:[{key:`flow`,label:`Flows`},{key:`data`,label:`Data`},{key:`serverless`,label:`Serverless`}]}];function b(e){let t=document.getElementById(`summary-cards`),n=e&&typeof e==`object`?e:{};t.innerHTML=y.map(e=>`
2
- <section class="overview-section">
3
- <h3 class="overview-section-title">${_(e.title)}</h3>
4
- <div class="overview-section-cards">
5
- ${(Array.isArray(e.items)?e.items:[]).map(e=>`<div class="card" data-kind="${_(e.key)}">
6
- <div class="card-icon">${v[e.key]??``}</div>
7
- <div class="card-label">${_(e.label)}</div>
8
- <div class="card-value">${n[e.key]??0}</div>
9
- </div>`).join(``)}
10
- </div>
11
- </section>
12
- `).join(``)}var x={heap:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2v4"/><path d="M12 18v4"/><path d="m4.93 4.93 2.83 2.83"/><path d="m16.24 16.24 2.83 2.83"/><path d="M2 12h4"/><path d="M18 12h4"/><path d="m4.93 19.07 2.83-2.83"/><path d="m16.24 7.76 2.83-2.83"/><circle cx="12" cy="12" r="4"/></svg>`,rss:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2"/><path d="M8 21h8"/><path d="M12 17v4"/></svg>`,uptime:`<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>`};function S(e){let t=document.getElementById(`env-info`);t&&(t.innerHTML=`
13
- <div class="env-item"><strong>Node</strong> ${_(e.nodeVersion??`—`)}</div>
14
- <div class="env-item"><strong>NODE_ENV</strong> ${_(e.nodeEnv??`—`)}</div>
15
- <div class="env-item"><strong>Inspector</strong> ${_(e.inspectorVersion??`—`)}</div>
16
- <div class="env-item"><strong>Platform</strong> ${_(e.platform??`—`)}</div>
17
- <div class="env-item"><strong>Arch</strong> ${_(e.arch??`—`)}</div>
18
- `)}function C(e){let t=document.getElementById(`overview-gateway`);if(!t)return;let n=Array.isArray(e.routes)?e.routes:[],r=e.metrics;t.innerHTML=`
19
- <h3 class="overview-block-title">Gateway</h3>
20
- <div class="overview-gateway-stats">
21
- <div class="overview-stat"><span class="stat-value">${n.length}</span><span class="stat-label">Routes</span></div>
22
- ${r?`
23
- <div class="overview-stat"><span class="stat-value">${r.totalCalls}</span><span class="stat-label">Total Calls</span></div>
24
- <div class="overview-stat"><span class="stat-value">${r.successCalls}</span><span class="stat-label">Success</span></div>
25
- <div class="overview-stat"><span class="stat-value">${(r.failureRate??0).toFixed(1)}%</span><span class="stat-label">Failure Rate</span></div>
26
- <div class="overview-stat"><span class="stat-value">${(r.averageResponseTime??0).toFixed(0)}ms</span><span class="stat-label">Avg Latency</span></div>
27
- `:``}
28
- </div>
29
- ${n.length?`<div class="overview-gateway-routes"><strong>Routes:</strong> ${n.slice(0,8).map(e=>`<code>${_(e)}</code>`).join(`, `)}${n.length>8?` <span class="muted">+${n.length-8} more</span>`:``}</div>`:``}
30
- `,t.classList.remove(`hidden`)}function w(e){let t=document.getElementById(`overview-discovery`);if(!t)return;let n=Array.isArray(e.services)?e.services:[],r=e.instancesByService&&typeof e.instancesByService==`object`?e.instancesByService:{},i=n.slice(0,6).map(e=>`<span class="discovery-service"><code>${_(e)}</code>: ${r[e]??0} instance(s)</span>`).join(`, `);t.innerHTML=`
31
- <h3 class="overview-block-title">Discovery</h3>
32
- <div class="overview-discovery-stats">
33
- <div class="overview-stat"><span class="stat-value">${e.totalServices??0}</span><span class="stat-label">Services</span></div>
34
- <div class="overview-stat"><span class="stat-value">${e.totalInstances??0}</span><span class="stat-label">Connected Instances</span></div>
35
- </div>
36
- ${n.length?`<div class="overview-discovery-services">${i}${n.length>6?` <span class="muted">+${n.length-6} more</span>`:``}</div>`:`<p class="muted">No services registered</p>`}
37
- `,t.classList.remove(`hidden`)}function ee(e){let t=document.getElementById(`overview-resilience`);if(!t)return;let n=Array.isArray(e.circuitBreakerStates)?e.circuitBreakerStates:[],r=n.map(e=>`<span class="cb-state ${(e.state||``).toLowerCase()}"><code>${_(e.name)}</code>: ${_(e.state)}</span>`).join(`, `);t.innerHTML=`
38
- <h3 class="overview-block-title">Resilience</h3>
39
- <div class="overview-resilience-stats">
40
- <div class="overview-stat"><span class="stat-value">${e.circuitBreakers??0}</span><span class="stat-label">Circuit Breakers</span></div>
41
- </div>
42
- ${n.length?`<div class="overview-resilience-states">${r}</div>`:``}
43
- `,t.classList.remove(`hidden`)}function te(e){let t=document.getElementById(`health-cards`);t&&(t.innerHTML=[{key:`health`,endpoint:`/health`,label:`Health`,data:e.health},{key:`ready`,endpoint:`/ready`,label:`Ready`,data:e.ready},{key:`startup`,endpoint:`/startup`,label:`Startup`,data:e.startup}].map(e=>{let t=e.data??{status:`unknown`,ok:!1};return`
44
- <div class="health-card ${t.ok?`healthy`:t.status===`unknown`?`unknown`:`unhealthy`}">
45
- <h3>${_(e.label)}</h3>
46
- <div class="status">${t.ok?`Up`:t.status===`unknown`?`Unknown`:`Down`}</div>
47
- <div class="endpoint">${_(e.endpoint)}</div>
48
- </div>
49
- `}).join(``))}function ne(e){let t=document.getElementById(`runtime-cards`),n=e=>(e/1024/1024).toFixed(2);e.memory&&(i.push({heap:e.memory.heapUsed,rss:e.memory.rss,t:Date.now()}),i.length>a&&i.shift()),t.innerHTML=`
50
- <div class="card">
51
- <div class="card-icon">${x.heap}</div>
52
- <div class="card-label">Heap Used</div>
53
- <div class="card-value">${e.memory?.heapUsed?n(e.memory.heapUsed)+` MB`:`—`}</div>
54
- </div>
55
- <div class="card">
56
- <div class="card-icon">${x.rss}</div>
57
- <div class="card-label">RSS Memory</div>
58
- <div class="card-value">${e.memory?.rss?n(e.memory.rss)+` MB`:`—`}</div>
59
- </div>
60
- <div class="card">
61
- <div class="card-icon">${x.uptime}</div>
62
- <div class="card-label">Uptime</div>
63
- <div class="card-value highlight">${e.uptimeSeconds==null?`—`:m(e.uptimeSeconds)}</div>
64
- </div>
65
- `,T()}function T(){let e=document.getElementById(`memory-chart-container`);if(!e||i.length<2){e?.classList.add(`hidden`);return}e.classList.remove(`hidden`);let t=Math.max(...i.map(e=>e.heap)),n=Math.max(...i.map(e=>e.rss)),r=Math.max(t,n,1),a=e=>e/1024/1024/r*100;e.innerHTML=`
66
- <svg width="100%" height="100%" viewBox="0 0 400 180" preserveAspectRatio="none">
67
- <polyline fill="none" stroke="var(--accent)" stroke-width="2" points="${i.map((e,t)=>`${t/(i.length-1)*100},${100-a(e.heap)}`).join(` `)}"/>
68
- </svg>
69
- <div style="font-size:11px;color:var(--text-muted);margin-top:0.5rem">Heap over time (last ${i.length} samples)</div>
70
- `}var E={},D=50;function O(e){let t=new Map;for(let n of e){let e=String(n.flowId??``);t.has(e)||t.set(e,[]),t.get(e).push(n)}let n=new Map;for(let[e,r]of t){let t=r.find(e=>!!String(e.nodes??``).trim())??r[0],i=(t.nodes??``).split(/[,]/).map(e=>e.trim()).filter(Boolean);i.length===0&&(i=r.map(e=>e.nodeName).filter(e=>!!e));let a=(t.edges??``).toString().split(/[;,]/).map(e=>e.trim()).filter(Boolean).map(e=>{let t=e.indexOf(`→`);if(t<0)return null;let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();return n&&r?{from:n,to:r}:null}).filter(e=>e!=null);for(let e of r){let t=(e.edges??``).toString().split(/[;,]/);for(let e of t){let t=e.indexOf(`→`);if(t>=0){let n=e.slice(0,t).trim(),r=e.slice(t+1).trim();n&&r&&!a.some(e=>e.from===n&&e.to===r)&&a.push({from:n,to:r})}}}let o=String(t.entryNode??i[0]??``);n.set(e,{nodes:[...new Set(i)],edges:a,entryNode:o})}return n}var k=48,re=24,A=6;function j(e){let t=new Map,n=new Map,r=e.entryNode||e.nodes[0];if(!r)return t;n.set(r,0);let i=[r],a=new Set([r]);for(;i.length>0;){let t=i.shift(),r=n.get(t)??0;for(let o of e.edges)if(o.from===t)if(!a.has(o.to))a.add(o.to),n.set(o.to,r+1),i.push(o.to);else{let e=n.get(o.to)??0;r+1>e&&n.set(o.to,r+1)}}let o=Math.max(0,...Array.from(n.values()));for(let t of e.nodes)n.has(t)||n.set(t,o+1);let s=new Map;for(let[e,t]of n)s.has(t)||s.set(t,[]),s.get(t).push(e);let c=[...s.keys()].sort((e,t)=>e-t);for(let e=0;e<c.length;e++){let n=c[e],r=s.get(n)??[];for(let n=0;n<r.length;n++){let i=r[n],a=A+e*54,o=A+n*28;t.set(i,{x:a,y:o})}}return t}function M(e){let t=document.getElementById(`flow-diagram`),n=Array.isArray(e)?e:[];if(!t||!n.length){t?.classList.add(`hidden`);return}let r=O(n);if(r.size===0){t?.classList.add(`hidden`);return}let i=k,a=re,o=``;for(let[e,t]of r){let n=j(t);if(n.size===0)continue;let r=Math.max(...Array.from(n.values()).map(e=>e.x))+i+A*2,s=Math.max(...Array.from(n.values()).map(e=>e.y))+a+A*2,c=`<svg class="flow-diagram-svg" viewBox="0 0 ${Math.max(240,r)} ${Math.max(48,s)}" xmlns="http://www.w3.org/2000/svg">`;for(let{from:e,to:r}of t.edges){let t=n.get(e),o=n.get(r);if(t&&o){let e=t.x+i,n=t.y+a/2,r=o.x,s=o.y+a/2,l=(e+r)/2;c+=`<path d="M ${e} ${n} C ${l} ${n} ${l} ${s} ${r} ${s}" fill="none" stroke="var(--flow-edge)" stroke-width="1" class="flow-edge"/>`;let u=r-4*Math.cos(Math.PI/6),d=s-4*Math.sin(Math.PI/6),f=r-4*Math.cos(-Math.PI/6),p=s-4*Math.sin(-Math.PI/6);c+=`<polygon points="${r},${s} ${u},${d} ${f},${p}" fill="var(--flow-edge)" class="flow-arrow"/>`}}for(let[e,r]of n){let n=e===t.entryNode?`flow-diagram-node entry`:`flow-diagram-node`,o=e.length>10?e.slice(0,8)+`…`:e;c+=`<g class="flow-node-group"><rect class="${n}" x="${r.x}" y="${r.y}" width="${i}" height="${a}" rx="4"/><text x="${r.x+i/2}" y="${r.y+a/2+3}" text-anchor="middle" font-size="9" fill="var(--text-primary)" class="flow-node-label">${_(o)}</text></g>`}c+=`</svg>`,o+=`<div class="flow-diagram-card"><span class="flow-diagram-badge" title="${_(e)}">${_(e)}</span><div class="flow-diagram-svg-wrap">${c}</div></div>`}t.innerHTML=o,t.classList.remove(`hidden`)}function N(e){let t=document.getElementById(`rag-explorer`),n=document.getElementById(`rag-pipeline-select`),r=document.getElementById(`rag-results`);if(!t||!n||!r)return;let i=Array.isArray(e)?e:[];if(!i.length){t.classList.add(`hidden`);return}t.classList.remove(`hidden`),n.innerHTML=i.map(e=>`<option value="${_(String(e.pipelineName??``))}">${_(String(e.pipelineName??``))}</option>`).join(``),r.innerHTML=``}async function P(){let t=document.getElementById(`rag-pipeline-select`),n=document.getElementById(`rag-search-input`),r=document.getElementById(`rag-results`);if(!t||!n||!r)return;let i=t.value,a=n.value.trim();if(a){r.innerHTML=`<p>Searching...</p>`;try{let t=await fetch(`${e}/rag/${encodeURIComponent(i)}/search?q=${encodeURIComponent(a)}`),n=await t.json();if(!t.ok){r.innerHTML=`<p class="error">${_(n.error??`Search failed`)}</p>`;return}let o=n.results??[];if(!o.length){r.innerHTML=`<p>No results found.</p>`;return}r.innerHTML=o.map(e=>`<div class="rag-result-item"><span class="score">${e.score==null?`—`:(e.score*100).toFixed(1)+`%`}</span> ${_(String(e.content??``).slice(0,200))}${String(e.content??``).length>200?`...`:``}</div>`).join(``)}catch(e){r.innerHTML=`<p class="error">${_(String(e))}</p>`}}}function F(e){let t=document.getElementById(`module-graph-container`),n=Array.isArray(e)?e:[];if(!t||!n.length){t?.classList.add(`hidden`);return}let r=new Map,i=[],a=n.map(e=>String(e.moduleName??``)).filter(Boolean),o=[...new Set(a)];o.forEach((e,t)=>{let n=Math.floor(t/4),i=t%4;r.set(e,{x:80+i*120,y:40+n*60})});for(let e of n){let t=String(e.moduleName??``),n=e.imports,a=Array.isArray(n)?n:typeof n==`string`?n.split(/[,;]/).map(e=>e.trim()):[];for(let e of a){let n=String(e).trim();n&&(o.includes(n)||r.has(n))&&(i.push({from:t,to:n}),r.has(n)||r.set(n,{x:80+r.size%4*120,y:40+Math.floor(r.size/4)*60}))}}let s=`<svg class="module-graph-svg" viewBox="0 0 500 ${Math.max(200,Math.ceil(o.length/4)*70)}" xmlns="http://www.w3.org/2000/svg">`;for(let{from:e,to:t}of i){let n=r.get(e),i=r.get(t);n&&i&&(s+=`<line x1="${n.x+50}" y1="${n.y+15}" x2="${i.x+50}" y2="${i.y+15}" stroke="var(--border)" stroke-width="1"/>`)}for(let[e,t]of r)s+=`<rect x="${t.x}" y="${t.y}" width="100" height="30" rx="4" fill="var(--bg-tertiary)" stroke="var(--border)"/>`,s+=`<text x="${t.x+50}" y="${t.y+20}" text-anchor="middle" font-size="11" fill="var(--text-primary)">${_(e.length>12?e.slice(0,10)+`..`:e)}</text>`;s+=`</svg>`,t.innerHTML=s,t.classList.remove(`hidden`)}function I(e,t,n,r,i,a){let o=document.getElementById(e),s=E[e]??{col:n[0],dir:`asc`},c=[...t];a?.sortable&&c.length>0&&c.sort((e,t)=>{let n=e[s.col],r=t[s.col],i=String(n??``).localeCompare(String(r??``),void 0,{numeric:!0});return s.dir===`asc`?i:-i});let l=c.length>D?c.slice(0,D):c,u=c.length>D;if(!t.length){o.innerHTML=`<thead></thead><tbody><tr><td colspan="${n.length+(a?.tryRoute||a?.runAgent?1:0)}" class="empty-state"><p>No entries found</p></td></tr></tbody>`;return}let d=i??{},f=n.map(e=>{let t=e.replace(/([A-Z])/g,` $1`).trim();return`<th class="${a?.sortable?` sortable ${s.col===e?s.dir:``}`:``}" data-col="${e}">${t}</th>`});if(a?.tryRoute&&f.push(`<th>Actions</th>`),a?.runAgent&&f.push(`<th>Actions</th>`),a?.previewPrompt&&f.push(`<th>Actions</th>`),o.innerHTML=`
71
- <thead><tr>${f.join(``)}</tr></thead>
72
- <tbody>
73
- ${l.map(e=>{let t=``;if(a?.tryRoute&&e.fullPath!=null){let n=String(e.fullPath);t=`<td><button class="btn btn-sm try-route" data-method="${String(e.httpMethod??`GET`).toUpperCase()}" data-path="${_(n)}">Try</button></td>`}else if(a?.runAgent&&e.agentName!=null){let n=_(String(e.agentName));t=`<td><button class="btn btn-sm run-agent" data-name="${n}">Run</button> <button class="btn btn-sm timeline-agent" data-name="${n}">Timeline</button></td>`}else a?.previewPrompt&&e.promptKey!=null?t=`<td><button class="btn btn-sm preview-prompt" data-key="${_(String(e.promptKey))}">Preview</button></td>`:(a?.tryRoute||a?.runAgent||a?.previewPrompt)&&(t=`<td></td>`);return`<tr data-id="${e.id??``}" data-json='${JSON.stringify(e).replace(/'/g,`\\'`)}'>
74
- ${n.map(t=>{let n=e[t],r=d[t];return`<td>${r?r(n,e):String(n??`—`)}</td>`}).join(``)}
75
- ${t}
76
- </tr>`}).join(``)}
77
- </tbody>
78
- `,u){let e=document.createElement(`tr`);e.innerHTML=`<td colspan="${n.length+(a?.tryRoute||a?.runAgent?1:0)}" class="empty-state"><p>Showing ${D} of ${c.length}. Use search to filter.</p></td>`,o.querySelector(`tbody`).appendChild(e)}o.querySelectorAll(`tbody tr[data-json]`).forEach(e=>{e.addEventListener(`click`,t=>{if(t.target.closest(`button`))return;let n=e.dataset.json;n&&H(JSON.parse(n))})}),o.querySelectorAll(`th.sortable`).forEach(o=>{o.addEventListener(`click`,()=>{let c=o.dataset.col;E[e]={col:c,dir:s.col===c&&s.dir===`asc`?`desc`:`asc`},I(e,t,n,r,i,a)})}),o.querySelectorAll(`.try-route`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),L(e.dataset.method??`GET`,e.dataset.path??`/`)})}),o.querySelectorAll(`.run-agent`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),ie(e.dataset.name??``)})}),o.querySelectorAll(`.timeline-agent`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),B(e.dataset.name??``)})}),o.querySelectorAll(`.preview-prompt`).forEach(e=>{e.addEventListener(`click`,t=>{t.stopPropagation(),se(e.dataset.key??``)})})}function L(e,n){let r=document.getElementById(`route-test-modal`),i=document.getElementById(`test-url`),a=document.getElementById(`test-method`),o=document.getElementById(`test-body-group`),s=document.getElementById(`test-result`);i.value=`${t}${n}`,a.value=e,o.classList.toggle(`hidden`,e===`GET`),s.classList.add(`hidden`),r.classList.remove(`hidden`)}var R=null;function z(e){let t=document.getElementById(`agent-timeline`);if(t){if(!e.length){t.innerHTML=`<p class="muted">No timeline events yet. Run an agent to stream steps.</p>`;return}t.innerHTML=e.map(e=>{let t=_(String(e.type??``)),n=e.state?`<span class="badge">${_(String(e.state))}</span>`:``,r=e.durationMs==null?``:`<span class="muted">${_(String(e.durationMs))}ms</span>`,i=e.confidence==null?``:`<span class="muted">confidence ${_(String(e.confidence))}</span>`,a=e.tokens==null?``:`<span class="muted">${_(String(e.tokens))} tok</span>`,o=e.cost==null?``:`<span class="muted">$${_(String(e.cost))}</span>`,s=e.prompt?`<pre class="timeline-prompt">${_(String(e.prompt).slice(0,400))}</pre>`:``;return`<div class="timeline-step" data-id="${_(String(e.id??``))}">
79
- <div class="timeline-step-head"><strong>${t}</strong> ${n} ${r} ${i} ${a} ${o}</div>
80
- ${s}
81
- </div>`}).join(``)}}async function B(t){let n=document.getElementById(`agent-timeline`);n&&(n.innerHTML=`<p class="muted">Loading timeline…</p>`);try{let r=await fetch(`${e}/agents/${encodeURIComponent(t)}/timeline`),i=await r.json();if(!r.ok){n&&(n.innerHTML=`<p class="muted">${_(i.error??`Failed`)}</p>`);return}z(i.steps??[])}catch(e){n&&(n.innerHTML=`<p class="muted">${_(String(e))}</p>`)}R&&=(R.close(),null);let r=[];R=new EventSource(`${e}/agents/${encodeURIComponent(t)}/stream`),R.onmessage=e=>{try{let t=JSON.parse(e.data);r.push(t),z(r.slice(-100))}catch{}}}async function ie(t){let n=prompt(`Enter input for agent (or leave empty for empty string):`)??``;B(t);try{let r=await fetch(`${e}/agents/${encodeURIComponent(t)}/run`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({input:n})}),i=await r.json();if(!r.ok){H({error:i.error??`Agent run failed`,status:r.status});return}H({agentName:t,result:i.result});let a=await fetch(`${e}/agents/${encodeURIComponent(t)}/timeline`);a.ok&&z((await a.json()).steps??[])}catch(e){H({error:String(e),agentName:t})}}function ae(e){let t=document.getElementById(`prompt-playground-modal`),n=document.getElementById(`playground-key`),r=document.getElementById(`playground-vars`),i=document.getElementById(`playground-output`),a=document.getElementById(`playground-tokens`);n.value=e,r.value=`{}`,i.textContent=``,a.textContent=`—`,t.classList.remove(`hidden`)}async function oe(t,n){let r=await fetch(`${e}/prompts/render`,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({key:t,variables:n})});if(!r.ok){let e=await r.json().catch(()=>({error:r.statusText}));throw Error(e.error??`Failed to render`)}return r.json()}function se(e){ae(e)}var V=null;function H(e){V=e;let t=document.getElementById(`detail-panel`),n=document.getElementById(`detail-title`),r=document.getElementById(`detail-content`);n.textContent=String(e.kind??`Entry`),r.innerHTML=g(e),t.classList.remove(`hidden`)}function ce(){V=null,document.getElementById(`detail-panel`).classList.add(`hidden`)}function le(){if(!V)return;let e=JSON.stringify(V,null,2);navigator.clipboard.writeText(e).then(()=>{let e=document.getElementById(`detail-copy`);if(e){let t=e.textContent;e.textContent=`Copied!`,setTimeout(()=>{e.textContent=t},1500)}})}function ue(e,t){let n=Array.isArray(e)?e:[];if(!t.trim())return n;let r=t.toLowerCase();return n.filter(e=>JSON.stringify(e).toLowerCase().includes(r))}var U={httpMethod:e=>h(String(e??``))},W={enabled:e=>`<span class="badge ${e?`badge-get`:`badge-default`}">${e?`Enabled`:`Disabled`}</span>`,nextRuns:(e,t)=>{let n=Array.isArray(e)?e:[];return n.length?n.slice(0,3).map(e=>{try{return new Date(e).toLocaleString(void 0,{month:`short`,day:`numeric`,hour:`2-digit`,minute:`2-digit`})}catch{return e}}).join(`, `)+(n.length>3?`...`:``):`—`}},G={moduleName:e=>String(e??`—`),scope:e=>{let t=String(e??`singleton`);return`<span class="badge ${t===`singleton`?`badge-get`:t===`request`?`badge-post`:`badge-default`}">${t}</span>`}},K={tools:e=>Array.isArray(e)?e.join(`, `):String(e??`—`)},q={streaming:e=>`<span class="badge ${e?`badge-get`:`badge-default`}">${e?`Yes`:`No`}</span>`};function J(e,t){try{t()}catch(t){console.error(`[Inspector] ${e} failed:`,t)}}async function Y(e=!1){if(!r){r=!0,u(!0),p(!1);try{let t=await o(e),r=Array.isArray(t?.entries)?t.entries:[],i=t?.summary&&typeof t.summary==`object`?t.summary:{},a=t?.overview&&typeof t.overview==`object`?t.overview:{};n={entries:r,summary:i,overview:a},J(`overview`,()=>b(i)),a.gateway&&J(`gatewayOverview`,()=>C(a.gateway)),a.discovery&&J(`discoveryOverview`,()=>w(a.discovery)),a.resilience&&J(`resilienceOverview`,()=>ee(a.resilience)),[`overview-gateway`,`overview-discovery`,`overview-resilience`].forEach(e=>{let t=document.getElementById(e);t&&!a[e.replace(`overview-`,``)]&&t.classList.add(`hidden`)});let[u,p,m]=await Promise.all([c(),Promise.all([l(`/health`),l(`/ready`),l(`/startup`)]).then(([e,t,n])=>({health:e,ready:t,startup:n})),s()]);S(u),te(p),ne(m),d(p,m),f(i);let h=n.entries.filter(e=>e.kind===`route`),g=n.entries.filter(e=>e.kind===`module`),_=n.entries.filter(e=>e.kind===`provider`),v=n.entries.filter(e=>e.kind===`cron`),y=n.entries.filter(e=>e.kind===`queue`),x=n.entries.filter(e=>e.kind===`websocket`),T=n.entries.filter(e=>e.kind===`agent`),E=n.entries.filter(e=>e.kind===`rag`),D=n.entries.filter(e=>e.kind===`prompt`),O=n.entries.filter(e=>e.kind===`aifunction`),k=n.entries.filter(e=>e.kind===`event`),re=n.entries.filter(e=>e.kind===`graphql`),A=n.entries.filter(e=>e.kind===`grpc`),j=n.entries.filter(e=>e.kind===`kafka`),P=n.entries.filter(e=>e.kind===`flow`),L=n.entries.filter(e=>e.kind===`data`),R=n.entries.filter(e=>e.kind===`serverless`),z=n.entries.filter(e=>e.kind===`ml`);I(`routes-table`,h,[`httpMethod`,`fullPath`,`controllerPath`,`className`],`route`,U,{sortable:!0,tryRoute:!0}),J(`moduleGraph`,()=>F(g)),I(X.modules,g,[`moduleName`,`dynamicModule`,`imports`],`module`,void 0,{sortable:!0}),I(X.providers,_,[`providerName`,`moduleName`,`scope`],`provider`,G,{sortable:!0}),I(X.jobs,v,[`jobName`,`cronExpression`,`enabled`,`nextRuns`],`cron`,W),I(X.queues,y,[`queueName`,`consumerName`,`className`],`queue`),I(X.websocket,x,[`gatewayName`,`eventName`,`namespace`],`websocket`),I(X.agents,T,[`agentName`,`className`,`model`,`tools`],`agent`,K,{sortable:!0,runAgent:!0}),I(X.ai,O,[`className`,`methodName`,`provider`,`model`,`streaming`],`aifunction`,q),J(`ragExplorer`,()=>N(E)),I(X.rag,E,[`pipelineName`,`vectorStore`,`embeddingProvider`,`chunkingStrategy`],`rag`,void 0,{sortable:!0}),I(X.prompts,D,[`promptKey`,`scope`],`prompt`,void 0,{sortable:!0,previewPrompt:!0}),I(X.events,k,[`eventName`,`className`,`methodName`],`event`),I(X.graphql,re,[`operationType`,`operationName`,`resolverName`,`className`],`graphql`),I(X.grpc,A,[`serviceName`,`methodName`,`className`],`grpc`),I(X.kafka,j,[`consumerName`,`topic`,`groupId`,`methodName`],`kafka`);let B=document.getElementById(`flow-runtime-info`);B&&B.classList.toggle(`hidden`,P.length===0),J(`flowDiagram`,()=>M(P)),I(X.flows,P,[`flowId`,`version`,`sourceType`,`nodeName`,`entryNode`,`edges`,`className`],`flow`),I(X.data,L,[`pipelineName`,`className`],`data`),I(X.serverless,R,[`controllerName`,`runtime`,`memory`,`timeout`],`serverless`),I(X.ml,z,[`modelName`,`version`,`className`],`ml`)}catch(e){let t=String(e),n=t.includes(`Failed to fetch`)||t.includes(`NetworkError`)||t.includes(`Load failed`);p(n),d({health:{ok:!1},ready:{ok:!1},startup:{ok:!1}},{}),f({});let r=document.getElementById(`summary-cards`);if(r){let t=n?`Is the app running?`:`A rendering error occurred. Check the console for details.`;r.innerHTML=`<div class="overview-error"><p>Error: ${_(String(e))}</p><p>${_(t)} <button class="btn btn-sm btn-primary" id="retry-load">Retry</button></p></div>`,document.getElementById(`retry-load`)?.addEventListener(`click`,()=>Y(!0))}}finally{r=!1,u(!1)}}}var X={routes:`routes-table`,modules:`modules-table`,providers:`providers-table`,jobs:`jobs-table`,queues:`queues-table`,websocket:`websocket-table`,agents:`agents-table`,ai:`ai-table`,rag:`rag-table`,prompts:`prompts-table`,events:`events-table`,graphql:`graphql-table`,grpc:`grpc-table`,kafka:`kafka-table`,flows:`flows-table`,data:`data-table`,serverless:`serverless-table`,ml:`ml-table`},de={route:`routes`,module:`modules`,provider:`providers`,cron:`jobs`,queue:`queues`,websocket:`websocket`,agent:`agents`,aifunction:`ai`,rag:`rag`,prompt:`prompts`,event:`events`,graphql:`graphql`,grpc:`grpc`,kafka:`kafka`,flow:`flows`,data:`data`,serverless:`serverless`,ml:`ml`};function Z(e){let t=document.querySelector(`.sidebar nav a[data-tab="${e}"]`);if(t){document.querySelectorAll(`.sidebar nav a`).forEach(e=>e.classList.remove(`active`)),document.querySelectorAll(`.tab-panel`).forEach(e=>e.classList.remove(`active`)),t.classList.add(`active`),document.getElementById(e)?.classList.add(`active`);let n=new URLSearchParams(window.location.search);n.set(`tab`,e),window.history.replaceState({},``,`${window.location.pathname}?${n}`)}}document.querySelectorAll(`.sidebar nav a`).forEach(e=>{e.addEventListener(`click`,t=>{t.preventDefault();let n=e.dataset.tab;Z(n)})}),document.getElementById(`summary-cards`)?.addEventListener(`click`,e=>{let t=e.target.closest(`.card[data-kind]`);if(t){let e=t.dataset.kind,n=e?de[e]:null;n&&Z(n)}});function Q(){Y(!0)}document.getElementById(`refresh`)?.addEventListener(`click`,Q),document.getElementById(`refresh-sidebar`)?.addEventListener(`click`,Q),document.getElementById(`detail-close`).addEventListener(`click`,ce),document.getElementById(`detail-copy`)?.addEventListener(`click`,le),document.getElementById(`export-btn`)?.addEventListener(`click`,()=>{if(!n)return;let e=new Blob([JSON.stringify(n,null,2)],{type:`application/json`}),t=document.createElement(`a`);t.href=URL.createObjectURL(e),t.download=`inspector-snapshot-${new Date().toISOString().slice(0,19).replace(/[T:]/g,`-`)}.json`,t.click(),URL.revokeObjectURL(t.href)});var fe=document.getElementById(`auto-refresh`),$=null;fe?.addEventListener(`change`,()=>{$&&clearInterval($),$=null,fe?.checked&&($=setInterval(()=>Y(!1),15e3))}),document.getElementById(`test-route-btn`)?.addEventListener(`click`,async()=>{let e=document.getElementById(`test-url`).value,t=document.getElementById(`test-method`).value,n=document.getElementById(`test-body`),r=document.getElementById(`test-result`);r.classList.remove(`hidden`),r.className=`test-result`,r.textContent=`Sending...`;try{let i={method:t};if(t!==`GET`&&n?.value)try{JSON.parse(n.value),i.body=n.value,i.headers={"Content-Type":`application/json`}}catch{r.className=`test-result error`,r.textContent=`Invalid JSON body`;return}let a=await fetch(e,i),o=await a.text();r.className=`test-result ${a.ok?`success`:`error`}`,r.textContent=`Status: ${a.status}\n\n${o.slice(0,500)}${o.length>500?`...`:``}`}catch(e){r.className=`test-result error`,r.textContent=String(e)}}),document.getElementById(`test-route-cancel`)?.addEventListener(`click`,()=>{document.getElementById(`route-test-modal`).classList.add(`hidden`)}),document.getElementById(`test-method`)?.addEventListener(`change`,e=>{let t=e.target.value;document.getElementById(`test-body-group`).classList.toggle(`hidden`,t===`GET`)}),document.getElementById(`playground-render`)?.addEventListener(`click`,async()=>{let e=document.getElementById(`playground-key`).value,t=document.getElementById(`playground-vars`).value,n=document.getElementById(`playground-output`),r=document.getElementById(`playground-tokens`),i={};try{i=t.trim()?JSON.parse(t):{}}catch{n.textContent=`Invalid JSON in variables`,r.textContent=`—`;return}try{let{rendered:t,tokenEstimate:a}=await oe(e,i);n.textContent=t,r.textContent=String(a)}catch(e){n.textContent=String(e),r.textContent=`—`}}),document.getElementById(`playground-close`)?.addEventListener(`click`,()=>{document.getElementById(`prompt-playground-modal`).classList.add(`hidden`)}),document.getElementById(`diff-btn`)?.addEventListener(`click`,()=>{document.getElementById(`diff-modal`).classList.remove(`hidden`)}),document.getElementById(`diff-close`)?.addEventListener(`click`,()=>{document.getElementById(`diff-modal`).classList.add(`hidden`)}),document.getElementById(`diff-load-file`)?.addEventListener(`click`,()=>{document.getElementById(`diff-file`).click()}),document.getElementById(`diff-file`)?.addEventListener(`change`,e=>{let t=e.target.files?.[0];if(!t)return;let n=new FileReader;n.onload=()=>{document.getElementById(`diff-snapshot-b`).value=String(n.result)},n.readAsText(t)}),document.getElementById(`rag-search-btn`)?.addEventListener(`click`,P),document.getElementById(`diff-compare-btn`)?.addEventListener(`click`,()=>{let e=document.getElementById(`diff-snapshot-b`).value.trim(),t=document.getElementById(`diff-result`);if(!n){t.innerHTML=`<p class="error">No current snapshot. Refresh first.</p>`,t.classList.remove(`hidden`);return}let r;try{r=e?JSON.parse(e):{entries:[],summary:{}}}catch{t.innerHTML=`<p class="error">Invalid JSON in Snapshot B.</p>`,t.classList.remove(`hidden`);return}let i=n.entries??[],a=r.entries??[],o=new Set(i.map(e=>e.id)),s=new Set(a.map(e=>e.id)),c=a.filter(e=>!o.has(e.id)),l=i.filter(e=>!s.has(e.id)),u=i.filter(e=>{let t=a.find(t=>t.id===e.id);return t&&JSON.stringify(e)!==JSON.stringify(t)}),d=``;c.length&&(d+=`<p class="added">+ ${c.length} added</p><ul>${c.map(e=>`<li>${_(String(e.kind))}: ${_(String(e.id??``))}</li>`).join(``)}</ul>`),l.length&&(d+=`<p class="removed">− ${l.length} removed</p><ul>${l.map(e=>`<li>${_(String(e.kind))}: ${_(String(e.id??``))}</li>`).join(``)}</ul>`),u.length&&(d+=`<p class="changed">~ ${u.length} changed</p><ul>${u.map(e=>`<li>${_(String(e.kind))}: ${_(String(e.id??``))}</li>`).join(``)}</ul>`),d||=`<p>No differences.</p>`,t.innerHTML=d,t.classList.remove(`hidden`)}),document.getElementById(`search`).addEventListener(`input`,e=>{let t=e.target.value;if(!n)return;let r=ue(n.entries,t),i=n.summary&&typeof n.summary==`object`?n.summary:{};b(Object.fromEntries(Object.entries(i).map(([e])=>[e,r.filter(t=>t.kind===e).length])));let a=r.filter(e=>e.kind===`route`),o=r.filter(e=>e.kind===`module`),s=r.filter(e=>e.kind===`provider`),c=r.filter(e=>e.kind===`cron`),l=r.filter(e=>e.kind===`queue`),u=r.filter(e=>e.kind===`websocket`),d=r.filter(e=>e.kind===`agent`),f=r.filter(e=>e.kind===`rag`),p=r.filter(e=>e.kind===`prompt`),m=r.filter(e=>e.kind===`aifunction`),h=r.filter(e=>e.kind===`event`),g=r.filter(e=>e.kind===`graphql`),_=r.filter(e=>e.kind===`grpc`),v=r.filter(e=>e.kind===`kafka`),y=r.filter(e=>e.kind===`flow`),x=r.filter(e=>e.kind===`data`),S=r.filter(e=>e.kind===`serverless`),C=r.filter(e=>e.kind===`ml`);I(`routes-table`,a,[`httpMethod`,`fullPath`,`controllerPath`,`className`],`route`,U,{sortable:!0,tryRoute:!0}),F(o),I(`modules-table`,o,[`moduleName`,`dynamicModule`,`imports`],`module`,void 0,{sortable:!0}),I(`providers-table`,s,[`providerName`,`moduleName`,`scope`],`provider`,G,{sortable:!0}),I(`jobs-table`,c,[`jobName`,`cronExpression`,`enabled`,`nextRuns`],`cron`,W),I(`queues-table`,l,[`queueName`,`consumerName`,`className`],`queue`),I(`websocket-table`,u,[`gatewayName`,`eventName`,`namespace`],`websocket`),I(`agents-table`,d,[`agentName`,`className`,`model`,`tools`],`agent`,K,{sortable:!0,runAgent:!0}),I(`ai-table`,m,[`className`,`methodName`,`provider`,`model`,`streaming`],`aifunction`,q),N(f),I(`rag-table`,f,[`pipelineName`,`vectorStore`,`embeddingProvider`,`chunkingStrategy`],`rag`,void 0,{sortable:!0}),I(`prompts-table`,p,[`promptKey`,`scope`],`prompt`,void 0,{sortable:!0,previewPrompt:!0}),I(`events-table`,h,[`eventName`,`className`,`methodName`],`event`),I(`graphql-table`,g,[`operationType`,`operationName`,`resolverName`,`className`],`graphql`),I(`grpc-table`,_,[`serviceName`,`methodName`,`className`],`grpc`),I(`kafka-table`,v,[`consumerName`,`topic`,`groupId`,`methodName`],`kafka`);let w=document.getElementById(`flow-runtime-info`);w&&w.classList.toggle(`hidden`,y.length===0),M(y),I(`flows-table`,y,[`flowId`,`version`,`sourceType`,`nodeName`,`entryNode`,`edges`,`className`],`flow`,void 0,{sortable:!0}),I(`data-table`,x,[`pipelineName`,`className`],`data`),I(`serverless-table`,S,[`controllerName`,`runtime`,`memory`,`timeout`],`serverless`),I(`ml-table`,C,[`modelName`,`version`,`className`],`ml`)}),Y().then(()=>{let e=new URLSearchParams(window.location.search).get(`tab`);e&&Z(e)});