@tonyclaw/agent-inspector 2.1.2 → 2.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{CompareDrawer-BULPis8W.js → CompareDrawer-BihEPd3v.js} +1 -1
  3. package/.output/public/assets/ProxyViewerContainer-DYqXb6WW.js +117 -0
  4. package/.output/public/assets/{ReplayDialog-3ln-D7OS.js → ReplayDialog-DnX-6kY8.js} +1 -1
  5. package/.output/public/assets/{RequestAnatomy-D8d1xV8O.js → RequestAnatomy-CIkHAxZO.js} +1 -1
  6. package/.output/public/assets/{ResponseView-CJijikn-.js → ResponseView-BFc8jjZM.js} +1 -1
  7. package/.output/public/assets/{StreamingChunkSequence-C-RCuOTp.js → StreamingChunkSequence-p8qkpF6K.js} +1 -1
  8. package/.output/public/assets/_sessionId-Csx4T_y6.js +1 -0
  9. package/.output/public/assets/index-Bcq8bZoK.css +1 -0
  10. package/.output/public/assets/index-KMuh-31x.js +1 -0
  11. package/.output/public/assets/{main-D3pBFhb_.js → main-xlSdu7_I.js} +7 -7
  12. package/.output/server/_libs/lucide-react.mjs +204 -173
  13. package/.output/server/_libs/radix-ui__react-dialog.mjs +2 -0
  14. package/.output/server/{_sessionId-BFMVfrw3.mjs → _sessionId-CwVQgxoK.mjs} +3 -3
  15. package/.output/server/_ssr/{CompareDrawer-CwNPZgc_.mjs → CompareDrawer-Br9Ec0ah.mjs} +3 -3
  16. package/.output/server/_ssr/{ProxyViewerContainer-HpLc7F_J.mjs → ProxyViewerContainer-Oe5Tr3C2.mjs} +982 -70
  17. package/.output/server/_ssr/{ReplayDialog-DBaFhSv6.mjs → ReplayDialog-C1_QsoA-.mjs} +4 -4
  18. package/.output/server/_ssr/{RequestAnatomy-D0E0e2DT.mjs → RequestAnatomy-cn08QSoz.mjs} +2 -2
  19. package/.output/server/_ssr/{ResponseView-D2FFSRQ8.mjs → ResponseView-CIqUCCTG.mjs} +3 -3
  20. package/.output/server/_ssr/{StreamingChunkSequence-Cdu36-rL.mjs → StreamingChunkSequence-0MhVWD2F.mjs} +3 -3
  21. package/.output/server/_ssr/{index-CtBfmJYM.mjs → index-jpnI5ghp.mjs} +2 -2
  22. package/.output/server/_ssr/index.mjs +2 -2
  23. package/.output/server/_ssr/{router-Dzx1sbAQ.mjs → router-SSOn7c09.mjs} +1971 -222
  24. package/.output/server/_tanstack-start-manifest_v-BCgy_9er.mjs +4 -0
  25. package/.output/server/index.mjs +62 -62
  26. package/package.json +2 -1
  27. package/src/assets/agent-inspector.ico +0 -0
  28. package/src/assets/favicon.svg +21 -31
  29. package/src/components/ProxyViewer.tsx +87 -1
  30. package/src/components/ProxyViewerContainer.tsx +26 -0
  31. package/src/components/alerts/AlertsDialog.tsx +610 -0
  32. package/src/components/proxy-viewer/LogEntry.tsx +324 -51
  33. package/src/components/ui/dialog.tsx +1 -0
  34. package/src/contracts/index.ts +15 -2
  35. package/src/contracts/log.ts +18 -0
  36. package/src/lib/alertContract.ts +79 -0
  37. package/src/lib/apiClient.ts +39 -0
  38. package/src/lib/export-logs.ts +47 -9
  39. package/src/lib/logImportContract.ts +12 -0
  40. package/src/lib/useAlerts.ts +82 -0
  41. package/src/lib/useGroupEvidence.ts +6 -2
  42. package/src/lib/useGroups.ts +6 -2
  43. package/src/proxy/alerts.ts +664 -0
  44. package/src/proxy/logBodyChunks.ts +91 -0
  45. package/src/proxy/logImporter.ts +491 -0
  46. package/src/proxy/logIndex.ts +63 -2
  47. package/src/proxy/sqliteLogIndex.ts +612 -0
  48. package/src/proxy/store.ts +32 -7
  49. package/src/routes/api/alerts.summary.ts +24 -0
  50. package/src/routes/api/alerts.ts +52 -0
  51. package/src/routes/api/logs.$id.body.ts +44 -0
  52. package/src/routes/api/logs.import.ts +50 -0
  53. package/src/services/alerts.ts +12 -0
  54. package/.output/public/assets/ProxyViewerContainer-YxtP1xBj.js +0 -117
  55. package/.output/public/assets/_sessionId-DGehOTux.js +0 -1
  56. package/.output/public/assets/index-B-MZ9lQM.css +0 -1
  57. package/.output/public/assets/index-DhsjXb_K.js +0 -1
  58. package/.output/server/_tanstack-start-manifest_v-VrssoWVE.mjs +0 -4
@@ -0,0 +1,4 @@
1
+ const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/__root.tsx", "children": ["/", "/api/alerts", "/api/config", "/api/groups", "/api/health", "/api/logs", "/api/mcp", "/api/models", "/api/providers", "/api/runs", "/api/sessions", "/proxy/$", "/session/$sessionId", "/api/knowledge/candidates", "/api/knowledge/project-context", "/api/knowledge/search", "/api/knowledge/sessions/$sessionId/candidates"], "preloads": ["/assets/main-xlSdu7_I.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-KMuh-31x.js", "/assets/ProxyViewerContainer-DYqXb6WW.js"] }, "/api/alerts": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/alerts.ts", "children": ["/api/alerts/summary"] }, "/api/config": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/config.ts", "children": ["/api/config/paths"] }, "/api/groups": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/groups.ts", "children": ["/api/groups/$groupId"] }, "/api/health": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/health.ts" }, "/api/logs": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.ts", "children": ["/api/logs/$id", "/api/logs/import", "/api/logs/stream"] }, "/api/mcp": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/mcp.ts" }, "/api/models": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/models.ts" }, "/api/providers": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.ts", "children": ["/api/providers/$providerId", "/api/providers/export", "/api/providers/import", "/api/providers/scan"] }, "/api/runs": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/runs.ts", "children": ["/api/runs/$runId"] }, "/api/sessions": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/sessions.ts" }, "/proxy/$": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/proxy/$.ts" }, "/session/$sessionId": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/session/$sessionId.tsx", "assets": [], "preloads": ["/assets/_sessionId-Csx4T_y6.js", "/assets/ProxyViewerContainer-DYqXb6WW.js"] }, "/api/alerts/summary": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/alerts.summary.ts" }, "/api/config/paths": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/config.paths.ts" }, "/api/groups/$groupId": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/groups.$groupId.ts", "children": ["/api/groups/$groupId/evidence", "/api/groups/$groupId/sessions"] }, "/api/knowledge/candidates": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.candidates.ts", "children": ["/api/knowledge/candidates/$candidateId"] }, "/api/knowledge/project-context": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.project-context.ts" }, "/api/knowledge/search": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.search.ts" }, "/api/logs/$id": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.$id.ts", "children": ["/api/logs/$id/body", "/api/logs/$id/chunks", "/api/logs/$id/replay"] }, "/api/logs/import": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.import.ts" }, "/api/logs/stream": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.stream.ts" }, "/api/providers/$providerId": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.$providerId.ts", "children": ["/api/providers/$providerId/model-metadata", "/api/providers/$providerId/test"] }, "/api/providers/export": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.export.ts" }, "/api/providers/import": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.import.ts" }, "/api/providers/scan": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.scan.ts" }, "/api/runs/$runId": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/runs.$runId.ts", "children": ["/api/runs/$runId/evidence"] }, "/api/groups/$groupId/evidence": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/groups.$groupId.evidence.ts" }, "/api/groups/$groupId/sessions": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/groups.$groupId.sessions.ts" }, "/api/knowledge/candidates/$candidateId": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.candidates.$candidateId.ts", "children": ["/api/knowledge/candidates/$candidateId/promote"] }, "/api/logs/$id/body": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.$id.body.ts" }, "/api/logs/$id/chunks": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.$id.chunks.ts" }, "/api/logs/$id/replay": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/logs.$id.replay.ts" }, "/api/providers/$providerId/model-metadata": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.$providerId.model-metadata.ts" }, "/api/providers/$providerId/test": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.$providerId.test.ts", "children": ["/api/providers/$providerId/test/log"] }, "/api/runs/$runId/evidence": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/runs.$runId.evidence.ts" }, "/api/knowledge/candidates/$candidateId/promote": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.candidates.$candidateId.promote.ts" }, "/api/knowledge/sessions/$sessionId/candidates": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/knowledge.sessions.$sessionId.candidates.ts" }, "/api/providers/$providerId/test/log": { "filePath": "C:/Users/claw/workspace/agent-inspector/src/routes/api/providers.$providerId.test.log.ts" } }, "clientEntry": "/assets/main-xlSdu7_I.js" });
2
+ export {
3
+ tsrStartManifest
4
+ };
@@ -35,103 +35,103 @@ const headers = ((m) => function headersRouteRule(event) {
35
35
  }
36
36
  });
37
37
  const assets = {
38
- "/assets/CompareDrawer-BULPis8W.js": {
39
- "type": "text/javascript; charset=utf-8",
40
- "etag": '"49e8-VRPo0JDjTY4i12CzP7TKFUpWrhU"',
41
- "mtime": "2026-07-03T04:36:34.362Z",
42
- "size": 18920,
43
- "path": "../public/assets/CompareDrawer-BULPis8W.js"
44
- },
45
- "/assets/index-B-MZ9lQM.css": {
46
- "type": "text/css; charset=utf-8",
47
- "etag": '"1db72-92tzHaZ/ZR+6wYtaJ3rTnS8Fbd0"',
48
- "mtime": "2026-07-03T04:36:34.362Z",
49
- "size": 121714,
50
- "path": "../public/assets/index-B-MZ9lQM.css"
51
- },
52
38
  "/assets/alibaba-TTwafVwX.svg": {
53
39
  "type": "image/svg+xml",
54
40
  "etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
55
- "mtime": "2026-07-03T04:36:34.362Z",
41
+ "mtime": "2026-07-03T07:52:18.057Z",
56
42
  "size": 5915,
57
43
  "path": "../public/assets/alibaba-TTwafVwX.svg"
58
44
  },
45
+ "/assets/index-KMuh-31x.js": {
46
+ "type": "text/javascript; charset=utf-8",
47
+ "etag": '"74-DDu8Y0k+118MPEojCQ31x0l0t6M"',
48
+ "mtime": "2026-07-03T07:52:18.057Z",
49
+ "size": 116,
50
+ "path": "../public/assets/index-KMuh-31x.js"
51
+ },
52
+ "/assets/CompareDrawer-BihEPd3v.js": {
53
+ "type": "text/javascript; charset=utf-8",
54
+ "etag": '"49e8-cBpqLRmj+nSdwIVvl8By/sv8Gls"',
55
+ "mtime": "2026-07-03T07:52:18.057Z",
56
+ "size": 18920,
57
+ "path": "../public/assets/CompareDrawer-BihEPd3v.js"
58
+ },
59
59
  "/assets/minimax-BPMzvuL-.jpeg": {
60
60
  "type": "image/jpeg",
61
61
  "etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
62
- "mtime": "2026-07-03T04:36:34.361Z",
62
+ "mtime": "2026-07-03T07:52:18.057Z",
63
63
  "size": 6918,
64
64
  "path": "../public/assets/minimax-BPMzvuL-.jpeg"
65
65
  },
66
- "/assets/RequestAnatomy-D8d1xV8O.js": {
66
+ "/assets/index-Bcq8bZoK.css": {
67
+ "type": "text/css; charset=utf-8",
68
+ "etag": '"1e82d-Bo+nRYLQB3/4r6wWrfFE4tW/SHg"',
69
+ "mtime": "2026-07-03T07:52:18.057Z",
70
+ "size": 124973,
71
+ "path": "../public/assets/index-Bcq8bZoK.css"
72
+ },
73
+ "/assets/RequestAnatomy-CIkHAxZO.js": {
67
74
  "type": "text/javascript; charset=utf-8",
68
- "etag": '"43f2-04Hwj4T4/Xod5OiVnj2IL8uvp6s"',
69
- "mtime": "2026-07-03T04:36:34.362Z",
75
+ "etag": '"43f2-ndCyHyHaIH5k3uyS5zLGEGd8ZQs"',
76
+ "mtime": "2026-07-03T07:52:18.057Z",
70
77
  "size": 17394,
71
- "path": "../public/assets/RequestAnatomy-D8d1xV8O.js"
78
+ "path": "../public/assets/RequestAnatomy-CIkHAxZO.js"
72
79
  },
73
- "/assets/index-DhsjXb_K.js": {
80
+ "/assets/ResponseView-BFc8jjZM.js": {
74
81
  "type": "text/javascript; charset=utf-8",
75
- "etag": '"74-gJ+8unt7dHjt58uju2wwENgCQ9s"',
76
- "mtime": "2026-07-03T04:36:34.362Z",
77
- "size": 116,
78
- "path": "../public/assets/index-DhsjXb_K.js"
82
+ "etag": '"30d2-FN8BV3cpzR3ubQDpdfQY+p1+z/Q"',
83
+ "mtime": "2026-07-03T07:52:18.057Z",
84
+ "size": 12498,
85
+ "path": "../public/assets/ResponseView-BFc8jjZM.js"
79
86
  },
80
- "/assets/main-D3pBFhb_.js": {
87
+ "/assets/StreamingChunkSequence-p8qkpF6K.js": {
81
88
  "type": "text/javascript; charset=utf-8",
82
- "etag": '"517d9-sSwH27aNsGv5k6JrEX4wB+imR2I"',
83
- "mtime": "2026-07-03T04:36:34.362Z",
84
- "size": 333785,
85
- "path": "../public/assets/main-D3pBFhb_.js"
89
+ "etag": '"d5c-8wlfYtpc07D3FnsFacfabFwHWYI"',
90
+ "mtime": "2026-07-03T07:52:18.059Z",
91
+ "size": 3420,
92
+ "path": "../public/assets/StreamingChunkSequence-p8qkpF6K.js"
86
93
  },
87
94
  "/assets/zhipuai-BPNAnxo-.svg": {
88
95
  "type": "image/svg+xml",
89
96
  "etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
90
- "mtime": "2026-07-03T04:36:34.361Z",
97
+ "mtime": "2026-07-03T07:52:18.057Z",
91
98
  "size": 11256,
92
99
  "path": "../public/assets/zhipuai-BPNAnxo-.svg"
93
100
  },
94
- "/assets/StreamingChunkSequence-C-RCuOTp.js": {
101
+ "/assets/_sessionId-Csx4T_y6.js": {
95
102
  "type": "text/javascript; charset=utf-8",
96
- "etag": '"d5c-wLsQFhijhbXBdhCV5VrfUQpTkXA"',
97
- "mtime": "2026-07-03T04:36:34.362Z",
98
- "size": 3420,
99
- "path": "../public/assets/StreamingChunkSequence-C-RCuOTp.js"
100
- },
101
- "/assets/ResponseView-CJijikn-.js": {
102
- "type": "text/javascript; charset=utf-8",
103
- "etag": '"30d2-UQ2trhGzRVfbOVcDsw0MegNNT1U"',
104
- "mtime": "2026-07-03T04:36:34.362Z",
105
- "size": 12498,
106
- "path": "../public/assets/ResponseView-CJijikn-.js"
103
+ "etag": '"d2-Qqkqbm9nR1nIMdgSM7sxuLljO6Q"',
104
+ "mtime": "2026-07-03T07:52:18.057Z",
105
+ "size": 210,
106
+ "path": "../public/assets/_sessionId-Csx4T_y6.js"
107
107
  },
108
- "/assets/ReplayDialog-3ln-D7OS.js": {
108
+ "/assets/ReplayDialog-DnX-6kY8.js": {
109
109
  "type": "text/javascript; charset=utf-8",
110
- "etag": '"318c-e/P9pR0qpfIS364q4kyij4WXvbc"',
111
- "mtime": "2026-07-03T04:36:34.362Z",
110
+ "etag": '"318c-4vrj6maBmg3vnKS0IStIsOYe0SE"',
111
+ "mtime": "2026-07-03T07:52:18.057Z",
112
112
  "size": 12684,
113
- "path": "../public/assets/ReplayDialog-3ln-D7OS.js"
113
+ "path": "../public/assets/ReplayDialog-DnX-6kY8.js"
114
114
  },
115
- "/assets/_sessionId-DGehOTux.js": {
115
+ "/assets/main-xlSdu7_I.js": {
116
116
  "type": "text/javascript; charset=utf-8",
117
- "etag": '"d2-tgCR/EgYUO2FparSSMVR3POa/5o"',
118
- "mtime": "2026-07-03T04:36:34.362Z",
119
- "size": 210,
120
- "path": "../public/assets/_sessionId-DGehOTux.js"
117
+ "etag": '"512fd-w+PhHGmgqkHUWhgkIrieWmaEqYU"',
118
+ "mtime": "2026-07-03T07:52:18.057Z",
119
+ "size": 332541,
120
+ "path": "../public/assets/main-xlSdu7_I.js"
121
121
  },
122
122
  "/assets/qwen-CONDcHqt.png": {
123
123
  "type": "image/png",
124
124
  "etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
125
- "mtime": "2026-07-03T04:36:34.362Z",
125
+ "mtime": "2026-07-03T07:52:18.057Z",
126
126
  "size": 357059,
127
127
  "path": "../public/assets/qwen-CONDcHqt.png"
128
128
  },
129
- "/assets/ProxyViewerContainer-YxtP1xBj.js": {
129
+ "/assets/ProxyViewerContainer-DYqXb6WW.js": {
130
130
  "type": "text/javascript; charset=utf-8",
131
- "etag": '"bafe3-4mylD57oarTKeI+eaF63Ba8W/Sc"',
132
- "mtime": "2026-07-03T04:36:34.362Z",
133
- "size": 765923,
134
- "path": "../public/assets/ProxyViewerContainer-YxtP1xBj.js"
131
+ "etag": '"bfe50-rgRP7lJq+wsVfs/xn5xkbtVZs7U"',
132
+ "mtime": "2026-07-03T07:52:18.057Z",
133
+ "size": 786e3,
134
+ "path": "../public/assets/ProxyViewerContainer-DYqXb6WW.js"
135
135
  }
136
136
  };
137
137
  function readAsset(id) {
@@ -159,7 +159,7 @@ const EncodingMap = {
159
159
  br: ".br",
160
160
  zstd: ".zst"
161
161
  };
162
- const _bTSMt_ = defineHandler((event) => {
162
+ const _9o1BXV = defineHandler((event) => {
163
163
  if (event.req.method && !METHODS.has(event.req.method)) {
164
164
  return;
165
165
  }
@@ -231,15 +231,15 @@ const findRouteRules = /* @__PURE__ */ (() => {
231
231
  return r;
232
232
  };
233
233
  })();
234
- const _lazy_OSYDIZ = defineLazyEventHandler(() => import("./_chunks/ssr-renderer.mjs"));
234
+ const _lazy_c5_ocM = defineLazyEventHandler(() => import("./_chunks/ssr-renderer.mjs"));
235
235
  const findRoute = /* @__PURE__ */ (() => {
236
- const data = { route: "/**", handler: _lazy_OSYDIZ };
236
+ const data = { route: "/**", handler: _lazy_c5_ocM };
237
237
  return ((_m, p) => {
238
238
  return { data, params: { "_": p.slice(1) } };
239
239
  });
240
240
  })();
241
241
  const globalMiddleware = [
242
- toEventHandler(_bTSMt_)
242
+ toEventHandler(_9o1BXV)
243
243
  ].filter(Boolean);
244
244
  const errorHandler$1 = (error, event) => {
245
245
  const res = defaultHandler(error, event);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tonyclaw/agent-inspector",
3
- "version": "2.1.2",
3
+ "version": "2.1.4",
4
4
  "type": "module",
5
5
  "description": "Agent observability and knowledge capture layer for AI coding tools.",
6
6
  "license": "MIT",
@@ -92,6 +92,7 @@
92
92
  "zod": "^4.3.6"
93
93
  },
94
94
  "optionalDependencies": {
95
+ "better-sqlite3": "^12.11.1",
95
96
  "rcedit": "4.0.1"
96
97
  },
97
98
  "devDependencies": {
Binary file
@@ -1,31 +1,21 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" role="img" aria-label="Agent Inspector">
2
- <rect width="64" height="64" rx="14" fill="#111827" />
3
- <g fill="none" stroke="#f59e0b" stroke-width="4.2" stroke-linecap="round" stroke-linejoin="round">
4
- <path fill="#f59e0b" d="M15 36c0-11 7-18 17-18s17 7 17 18c0 8-7 13-17 13s-17-5-17-13z" />
5
- <path d="M16 31c-6-5-12-3-12 4 0 5 6 6 11 2" />
6
- <path d="M48 31c6-5 12-3 12 4 0 5-6 6-11 2" />
7
- <path d="M27 19l-3-7" />
8
- <path d="M37 19l3-7" />
9
- <path d="M19 45l-6 9" />
10
- <path d="M27 48l-3 9" />
11
- <path d="M37 48l3 9" />
12
- <path d="M45 45l6 9" />
13
- </g>
14
- <path d="M14 47l9-8 8 9c-5 3.5-12 3-17-1z" fill="#2f6b3f" opacity=".95" />
15
- <path d="M18 46l5-5 5 6c-3 1.6-7 1.4-10-1z" fill="#6fb36f" opacity=".95" />
16
- <path d="M23 41v10" fill="none" stroke="#d6b45f" stroke-width="1.6" stroke-linecap="round" />
17
- <circle cx="31" cy="48" r="1.8" fill="#c2412d" />
18
- <path d="M24 44l13-11 14 13c-8 5.8-18 5.3-27-2z" fill="#2f6b3f" opacity=".97" />
19
- <path d="M30 43l7-7 9 9c-5 2.7-11 2.5-16-2z" fill="#6fb36f" opacity=".95" />
20
- <path d="M37 36v14" fill="none" stroke="#d6b45f" stroke-width="2" stroke-linecap="round" />
21
- <path d="M30 43c5-2 11-1.5 16 2" fill="none" stroke="#9fca78" stroke-width="1.8" stroke-linecap="round" />
22
- <circle cx="51" cy="46" r="2" fill="#c2412d" />
23
- <path d="M40 50l8-8 7 8c-4.2 3.2-10 3-15 0z" fill="#2f6b3f" opacity=".95" />
24
- <path d="M43 49l5-5 4.5 5.5c-3 1.5-6 1.2-9.5-.5z" fill="#6fb36f" opacity=".95" />
25
- <path d="M48 44v9" fill="none" stroke="#d6b45f" stroke-width="1.5" stroke-linecap="round" />
26
- <circle cx="55" cy="50" r="1.7" fill="#c2412d" />
27
- <circle cx="24" cy="11" r="3.2" fill="#f59e0b" />
28
- <circle cx="40" cy="11" r="3.2" fill="#f59e0b" />
29
- <circle cx="25" cy="34" r="2.1" fill="#111827" />
30
- <circle cx="39" cy="34" r="2.1" fill="#111827" />
31
- </svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" role="img" aria-label="Agent Inspector">
2
+ <g
3
+ fill="none"
4
+ stroke="#f59e0b"
5
+ stroke-width="1.5"
6
+ stroke-linecap="round"
7
+ stroke-linejoin="round"
8
+ >
9
+ <path d="M5 13 C5 9 8 7 12 7 C16 7 19 9 19 13 C19 16 16 18 12 18 C8 18 5 16 5 13 Z" />
10
+ <path d="M5 11 C3.5 9.5 1.5 10 2 12.5 C2.5 14 4 13.5 5 12.5" />
11
+ <path d="M19 11 C20.5 9.5 22.5 10 22 12.5 C21.5 14 20 13.5 19 12.5" />
12
+ <line x1="10" y1="7" x2="9.5" y2="5" />
13
+ <line x1="14" y1="7" x2="14.5" y2="5" />
14
+ <line x1="6.5" y1="16" x2="4.5" y2="19.5" />
15
+ <line x1="9" y1="17.5" x2="8" y2="20.5" />
16
+ <line x1="15" y1="17.5" x2="16" y2="20.5" />
17
+ <line x1="17.5" y1="16" x2="19.5" y2="19.5" />
18
+ </g>
19
+ <circle cx="9.5" cy="4.5" r="0.9" fill="#f59e0b" />
20
+ <circle cx="14.5" cy="4.5" r="0.9" fill="#f59e0b" />
21
+ </svg>
@@ -1,4 +1,13 @@
1
- import { type JSX, useCallback, useEffect, useMemo, useRef, useState, Suspense } from "react";
1
+ import {
2
+ type ChangeEvent,
3
+ type JSX,
4
+ useCallback,
5
+ useEffect,
6
+ useMemo,
7
+ useRef,
8
+ useState,
9
+ Suspense,
10
+ } from "react";
2
11
  import {
3
12
  ArrowDownRight,
4
13
  ArrowLeft,
@@ -18,10 +27,12 @@ import {
18
27
  Plus,
19
28
  Siren,
20
29
  Trash2,
30
+ Upload,
21
31
  } from "lucide-react";
22
32
 
23
33
  import type { CapturedLog } from "../contracts";
24
34
  import { exportLogsAsZip, type ExportMode } from "../lib/export-logs";
35
+ import type { ImportLogsResponse } from "../lib/logImportContract";
25
36
  import { copyTextToClipboard } from "../lib/clipboard";
26
37
  import type { InspectorGroupEvidence, InspectorGroupMember } from "../lib/groupContract";
27
38
  import type { CaptureMode, TimeDisplayFormat } from "../lib/runtimeConfig";
@@ -36,6 +47,7 @@ import { crabVariants } from "./ui/crab-variants";
36
47
  import { McpLogo } from "./ui/mcp-logo";
37
48
  import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "./ui/select";
38
49
  import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "./ui/tooltip";
50
+ import { AlertsDialog } from "./alerts/AlertsDialog";
39
51
  import { GroupsDialog } from "./groups/GroupsDialog";
40
52
  import { SettingsDialog } from "./providers/SettingsDialog";
41
53
  import { computeCacheTrends } from "./proxy-viewer/cacheTrend";
@@ -895,6 +907,7 @@ function BrandHeader({
895
907
  </div>
896
908
  </div>
897
909
  <div className="flex shrink-0 items-center gap-1">
910
+ <AlertsDialog />
898
911
  <GroupsDialog />
899
912
  <SettingsDialog />
900
913
  </div>
@@ -927,6 +940,7 @@ function BrandHeader({
927
940
  <McpReadyBadge />
928
941
  </h1>
929
942
  <div className="justify-self-end flex items-center gap-1">
943
+ <AlertsDialog />
930
944
  <GroupsDialog />
931
945
  <SettingsDialog />
932
946
  </div>
@@ -1253,6 +1267,7 @@ export type ProxyViewerProps = {
1253
1267
  /** Clear only the logs whose ids are passed. Called by the per-group
1254
1268
  * Clear button on each conversation header. */
1255
1269
  onClearGroup: (ids: number[]) => void;
1270
+ onImportLogs?: (file: File) => Promise<ImportLogsResponse>;
1256
1271
  viewMode: "simple" | "full";
1257
1272
  captureMode: CaptureMode;
1258
1273
  /** Live strip-Claude-Code-billing-header flag, sourced once at the container. */
@@ -1285,6 +1300,7 @@ export function ProxyViewer({
1285
1300
  onModelChange,
1286
1301
  onClearAll,
1287
1302
  onClearGroup,
1303
+ onImportLogs,
1288
1304
  viewMode,
1289
1305
  captureMode,
1290
1306
  strip,
@@ -1300,12 +1316,16 @@ export function ProxyViewer({
1300
1316
  const { providers } = useProviders();
1301
1317
  const [exporting, setExporting] = useState<ExportMode | null>(null);
1302
1318
  const [exportError, setExportError] = useState<string | null>(null);
1319
+ const [importing, setImporting] = useState(false);
1320
+ const [importStatus, setImportStatus] = useState<string | null>(null);
1321
+ const [importError, setImportError] = useState<string | null>(null);
1303
1322
  const [comparePair, setComparePair] = useState<[CapturedLog, CapturedLog] | null>(null);
1304
1323
  const [crabEntrancePhase, setCrabEntrancePhase] = useState<"hidden" | "playing" | "done">(
1305
1324
  "hidden",
1306
1325
  );
1307
1326
  const logListRef = useRef<HTMLDivElement>(null);
1308
1327
  const logListWrapperRef = useRef<HTMLDivElement>(null);
1328
+ const importInputRef = useRef<HTMLInputElement>(null);
1309
1329
  useKeyboardNavigation(logListRef, logListWrapperRef, { pageWide: true });
1310
1330
 
1311
1331
  useEffect(() => {
@@ -1344,6 +1364,35 @@ export function ProxyViewer({
1344
1364
  },
1345
1365
  [logs],
1346
1366
  );
1367
+ const handleImportClick = useCallback(() => {
1368
+ importInputRef.current?.click();
1369
+ }, []);
1370
+
1371
+ const handleImportFileChange = useCallback(
1372
+ (event: ChangeEvent<HTMLInputElement>) => {
1373
+ const file = event.currentTarget.files?.[0];
1374
+ event.currentTarget.value = "";
1375
+ if (file === undefined || onImportLogs === undefined) return;
1376
+
1377
+ setImporting(true);
1378
+ setImportError(null);
1379
+ setImportStatus(null);
1380
+ void onImportLogs(file)
1381
+ .then((result) => {
1382
+ const skipped = result.skipped > 0 ? `, skipped ${String(result.skipped)}` : "";
1383
+ setImportStatus(
1384
+ `Imported ${String(result.imported)} logs as ${result.sessionId}${skipped}.`,
1385
+ );
1386
+ })
1387
+ .catch((err: unknown) => {
1388
+ setImportError(err instanceof Error ? err.message : "Failed to import logs");
1389
+ })
1390
+ .finally(() => {
1391
+ setImporting(false);
1392
+ });
1393
+ },
1394
+ [onImportLogs],
1395
+ );
1347
1396
  // Close the compare drawer when the user changes the session or model
1348
1397
  // filter, since the predecessor relationship may no longer be meaningful.
1349
1398
  useEffect(() => {
@@ -1503,6 +1552,33 @@ export function ProxyViewer({
1503
1552
  {activeScopeLabel}
1504
1553
  </div>
1505
1554
  </div>
1555
+ {onImportLogs !== undefined && (
1556
+ <>
1557
+ <input
1558
+ ref={importInputRef}
1559
+ type="file"
1560
+ accept=".zip,.json,.jsonl,application/zip,application/json"
1561
+ className="hidden"
1562
+ onChange={handleImportFileChange}
1563
+ />
1564
+ <button
1565
+ type="button"
1566
+ onClick={handleImportClick}
1567
+ disabled={importing}
1568
+ className="inline-flex h-8 items-center gap-1.5 rounded-md px-3 text-xs text-muted-foreground transition-colors hover:bg-muted hover:text-foreground disabled:cursor-not-allowed disabled:opacity-50"
1569
+ title="Import Agent Inspector export"
1570
+ >
1571
+ {importing ? (
1572
+ <span>Importing...</span>
1573
+ ) : (
1574
+ <>
1575
+ <Upload className="size-3.5" />
1576
+ <span>Import</span>
1577
+ </>
1578
+ )}
1579
+ </button>
1580
+ </>
1581
+ )}
1506
1582
  {exportActionVisibility.redacted && (
1507
1583
  <button
1508
1584
  type="button"
@@ -1559,6 +1635,16 @@ export function ProxyViewer({
1559
1635
  {exportError}
1560
1636
  </div>
1561
1637
  )}
1638
+ {importError !== null && (
1639
+ <div className="mt-2 rounded-md border border-destructive/30 bg-destructive/10 px-3 py-2 text-xs text-destructive">
1640
+ {importError}
1641
+ </div>
1642
+ )}
1643
+ {importStatus !== null && importError === null && (
1644
+ <div className="mt-2 rounded-md border border-emerald-500/25 bg-emerald-500/10 px-3 py-2 text-xs text-emerald-200">
1645
+ {importStatus}
1646
+ </div>
1647
+ )}
1562
1648
  </div>
1563
1649
 
1564
1650
  <div className="px-4 py-4 lg:px-5">
@@ -3,6 +3,7 @@ import { z } from "zod";
3
3
  import { CapturedLogSchema, type CapturedLog } from "../contracts";
4
4
  import { fetchJson } from "../lib/apiClient";
5
5
  import { InspectorGroupsListResponseSchema, type InspectorGroup } from "../lib/groupContract";
6
+ import { ImportLogsResponseSchema, type ImportLogsResponse } from "../lib/logImportContract";
6
7
  import { useStripConfig } from "../lib/useStripConfig";
7
8
  import { OnboardingBanner } from "./OnboardingBanner";
8
9
  import {
@@ -487,6 +488,30 @@ export function ProxyViewerContainer({
487
488
  })();
488
489
  }, []);
489
490
 
491
+ const handleImportLogs = useCallback(async (file: File): Promise<ImportLogsResponse> => {
492
+ const formData = new FormData();
493
+ formData.set("file", file);
494
+ const result = await fetchJson("/api/logs/import", ImportLogsResponseSchema, {
495
+ method: "POST",
496
+ body: formData,
497
+ });
498
+
499
+ setAllLogs((prev) => {
500
+ const importedIds = new Set(result.logs.map((log) => log.id));
501
+ const next = [...prev.filter((log) => !importedIds.has(log.id)), ...result.logs].sort(
502
+ (left, right) => left.id - right.id,
503
+ );
504
+ const trimmed = trimClientLogs(next);
505
+ logIndexRef.current = buildLogIndex(trimmed);
506
+ return trimmed;
507
+ });
508
+ setSelectedSession(result.sessionId);
509
+ setSelectedModel("__all__");
510
+ setLogPage(null);
511
+ setError(null);
512
+ return result;
513
+ }, []);
514
+
490
515
  // Read the strip config once at the container so the virtualized list does
491
516
  // not need N independent SWR subscriptions per row.
492
517
  const { strip, captureMode, slowResponseThresholdSeconds, timeDisplayFormat } = useStripConfig();
@@ -552,6 +577,7 @@ export function ProxyViewerContainer({
552
577
  onModelChange={setSelectedModel}
553
578
  onClearAll={handleClearAll}
554
579
  onClearGroup={handleClearGroup}
580
+ onImportLogs={initialSessionId === undefined ? handleImportLogs : undefined}
555
581
  isLoading={initialSessionId === undefined ? !streamInitialized : sessionPageLoading}
556
582
  pagination={pagination}
557
583
  sessionMemberships={sessionMemberships}