@tonyclaw/llm-inspector 1.18.2 → 1.19.0

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 (42) hide show
  1. package/.output/cli.js +776 -139
  2. package/.output/nitro.json +1 -1
  3. package/.output/public/assets/{CompareDrawer-C-4ypEWs.js → CompareDrawer-DwayZPPO.js} +1 -1
  4. package/.output/public/assets/ProxyViewerContainer-iv3LVMEW.js +101 -0
  5. package/.output/public/assets/{ReplayDialog-CyBKOgba.js → ReplayDialog-CaV1elYO.js} +1 -1
  6. package/.output/public/assets/{RequestAnatomy-C0IrVQ3q.js → RequestAnatomy-CSfnjK7j.js} +1 -1
  7. package/.output/public/assets/{ResponseView-MogToC4i.js → ResponseView-YkOL__xm.js} +1 -1
  8. package/.output/public/assets/{StreamingChunkSequence-ClhUhT-s.js → StreamingChunkSequence-D_p6L-oB.js} +1 -1
  9. package/.output/public/assets/_sessionId-BgCVUC6R.js +1 -0
  10. package/.output/public/assets/index-CWA4S0FO.js +1 -0
  11. package/.output/public/assets/index-DeJyypsp.css +1 -0
  12. package/.output/public/assets/{json-viewer-BicGakI5.js → json-viewer-BB-9bqnP.js} +2 -2
  13. package/.output/public/assets/{main-Be2qqUUW.js → main-COVN451W.js} +2 -2
  14. package/.output/server/_libs/lucide-react.mjs +93 -72
  15. package/.output/server/{_sessionId-DhKJIdQC.mjs → _sessionId-BJT5qIib.mjs} +2 -2
  16. package/.output/server/_ssr/{CompareDrawer-BGUgukJ8.mjs → CompareDrawer-DNGYdUXs.mjs} +4 -4
  17. package/.output/server/_ssr/{ProxyViewerContainer--3K3o3Sm.mjs → ProxyViewerContainer-B-zDOLYE.mjs} +354 -343
  18. package/.output/server/_ssr/{ReplayDialog-Bo86xZI4.mjs → ReplayDialog-DWeqMA4y.mjs} +4 -4
  19. package/.output/server/_ssr/{RequestAnatomy-jRU5qgwB.mjs → RequestAnatomy-TOsrMu9-.mjs} +3 -3
  20. package/.output/server/_ssr/{ResponseView-DdO_-79a.mjs → ResponseView-BuqdPrzm.mjs} +4 -4
  21. package/.output/server/_ssr/{StreamingChunkSequence-BigLwhh4.mjs → StreamingChunkSequence-DuzNZkqL.mjs} +3 -3
  22. package/.output/server/_ssr/{index-BHG6vOnr.mjs → index-1nCQUt3y.mjs} +2 -2
  23. package/.output/server/_ssr/index.mjs +2 -2
  24. package/.output/server/_ssr/{json-viewer-B4c_WjXD.mjs → json-viewer-BL8xhHbi.mjs} +9 -5
  25. package/.output/server/_ssr/{router-DVixpJO-.mjs → router-aCaUgVTW.mjs} +3 -3
  26. package/.output/server/{_tanstack-start-manifest_v-BbvWUF4v.mjs → _tanstack-start-manifest_v-cBRxvCjb.mjs} +1 -1
  27. package/.output/server/index.mjs +61 -61
  28. package/package.json +2 -1
  29. package/src/cli/detect-tools.ts +146 -0
  30. package/src/cli/onboard.ts +229 -0
  31. package/src/cli/templates/command-onboard.ts +17 -0
  32. package/src/cli/templates/skill-onboard.ts +325 -0
  33. package/src/cli.ts +185 -163
  34. package/src/components/ProxyViewer.tsx +153 -142
  35. package/src/components/proxy-viewer/LogEntry.tsx +136 -157
  36. package/src/components/proxy-viewer/LogEntryHeader.tsx +147 -66
  37. package/src/components/proxy-viewer/useCopyFeedback.ts +36 -0
  38. package/src/components/ui/json-viewer.tsx +12 -0
  39. package/.output/public/assets/ProxyViewerContainer-WRenRpeh.js +0 -101
  40. package/.output/public/assets/_sessionId-BO47oA3Z.js +0 -1
  41. package/.output/public/assets/index-BRvz6-L6.css +0 -1
  42. package/.output/public/assets/index-Btw8ec7-.js +0 -1
@@ -1,10 +1,10 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
2
- import { D as Dialog, b as DialogContent, d as DialogHeader, e as DialogTitle, T as Tabs, h as TabsList, i as TabsTrigger, j as TabsContent, k as TooltipProvider, l as Tooltip, m as TooltipTrigger, n as TooltipContent, o as Button } from "./ProxyViewerContainer--3K3o3Sm.mjs";
3
- import { ResponseView } from "./ResponseView-DdO_-79a.mjs";
4
- import "./router-DVixpJO-.mjs";
2
+ import { D as Dialog, b as DialogContent, d as DialogHeader, e as DialogTitle, T as Tabs, h as TabsList, i as TabsTrigger, j as TabsContent, k as TooltipProvider, l as Tooltip, m as TooltipTrigger, n as TooltipContent, o as Button } from "./ProxyViewerContainer-B-zDOLYE.mjs";
3
+ import { ResponseView } from "./ResponseView-BuqdPrzm.mjs";
4
+ import "./router-aCaUgVTW.mjs";
5
5
  import "../_libs/modelcontextprotocol__server.mjs";
6
6
  import "../_libs/jszip.mjs";
7
- import "./json-viewer-B4c_WjXD.mjs";
7
+ import "./json-viewer-BL8xhHbi.mjs";
8
8
  import { s as RotateCcw } from "../_libs/lucide-react.mjs";
9
9
  import { d as object, c as boolean, n as number, b as string } from "../_libs/zod.mjs";
10
10
  import "../_libs/swr.mjs";
@@ -1,9 +1,9 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
2
- import { k as TooltipProvider, f as formatTokens, c as cn, l as Tooltip, m as TooltipTrigger, n as TooltipContent } from "./ProxyViewerContainer--3K3o3Sm.mjs";
3
- import "./router-DVixpJO-.mjs";
2
+ import { k as TooltipProvider, f as formatTokens, c as cn, l as Tooltip, m as TooltipTrigger, n as TooltipContent } from "./ProxyViewerContainer-B-zDOLYE.mjs";
3
+ import "./router-aCaUgVTW.mjs";
4
4
  import "../_libs/modelcontextprotocol__server.mjs";
5
5
  import "../_libs/jszip.mjs";
6
- import { K as Info } from "../_libs/lucide-react.mjs";
6
+ import { Q as Info } from "../_libs/lucide-react.mjs";
7
7
  import "../_libs/swr.mjs";
8
8
  import "../_libs/use-sync-external-store.mjs";
9
9
  import "../_libs/dequal.mjs";
@@ -1,10 +1,10 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
2
- import { g as getLogFormatAdapter, f as formatTokens, c as cn, p as getStatusCategory, B as Badge, s as safeJsonValue } from "./ProxyViewerContainer--3K3o3Sm.mjs";
3
- import { JsonViewer } from "./json-viewer-B4c_WjXD.mjs";
4
- import "./router-DVixpJO-.mjs";
2
+ import { g as getLogFormatAdapter, f as formatTokens, c as cn, p as getStatusCategory, B as Badge, s as safeJsonValue } from "./ProxyViewerContainer-B-zDOLYE.mjs";
3
+ import { JsonViewer } from "./json-viewer-BL8xhHbi.mjs";
4
+ import "./router-aCaUgVTW.mjs";
5
5
  import "../_libs/modelcontextprotocol__server.mjs";
6
6
  import "../_libs/jszip.mjs";
7
- import { Z as Zap, i as TriangleAlert, N as CircleStop, Q as Brain, b as ChevronDown, f as ChevronRight, V as Terminal } from "../_libs/lucide-react.mjs";
7
+ import { Z as Zap, i as TriangleAlert, V as CircleStop, Y as Brain, b as ChevronDown, f as ChevronRight, _ as Terminal } from "../_libs/lucide-react.mjs";
8
8
  import { M as Markdown } from "../_libs/react-markdown.mjs";
9
9
  import { R as Root } from "../_libs/radix-ui__react-separator.mjs";
10
10
  import { R as Root$1, C as CollapsibleTrigger$1, a as CollapsibleContent$1 } from "../_libs/radix-ui__react-collapsible.mjs";
@@ -1,7 +1,7 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
2
- import { k as TooltipProvider, l as Tooltip, m as TooltipTrigger, B as Badge, n as TooltipContent } from "./ProxyViewerContainer--3K3o3Sm.mjs";
3
- import { JsonViewer } from "./json-viewer-B4c_WjXD.mjs";
4
- import "./router-DVixpJO-.mjs";
2
+ import { k as TooltipProvider, l as Tooltip, m as TooltipTrigger, B as Badge, n as TooltipContent } from "./ProxyViewerContainer-B-zDOLYE.mjs";
3
+ import { JsonViewer } from "./json-viewer-BL8xhHbi.mjs";
4
+ import "./router-aCaUgVTW.mjs";
5
5
  import "../_libs/modelcontextprotocol__server.mjs";
6
6
  import "../_libs/jszip.mjs";
7
7
  import { b as ChevronDown, f as ChevronRight, L as LoaderCircle } from "../_libs/lucide-react.mjs";
@@ -1,6 +1,6 @@
1
- import { P as ProxyViewerContainer } from "./ProxyViewerContainer--3K3o3Sm.mjs";
1
+ import { P as ProxyViewerContainer } from "./ProxyViewerContainer-B-zDOLYE.mjs";
2
2
  import "../_libs/react.mjs";
3
- import "./router-DVixpJO-.mjs";
3
+ import "./router-aCaUgVTW.mjs";
4
4
  import "../_libs/modelcontextprotocol__server.mjs";
5
5
  import "../_libs/jszip.mjs";
6
6
  import "../_libs/swr.mjs";
@@ -198,7 +198,7 @@ function getResponse() {
198
198
  return event.res;
199
199
  }
200
200
  async function getStartManifest(matchedRoutes) {
201
- const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-BbvWUF4v.mjs");
201
+ const { tsrStartManifest } = await import("../_tanstack-start-manifest_v-cBRxvCjb.mjs");
202
202
  const startManifest = tsrStartManifest();
203
203
  const rootRoute = startManifest.routes[rootRouteId] = startManifest.routes[rootRouteId] || {};
204
204
  rootRoute.assets = rootRoute.assets || [];
@@ -767,7 +767,7 @@ let entriesPromise;
767
767
  let baseManifestPromise;
768
768
  let cachedFinalManifestPromise;
769
769
  async function loadEntries() {
770
- const routerEntry = await import("./router-DVixpJO-.mjs").then((n) => n.f);
770
+ const routerEntry = await import("./router-aCaUgVTW.mjs").then((n) => n.f);
771
771
  const startEntry = await import("./start-HYkvq4Ni.mjs");
772
772
  return { startEntry, routerEntry };
773
773
  }
@@ -1,9 +1,9 @@
1
1
  import { r as reactExports, j as jsxRuntimeExports } from "../_libs/react.mjs";
2
- import { q as parseJsonText, c as cn, k as TooltipProvider, l as Tooltip, m as TooltipTrigger, n as TooltipContent } from "./ProxyViewerContainer--3K3o3Sm.mjs";
3
- import "./router-DVixpJO-.mjs";
2
+ import { q as parseJsonText, c as cn, k as TooltipProvider, l as Tooltip, m as TooltipTrigger, n as TooltipContent } from "./ProxyViewerContainer-B-zDOLYE.mjs";
3
+ import "./router-aCaUgVTW.mjs";
4
4
  import "../_libs/modelcontextprotocol__server.mjs";
5
5
  import "../_libs/jszip.mjs";
6
- import { C as Check, a as Copy, b as ChevronDown, f as ChevronRight, r as ChevronsDown } from "../_libs/lucide-react.mjs";
6
+ import { C as Check, a as Copy, b as ChevronDown, f as ChevronRight, q as ChevronsDown } from "../_libs/lucide-react.mjs";
7
7
  import { M as Markdown } from "../_libs/react-markdown.mjs";
8
8
  import "../_libs/swr.mjs";
9
9
  import "../_libs/use-sync-external-store.mjs";
@@ -490,7 +490,9 @@ function JsonViewer({
490
490
  const JsonViewerFromString = reactExports.memo(function JsonViewerFromString2({
491
491
  text,
492
492
  defaultExpandDepth = 0,
493
- className
493
+ className,
494
+ bulkDepth,
495
+ bulkRevision
494
496
  }) {
495
497
  const parsed = reactExports.useMemo(() => parseJsonText(text), [text]);
496
498
  if (parsed.kind === "json") {
@@ -499,7 +501,9 @@ const JsonViewerFromString = reactExports.memo(function JsonViewerFromString2({
499
501
  {
500
502
  data: parsed.data,
501
503
  defaultExpandDepth,
502
- className
504
+ className,
505
+ bulkDepth,
506
+ bulkRevision
503
507
  }
504
508
  );
505
509
  }
@@ -47,7 +47,7 @@ import "../_libs/debounce-fn.mjs";
47
47
  import "../_libs/mimic-function.mjs";
48
48
  import "../_libs/semver.mjs";
49
49
  import "../_libs/uint8array-extras.mjs";
50
- const appCss = "/assets/index-BRvz6-L6.css";
50
+ const appCss = "/assets/index-DeJyypsp.css";
51
51
  const Route$l = createRootRoute({
52
52
  head: () => ({
53
53
  meta: [
@@ -71,7 +71,7 @@ function RootDocument({ children }) {
71
71
  ] })
72
72
  ] });
73
73
  }
74
- const $$splitComponentImporter$1 = () => import("./index-BHG6vOnr.mjs");
74
+ const $$splitComponentImporter$1 = () => import("./index-1nCQUt3y.mjs");
75
75
  const Route$k = createFileRoute("/")({
76
76
  component: lazyRouteComponent($$splitComponentImporter$1, "component")
77
77
  });
@@ -114,7 +114,7 @@ function decodeSessionIdFromPath(encoded) {
114
114
  function getSessionPath(sessionId) {
115
115
  return `/session/${encodeSessionIdForPath(sessionId)}`;
116
116
  }
117
- const $$splitComponentImporter = () => import("../_sessionId-DhKJIdQC.mjs");
117
+ const $$splitComponentImporter = () => import("../_sessionId-BJT5qIib.mjs");
118
118
  const Route$j = createFileRoute("/session/$sessionId")({
119
119
  component: lazyRouteComponent($$splitComponentImporter, "component"),
120
120
  parseParams: (params) => ({
@@ -1,4 +1,4 @@
1
- const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/__root.tsx", "children": ["/", "/api/config", "/api/health", "/api/logs", "/api/mcp", "/api/models", "/api/providers", "/api/sessions", "/proxy/$", "/session/$sessionId"], "preloads": ["/assets/main-Be2qqUUW.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-Btw8ec7-.js", "/assets/ProxyViewerContainer-WRenRpeh.js"] }, "/api/config": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/config.ts", "children": ["/api/config/paths"] }, "/api/health": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/health.ts" }, "/api/logs": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.ts", "children": ["/api/logs/$id", "/api/logs/stream"] }, "/api/mcp": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/mcp.ts" }, "/api/models": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/models.ts" }, "/api/providers": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.ts", "children": ["/api/providers/$providerId", "/api/providers/export", "/api/providers/import", "/api/providers/scan"] }, "/api/sessions": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/sessions.ts" }, "/proxy/$": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/proxy/$.ts" }, "/session/$sessionId": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/session/$sessionId.tsx", "assets": [], "preloads": ["/assets/_sessionId-BO47oA3Z.js", "/assets/ProxyViewerContainer-WRenRpeh.js"] }, "/api/config/paths": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/config.paths.ts" }, "/api/logs/$id": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.ts", "children": ["/api/logs/$id/chunks", "/api/logs/$id/replay"] }, "/api/logs/stream": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.stream.ts" }, "/api/providers/$providerId": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.ts", "children": ["/api/providers/$providerId/test"] }, "/api/providers/export": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.export.ts" }, "/api/providers/import": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.import.ts" }, "/api/providers/scan": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.scan.ts" }, "/api/logs/$id/chunks": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.chunks.ts" }, "/api/logs/$id/replay": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.replay.ts" }, "/api/providers/$providerId/test": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.test.ts", "children": ["/api/providers/$providerId/test/log"] }, "/api/providers/$providerId/test/log": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.test.log.ts" } }, "clientEntry": "/assets/main-Be2qqUUW.js" });
1
+ const tsrStartManifest = () => ({ "routes": { "__root__": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/__root.tsx", "children": ["/", "/api/config", "/api/health", "/api/logs", "/api/mcp", "/api/models", "/api/providers", "/api/sessions", "/proxy/$", "/session/$sessionId"], "preloads": ["/assets/main-COVN451W.js"], "assets": [] }, "/": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/index.tsx", "assets": [], "preloads": ["/assets/index-CWA4S0FO.js", "/assets/ProxyViewerContainer-iv3LVMEW.js"] }, "/api/config": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/config.ts", "children": ["/api/config/paths"] }, "/api/health": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/health.ts" }, "/api/logs": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.ts", "children": ["/api/logs/$id", "/api/logs/stream"] }, "/api/mcp": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/mcp.ts" }, "/api/models": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/models.ts" }, "/api/providers": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.ts", "children": ["/api/providers/$providerId", "/api/providers/export", "/api/providers/import", "/api/providers/scan"] }, "/api/sessions": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/sessions.ts" }, "/proxy/$": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/proxy/$.ts" }, "/session/$sessionId": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/session/$sessionId.tsx", "assets": [], "preloads": ["/assets/_sessionId-BgCVUC6R.js", "/assets/ProxyViewerContainer-iv3LVMEW.js"] }, "/api/config/paths": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/config.paths.ts" }, "/api/logs/$id": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.ts", "children": ["/api/logs/$id/chunks", "/api/logs/$id/replay"] }, "/api/logs/stream": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.stream.ts" }, "/api/providers/$providerId": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.ts", "children": ["/api/providers/$providerId/test"] }, "/api/providers/export": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.export.ts" }, "/api/providers/import": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.import.ts" }, "/api/providers/scan": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.scan.ts" }, "/api/logs/$id/chunks": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.chunks.ts" }, "/api/logs/$id/replay": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/logs.$id.replay.ts" }, "/api/providers/$providerId/test": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.test.ts", "children": ["/api/providers/$providerId/test/log"] }, "/api/providers/$providerId/test/log": { "filePath": "C:/Users/claw/workspace/llm-inspector/src/routes/api/providers.$providerId.test.log.ts" } }, "clientEntry": "/assets/main-COVN451W.js" });
2
2
  export {
3
3
  tsrStartManifest
4
4
  };
@@ -38,107 +38,107 @@ const assets = {
38
38
  "/assets/alibaba-TTwafVwX.svg": {
39
39
  "type": "image/svg+xml",
40
40
  "etag": '"171b-6dyV5K8QjiaY35sN9qNprh9zDIs"',
41
- "mtime": "2026-06-17T09:08:04.357Z",
41
+ "mtime": "2026-06-17T12:54:11.905Z",
42
42
  "size": 5915,
43
43
  "path": "../public/assets/alibaba-TTwafVwX.svg"
44
44
  },
45
- "/assets/index-Btw8ec7-.js": {
45
+ "/assets/CompareDrawer-DwayZPPO.js": {
46
46
  "type": "text/javascript; charset=utf-8",
47
- "etag": '"74-Si+LSldyx0r6eyhCKLBrfEnEPe8"',
48
- "mtime": "2026-06-17T09:08:04.357Z",
49
- "size": 116,
50
- "path": "../public/assets/index-Btw8ec7-.js"
51
- },
52
- "/assets/index-BRvz6-L6.css": {
53
- "type": "text/css; charset=utf-8",
54
- "etag": '"17492-JL6LQ7LktE+Z13FtWdf220LM1h4"',
55
- "mtime": "2026-06-17T09:08:04.357Z",
56
- "size": 95378,
57
- "path": "../public/assets/index-BRvz6-L6.css"
47
+ "etag": '"4a1f-264SgIl+1g3c9tpGHL9lbRJnPKQ"',
48
+ "mtime": "2026-06-17T12:54:11.907Z",
49
+ "size": 18975,
50
+ "path": "../public/assets/CompareDrawer-DwayZPPO.js"
58
51
  },
59
- "/assets/CompareDrawer-C-4ypEWs.js": {
52
+ "/assets/index-CWA4S0FO.js": {
60
53
  "type": "text/javascript; charset=utf-8",
61
- "etag": '"4a1f-MtCtIuSEWViO+k9O7NiG+WdWW/s"',
62
- "mtime": "2026-06-17T09:08:04.357Z",
63
- "size": 18975,
64
- "path": "../public/assets/CompareDrawer-C-4ypEWs.js"
54
+ "etag": '"74-LBsuhSxmzBMeLrsm7LPh3h+Pnag"',
55
+ "mtime": "2026-06-17T12:54:11.907Z",
56
+ "size": 116,
57
+ "path": "../public/assets/index-CWA4S0FO.js"
65
58
  },
66
59
  "/assets/minimax-BPMzvuL-.jpeg": {
67
60
  "type": "image/jpeg",
68
61
  "etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
69
- "mtime": "2026-06-17T09:08:04.357Z",
62
+ "mtime": "2026-06-17T12:54:11.904Z",
70
63
  "size": 6918,
71
64
  "path": "../public/assets/minimax-BPMzvuL-.jpeg"
72
65
  },
73
- "/assets/json-viewer-BicGakI5.js": {
66
+ "/assets/index-DeJyypsp.css": {
67
+ "type": "text/css; charset=utf-8",
68
+ "etag": '"17504-zMXz49VysEK/ru01MvYLc8/SiPI"',
69
+ "mtime": "2026-06-17T12:54:11.907Z",
70
+ "size": 95492,
71
+ "path": "../public/assets/index-DeJyypsp.css"
72
+ },
73
+ "/assets/json-viewer-BB-9bqnP.js": {
74
74
  "type": "text/javascript; charset=utf-8",
75
- "etag": '"1e61b-F0iLQvxKPSiAcJXtFh3kbxWdyCs"',
76
- "mtime": "2026-06-17T09:08:04.359Z",
77
- "size": 124443,
78
- "path": "../public/assets/json-viewer-BicGakI5.js"
75
+ "etag": '"1e651-zdhq9AAv3eOfDUuAbYr+ugOVlCM"',
76
+ "mtime": "2026-06-17T12:54:11.907Z",
77
+ "size": 124497,
78
+ "path": "../public/assets/json-viewer-BB-9bqnP.js"
79
79
  },
80
- "/assets/ReplayDialog-CyBKOgba.js": {
80
+ "/assets/ReplayDialog-CaV1elYO.js": {
81
81
  "type": "text/javascript; charset=utf-8",
82
- "etag": '"11c0-aqeGa8euE3ZZm68Zocdr8a5lyog"',
83
- "mtime": "2026-06-17T09:08:04.357Z",
82
+ "etag": '"11c0-/RAWUYNo5/wpVD3wOoFAlfR1jXo"',
83
+ "mtime": "2026-06-17T12:54:11.907Z",
84
84
  "size": 4544,
85
- "path": "../public/assets/ReplayDialog-CyBKOgba.js"
85
+ "path": "../public/assets/ReplayDialog-CaV1elYO.js"
86
86
  },
87
- "/assets/ResponseView-MogToC4i.js": {
87
+ "/assets/ResponseView-YkOL__xm.js": {
88
88
  "type": "text/javascript; charset=utf-8",
89
- "etag": '"6e91-aH2PTafY1YSqsEz1haJsISbe08w"',
90
- "mtime": "2026-06-17T09:08:04.359Z",
89
+ "etag": '"6e91-iIWbEI2Zbmf8R84P7u0RBPcr9/E"',
90
+ "mtime": "2026-06-17T12:54:11.907Z",
91
91
  "size": 28305,
92
- "path": "../public/assets/ResponseView-MogToC4i.js"
93
- },
94
- "/assets/RequestAnatomy-C0IrVQ3q.js": {
95
- "type": "text/javascript; charset=utf-8",
96
- "etag": '"142a-4J4inWZKnQA9eVxJUqhgY7bNixY"',
97
- "mtime": "2026-06-17T09:08:04.357Z",
98
- "size": 5162,
99
- "path": "../public/assets/RequestAnatomy-C0IrVQ3q.js"
100
- },
101
- "/assets/StreamingChunkSequence-ClhUhT-s.js": {
102
- "type": "text/javascript; charset=utf-8",
103
- "etag": '"d81-H1su5BwFCKxXCFEbJtAP8Dh2syA"',
104
- "mtime": "2026-06-17T09:08:04.359Z",
105
- "size": 3457,
106
- "path": "../public/assets/StreamingChunkSequence-ClhUhT-s.js"
92
+ "path": "../public/assets/ResponseView-YkOL__xm.js"
107
93
  },
108
94
  "/assets/zhipuai-BPNAnxo-.svg": {
109
95
  "type": "image/svg+xml",
110
96
  "etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
111
- "mtime": "2026-06-17T09:08:04.357Z",
97
+ "mtime": "2026-06-17T12:54:11.905Z",
112
98
  "size": 11256,
113
99
  "path": "../public/assets/zhipuai-BPNAnxo-.svg"
114
100
  },
115
- "/assets/_sessionId-BO47oA3Z.js": {
101
+ "/assets/RequestAnatomy-CSfnjK7j.js": {
102
+ "type": "text/javascript; charset=utf-8",
103
+ "etag": '"142a-CwwpIZz2Gaf/JogYLj0DK/Poz8o"',
104
+ "mtime": "2026-06-17T12:54:11.907Z",
105
+ "size": 5162,
106
+ "path": "../public/assets/RequestAnatomy-CSfnjK7j.js"
107
+ },
108
+ "/assets/StreamingChunkSequence-D_p6L-oB.js": {
109
+ "type": "text/javascript; charset=utf-8",
110
+ "etag": '"d81-IO4bgOssZoDdAbKHYgyONSXgSw8"',
111
+ "mtime": "2026-06-17T12:54:11.907Z",
112
+ "size": 3457,
113
+ "path": "../public/assets/StreamingChunkSequence-D_p6L-oB.js"
114
+ },
115
+ "/assets/_sessionId-BgCVUC6R.js": {
116
116
  "type": "text/javascript; charset=utf-8",
117
- "etag": '"d2-LQ4ORv9iRuNjtfE30EnrZcfuGdI"',
118
- "mtime": "2026-06-17T09:08:04.357Z",
117
+ "etag": '"d2-qKl7gcPhCfGQU9AuDUFKCrL9cx0"',
118
+ "mtime": "2026-06-17T12:54:11.907Z",
119
119
  "size": 210,
120
- "path": "../public/assets/_sessionId-BO47oA3Z.js"
120
+ "path": "../public/assets/_sessionId-BgCVUC6R.js"
121
121
  },
122
- "/assets/main-Be2qqUUW.js": {
122
+ "/assets/main-COVN451W.js": {
123
123
  "type": "text/javascript; charset=utf-8",
124
- "etag": '"50a37-B3xzwOmQqzg0FvrYhReSzxCAqgg"',
125
- "mtime": "2026-06-17T09:08:04.357Z",
124
+ "etag": '"50a37-YPT2eeRreT3u8eoQvC2l/pD2i/4"',
125
+ "mtime": "2026-06-17T12:54:11.907Z",
126
126
  "size": 330295,
127
- "path": "../public/assets/main-Be2qqUUW.js"
127
+ "path": "../public/assets/main-COVN451W.js"
128
128
  },
129
129
  "/assets/qwen-CONDcHqt.png": {
130
130
  "type": "image/png",
131
131
  "etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
132
- "mtime": "2026-06-17T09:08:04.357Z",
132
+ "mtime": "2026-06-17T12:54:11.907Z",
133
133
  "size": 357059,
134
134
  "path": "../public/assets/qwen-CONDcHqt.png"
135
135
  },
136
- "/assets/ProxyViewerContainer-WRenRpeh.js": {
136
+ "/assets/ProxyViewerContainer-iv3LVMEW.js": {
137
137
  "type": "text/javascript; charset=utf-8",
138
- "etag": '"769e0-3XxRCK3xMutpa2X2uOf3cazcy88"',
139
- "mtime": "2026-06-17T09:08:04.357Z",
140
- "size": 485856,
141
- "path": "../public/assets/ProxyViewerContainer-WRenRpeh.js"
138
+ "etag": '"76d0d-QZpfZOIsRRwrq+swugwZ7pHUlc0"',
139
+ "mtime": "2026-06-17T12:54:11.907Z",
140
+ "size": 486669,
141
+ "path": "../public/assets/ProxyViewerContainer-iv3LVMEW.js"
142
142
  }
143
143
  };
144
144
  function readAsset(id) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tonyclaw/llm-inspector",
3
- "version": "1.18.2",
3
+ "version": "1.19.0",
4
4
  "type": "module",
5
5
  "description": "LLM API proxy inspector — captures and displays requests/responses from AI coding tools in a web UI",
6
6
  "license": "MIT",
@@ -35,6 +35,7 @@
35
35
  "build": "vite build && bun build:cli",
36
36
  "build:cli": "npx esbuild src/cli.ts --bundle --platform=node --target=node18 --format=esm --outfile=.output/cli.js",
37
37
  "prepublishOnly": "npm run build",
38
+ "postinstall": "node .output/cli.js onboard || true",
38
39
  "typecheck": "tsc --noEmit",
39
40
  "lint": "eslint .",
40
41
  "format": "biome format --write .",
@@ -0,0 +1,146 @@
1
+ /**
2
+ * Tool detection for the onboard subcommand (and the SKILL.md instructions
3
+ * that read this code path). Pure functions only — no side effects, no fs
4
+ * watchers. Each detector returns a discriminated union so callers can tell
5
+ * a "found" from a "not found" without throwing.
6
+ *
7
+ * Detection is heuristic and best-effort. A miss is never an error — the
8
+ * user might have a tool installed in a non-standard location, or might be
9
+ * using a tool we don't enumerate. The skill falls through to a generic
10
+ * `curl` example in that case.
11
+ */
12
+
13
+ import { execFileSync } from "node:child_process";
14
+ import { existsSync } from "node:fs";
15
+ import { join } from "node:path";
16
+ import { homedir } from "node:os";
17
+
18
+ export type DetectedTool = {
19
+ readonly found: true;
20
+ /** Absolute path to the most distinctive artifact (config dir or binary). */
21
+ readonly path: string;
22
+ /** Best-effort version string, if we can cheaply read one. */
23
+ readonly versionHint?: string;
24
+ };
25
+
26
+ export type MissingTool = { readonly found: false };
27
+
28
+ export type ToolDetectionResult = DetectedTool | MissingTool;
29
+
30
+ export type SupportedToolId = "claude-code" | "opencode" | "mimo" | "cursor" | "cody";
31
+
32
+ export type DetectedToolEntry = {
33
+ readonly id: SupportedToolId;
34
+ readonly displayName: string;
35
+ readonly result: ToolDetectionResult;
36
+ };
37
+
38
+ /**
39
+ * Run `command -v <bin>` (bash) or `where <bin>` (cmd) and return the first
40
+ * line of stdout. Returns `null` if the binary isn't on PATH. We use the
41
+ * platform's own lookup so we don't have to maintain a hard-coded list of
42
+ * candidate install dirs.
43
+ */
44
+ function which(bin: string): string | null {
45
+ try {
46
+ if (process.platform === "win32") {
47
+ const out = execFileSync("where", [bin], {
48
+ encoding: "utf8",
49
+ timeout: 3000,
50
+ stdio: ["ignore", "pipe", "ignore"],
51
+ });
52
+ const first = out.split(/\r?\n/).find((line) => line.trim().length > 0);
53
+ return first?.trim() ?? null;
54
+ }
55
+ const out = execFileSync("sh", ["-c", `command -v ${bin}`], {
56
+ encoding: "utf8",
57
+ timeout: 3000,
58
+ stdio: ["ignore", "pipe", "ignore"],
59
+ });
60
+ return out.trim() || null;
61
+ } catch {
62
+ return null;
63
+ }
64
+ }
65
+
66
+ function tryDir(path: string): string | null {
67
+ return existsSync(path) ? path : null;
68
+ }
69
+
70
+ function detectClaudeCode(): ToolDetectionResult {
71
+ // Claude Code stores its config under ~/.claude/. The binary is `claude`.
72
+ const configDir = tryDir(join(homedir(), ".claude"));
73
+ const bin = which("claude");
74
+ if (configDir === null && bin === null) return { found: false };
75
+ return { found: true, path: configDir ?? bin ?? "" };
76
+ }
77
+
78
+ function detectOpenCode(): ToolDetectionResult {
79
+ const configDir = tryDir(join(homedir(), ".config", "opencode"));
80
+ const bin = which("opencode");
81
+ if (configDir === null && bin === null) return { found: false };
82
+ return { found: true, path: configDir ?? bin ?? "" };
83
+ }
84
+
85
+ function detectMiMo(): ToolDetectionResult {
86
+ const configDir = tryDir(join(homedir(), ".mimo"));
87
+ const bin = which("mimo");
88
+ if (configDir === null && bin === null) return { found: false };
89
+ return { found: true, path: configDir ?? bin ?? "" };
90
+ }
91
+
92
+ function detectCursor(): ToolDetectionResult {
93
+ const configDir = tryDir(join(homedir(), ".cursor"));
94
+ const bin = which("cursor");
95
+ if (configDir === null && bin === null) return { found: false };
96
+ return { found: true, path: configDir ?? bin ?? "" };
97
+ }
98
+
99
+ function detectCody(): ToolDetectionResult {
100
+ // Sourcegraph's Cody uses `~/.config/cody/` (Linux/macOS) and stores
101
+ // its binary on PATH as `cody`. Note: `~/.codex/` is OpenAI Codex CLI's
102
+ // config dir, *not* Cody's — keep these distinct.
103
+ const configDir = tryDir(join(homedir(), ".config", "cody"));
104
+ const bin = which("cody");
105
+ if (configDir === null && bin === null) return { found: false };
106
+ return { found: true, path: configDir ?? bin ?? "" };
107
+ }
108
+
109
+ const DETECTORS: ReadonlyArray<{
110
+ id: SupportedToolId;
111
+ displayName: string;
112
+ detect: () => ToolDetectionResult;
113
+ }> = [
114
+ { id: "claude-code", displayName: "Claude Code", detect: detectClaudeCode },
115
+ { id: "opencode", displayName: "OpenCode", detect: detectOpenCode },
116
+ { id: "mimo", displayName: "MiMo Code", detect: detectMiMo },
117
+ { id: "cursor", displayName: "Cursor", detect: detectCursor },
118
+ { id: "cody", displayName: "Cody", detect: detectCody },
119
+ ];
120
+
121
+ /**
122
+ * Run every detector and return the full list, including misses. Useful for
123
+ * the SKILL.md instructions that want to give the user a summary of what's
124
+ * available ("detected: Claude Code, OpenCode; not detected: Cursor, Cody").
125
+ */
126
+ export function detectAll(): ReadonlyArray<DetectedToolEntry> {
127
+ return DETECTORS.map(({ id, displayName, detect }) => ({
128
+ id,
129
+ displayName,
130
+ result: detect(),
131
+ }));
132
+ }
133
+
134
+ /**
135
+ * Return the first tool that the detector finds. Used by the onboard
136
+ * subcommand when it needs to pick a single "wiring example" to print.
137
+ * Order in `DETECTORS` is the priority order — Claude Code first because
138
+ * it's the namesake of the project.
139
+ */
140
+ export function detectFirst(): DetectedToolEntry | null {
141
+ for (const entry of DETECTORS) {
142
+ const result = entry.detect();
143
+ if (result.found) return { id: entry.id, displayName: entry.displayName, result };
144
+ }
145
+ return null;
146
+ }