@tonyclaw/agent-inspector 2.0.4 → 2.0.6

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 (61) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/{CompareDrawer-BCH_fsLm.js → CompareDrawer-DDmqSAfl.js} +1 -1
  3. package/.output/public/assets/ProxyViewerContainer-Cxpdziwd.js +101 -0
  4. package/.output/public/assets/ReplayDialog-Bt5DGzlh.js +1 -0
  5. package/.output/public/assets/RequestAnatomy-BxX3_N9S.js +1 -0
  6. package/.output/public/assets/ResponseView-Bl_5S9gZ.js +1 -0
  7. package/.output/public/assets/StreamingChunkSequence-RJMwNf6F.js +1 -0
  8. package/.output/public/assets/_sessionId-b4isaoDp.js +1 -0
  9. package/.output/public/assets/index-BZ4x5UI6.js +1 -0
  10. package/.output/public/assets/{index-CobXD0yH.css → index-C624DUk9.css} +1 -1
  11. package/.output/public/assets/{json-viewer-BrzjD7qI.js → json-viewer-CRL_gWEZ.js} +1 -1
  12. package/.output/public/assets/{main-mgxeUdZQ.js → main-CKnTJ4-O.js} +6 -6
  13. package/.output/server/_libs/lucide-react.mjs +181 -114
  14. package/.output/server/{_sessionId-C4xsxIWm.mjs → _sessionId-B-x9fRY3.mjs} +3 -3
  15. package/.output/server/_ssr/{CompareDrawer-DuWEpqQ7.mjs → CompareDrawer-BQVNsAY2.mjs} +6 -6
  16. package/.output/server/_ssr/{ProxyViewerContainer-Cckz5qKu.mjs → ProxyViewerContainer-CYm2Dw19.mjs} +766 -122
  17. package/.output/server/_ssr/{ReplayDialog-BDRcr8E5.mjs → ReplayDialog-CaMQBc79.mjs} +240 -14
  18. package/.output/server/_ssr/{RequestAnatomy-BoO2_Ij0.mjs → RequestAnatomy--P5arRH2.mjs} +236 -66
  19. package/.output/server/_ssr/{ResponseView-DZiPBxvO.mjs → ResponseView-RtFwNvgD.mjs} +8 -8
  20. package/.output/server/_ssr/{StreamingChunkSequence-D-be7KEL.mjs → StreamingChunkSequence-B5HPkzab.mjs} +3 -3
  21. package/.output/server/_ssr/{index-5RImHKfu.mjs → index-CZIKZU43.mjs} +2 -2
  22. package/.output/server/_ssr/index.mjs +2 -2
  23. package/.output/server/_ssr/{json-viewer-aJhb93ZK.mjs → json-viewer-d4obyRaA.mjs} +3 -3
  24. package/.output/server/_ssr/{router-Dgkv5nKP.mjs → router-DGPt3MUc.mjs} +145 -71
  25. package/.output/server/_tanstack-start-manifest_v-BzH4pNaI.mjs +4 -0
  26. package/.output/server/index.mjs +64 -64
  27. package/package.json +1 -1
  28. package/src/components/OnboardingBanner.tsx +11 -19
  29. package/src/components/ProxyViewer.tsx +1 -1
  30. package/src/components/providers/ProviderCard.tsx +6 -20
  31. package/src/components/providers/SettingsDialog.tsx +95 -2
  32. package/src/components/proxy-viewer/AgentTraceSummary.tsx +639 -38
  33. package/src/components/proxy-viewer/CompareDrawer.tsx +4 -2
  34. package/src/components/proxy-viewer/LogEntry.tsx +4 -4
  35. package/src/components/proxy-viewer/LogEntryHeader.tsx +15 -25
  36. package/src/components/proxy-viewer/ReplayDialog.tsx +190 -8
  37. package/src/components/proxy-viewer/ResponseView.tsx +2 -2
  38. package/src/components/proxy-viewer/ToolTraceEvents.tsx +37 -16
  39. package/src/components/proxy-viewer/TurnGroup.tsx +14 -2
  40. package/src/components/proxy-viewer/anatomy/RequestAnatomy.tsx +196 -45
  41. package/src/components/proxy-viewer/anatomy/SegmentBar.tsx +92 -67
  42. package/src/components/proxy-viewer/anatomy/types.ts +15 -13
  43. package/src/components/proxy-viewer/formats/anthropic/ResponseView.tsx +2 -2
  44. package/src/components/proxy-viewer/log-formats/anthropic.ts +1 -1
  45. package/src/components/proxy-viewer/log-formats/openai.ts +1 -1
  46. package/src/components/proxy-viewer/log-formats/types.ts +1 -1
  47. package/src/components/proxy-viewer/replayComparison.ts +131 -0
  48. package/src/components/proxy-viewer/useKeyboardNavigation.ts +64 -22
  49. package/src/components/proxy-viewer/viewerState.ts +14 -2
  50. package/src/components/ui/json-viewer.tsx +1 -1
  51. package/src/knowledge/candidateStore.ts +32 -1
  52. package/src/routes/api/knowledge.candidates.$candidateId.ts +50 -0
  53. package/src/routes/api/knowledge.sessions.$sessionId.candidates.ts +12 -2
  54. package/.output/public/assets/ProxyViewerContainer-D85_UANk.js +0 -101
  55. package/.output/public/assets/ReplayDialog-DTeaHHit.js +0 -1
  56. package/.output/public/assets/RequestAnatomy-DZ8grAih.js +0 -1
  57. package/.output/public/assets/ResponseView-Cldm6RCi.js +0 -1
  58. package/.output/public/assets/StreamingChunkSequence-3x4p-yT7.js +0 -1
  59. package/.output/public/assets/_sessionId-YqWFBu6d.js +0 -1
  60. package/.output/public/assets/index-BIw2H6jO.js +0 -1
  61. package/.output/server/_tanstack-start-manifest_v-B8rrWXjr.mjs +0 -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-20T09:50:40.188Z",
41
+ "mtime": "2026-06-21T03:27:09.298Z",
42
42
  "size": 5915,
43
43
  "path": "../public/assets/alibaba-TTwafVwX.svg"
44
44
  },
45
- "/assets/index-BIw2H6jO.js": {
45
+ "/assets/CompareDrawer-DDmqSAfl.js": {
46
46
  "type": "text/javascript; charset=utf-8",
47
- "etag": '"74-4Z3U3XPh22QGtEz8rgtC6KUxxBk"',
48
- "mtime": "2026-06-20T09:50:40.189Z",
47
+ "etag": '"4a25-ax+lNTJqeO5Uw5iRn0IINDghlL8"',
48
+ "mtime": "2026-06-21T03:27:09.300Z",
49
+ "size": 18981,
50
+ "path": "../public/assets/CompareDrawer-DDmqSAfl.js"
51
+ },
52
+ "/assets/index-BZ4x5UI6.js": {
53
+ "type": "text/javascript; charset=utf-8",
54
+ "etag": '"74-I7Q+PS5hgyBfKRdQxaKtu+fOxCI"',
55
+ "mtime": "2026-06-21T03:27:09.300Z",
49
56
  "size": 116,
50
- "path": "../public/assets/index-BIw2H6jO.js"
57
+ "path": "../public/assets/index-BZ4x5UI6.js"
51
58
  },
52
- "/assets/index-CobXD0yH.css": {
59
+ "/assets/index-C624DUk9.css": {
53
60
  "type": "text/css; charset=utf-8",
54
- "etag": '"17587-wM3UwOtYjpQy81oA4sjkIdizScg"',
55
- "mtime": "2026-06-20T09:50:40.188Z",
56
- "size": 95623,
57
- "path": "../public/assets/index-CobXD0yH.css"
61
+ "etag": '"17b64-fA2ShN0vgWgtCNH7S8ke3+06+1g"',
62
+ "mtime": "2026-06-21T03:27:09.300Z",
63
+ "size": 97124,
64
+ "path": "../public/assets/index-C624DUk9.css"
65
+ },
66
+ "/assets/ReplayDialog-Bt5DGzlh.js": {
67
+ "type": "text/javascript; charset=utf-8",
68
+ "etag": '"2383-209uDqfCNP9kp/Eo1OJGkQf5K7o"',
69
+ "mtime": "2026-06-21T03:27:09.300Z",
70
+ "size": 9091,
71
+ "path": "../public/assets/ReplayDialog-Bt5DGzlh.js"
72
+ },
73
+ "/assets/RequestAnatomy-BxX3_N9S.js": {
74
+ "type": "text/javascript; charset=utf-8",
75
+ "etag": '"21df-RsC1hle1XaaRP0DDNQAtrI26Ohw"',
76
+ "mtime": "2026-06-21T03:27:09.300Z",
77
+ "size": 8671,
78
+ "path": "../public/assets/RequestAnatomy-BxX3_N9S.js"
58
79
  },
59
80
  "/assets/minimax-BPMzvuL-.jpeg": {
60
81
  "type": "image/jpeg",
61
82
  "etag": '"1b06-IwivU89ko5UTMUM1/t7hn4sQK9A"',
62
- "mtime": "2026-06-20T09:50:40.188Z",
83
+ "mtime": "2026-06-21T03:27:09.300Z",
63
84
  "size": 6918,
64
85
  "path": "../public/assets/minimax-BPMzvuL-.jpeg"
65
86
  },
66
- "/assets/json-viewer-BrzjD7qI.js": {
67
- "type": "text/javascript; charset=utf-8",
68
- "etag": '"1e652-kToNy9EOWKlmvVVK2ggoK6Yj4is"',
69
- "mtime": "2026-06-20T09:50:40.189Z",
70
- "size": 124498,
71
- "path": "../public/assets/json-viewer-BrzjD7qI.js"
72
- },
73
- "/assets/main-mgxeUdZQ.js": {
87
+ "/assets/json-viewer-CRL_gWEZ.js": {
74
88
  "type": "text/javascript; charset=utf-8",
75
- "etag": '"5138c-8pFfB8xlDwdi154QNl3icGhbrO0"',
76
- "mtime": "2026-06-20T09:50:40.189Z",
77
- "size": 332684,
78
- "path": "../public/assets/main-mgxeUdZQ.js"
79
- },
80
- "/assets/RequestAnatomy-DZ8grAih.js": {
81
- "type": "text/javascript; charset=utf-8",
82
- "etag": '"1426-KgPrtOak3tXSA1eBiDgPYDF0NzY"',
83
- "mtime": "2026-06-20T09:50:40.189Z",
84
- "size": 5158,
85
- "path": "../public/assets/RequestAnatomy-DZ8grAih.js"
86
- },
87
- "/assets/ReplayDialog-DTeaHHit.js": {
88
- "type": "text/javascript; charset=utf-8",
89
- "etag": '"11c0-vzfqRFtK58XnhNRimd5URd22Gcs"',
90
- "mtime": "2026-06-20T09:50:40.189Z",
91
- "size": 4544,
92
- "path": "../public/assets/ReplayDialog-DTeaHHit.js"
89
+ "etag": '"1e653-xRVAXa9/k/0cz9lZfPZsShTfToA"',
90
+ "mtime": "2026-06-21T03:27:09.301Z",
91
+ "size": 124499,
92
+ "path": "../public/assets/json-viewer-CRL_gWEZ.js"
93
93
  },
94
- "/assets/ResponseView-Cldm6RCi.js": {
94
+ "/assets/StreamingChunkSequence-RJMwNf6F.js": {
95
95
  "type": "text/javascript; charset=utf-8",
96
- "etag": '"6b01-Qix5qsvqjrCTAlqfCJ+Pp8h1e9I"',
97
- "mtime": "2026-06-20T09:50:40.189Z",
98
- "size": 27393,
99
- "path": "../public/assets/ResponseView-Cldm6RCi.js"
96
+ "etag": '"d82-23sq9u+7FJWOVlw2ZwY9VyBv1us"',
97
+ "mtime": "2026-06-21T03:27:09.300Z",
98
+ "size": 3458,
99
+ "path": "../public/assets/StreamingChunkSequence-RJMwNf6F.js"
100
100
  },
101
- "/assets/StreamingChunkSequence-3x4p-yT7.js": {
101
+ "/assets/ResponseView-Bl_5S9gZ.js": {
102
102
  "type": "text/javascript; charset=utf-8",
103
- "etag": '"d81-mHjIspQgaAOB4LmN6Cfnz+NcWOM"',
104
- "mtime": "2026-06-20T09:50:40.189Z",
105
- "size": 3457,
106
- "path": "../public/assets/StreamingChunkSequence-3x4p-yT7.js"
103
+ "etag": '"6aab-UCFRuWGhCGLKb2s5NCp1phbPUzQ"',
104
+ "mtime": "2026-06-21T03:27:09.300Z",
105
+ "size": 27307,
106
+ "path": "../public/assets/ResponseView-Bl_5S9gZ.js"
107
107
  },
108
108
  "/assets/zhipuai-BPNAnxo-.svg": {
109
109
  "type": "image/svg+xml",
110
110
  "etag": '"2bf8-hNaLCTi89nOFCsIIfWpP/jrfo0s"',
111
- "mtime": "2026-06-20T09:50:40.188Z",
111
+ "mtime": "2026-06-21T03:27:09.298Z",
112
112
  "size": 11256,
113
113
  "path": "../public/assets/zhipuai-BPNAnxo-.svg"
114
114
  },
115
- "/assets/CompareDrawer-BCH_fsLm.js": {
115
+ "/assets/_sessionId-b4isaoDp.js": {
116
116
  "type": "text/javascript; charset=utf-8",
117
- "etag": '"4a1f-Y215Tlm1TY2GPfXfX4DX86bgJPU"',
118
- "mtime": "2026-06-20T09:50:40.189Z",
119
- "size": 18975,
120
- "path": "../public/assets/CompareDrawer-BCH_fsLm.js"
117
+ "etag": '"d2-p8zHXMHP91ArIYS6WLwFbKor58Y"',
118
+ "mtime": "2026-06-21T03:27:09.300Z",
119
+ "size": 210,
120
+ "path": "../public/assets/_sessionId-b4isaoDp.js"
121
121
  },
122
- "/assets/_sessionId-YqWFBu6d.js": {
122
+ "/assets/main-CKnTJ4-O.js": {
123
123
  "type": "text/javascript; charset=utf-8",
124
- "etag": '"d2-hOIbwqwgtPs0H/vPSZ1gDPz5pFU"',
125
- "mtime": "2026-06-20T09:50:40.189Z",
126
- "size": 210,
127
- "path": "../public/assets/_sessionId-YqWFBu6d.js"
124
+ "etag": '"5138c-MlPN81hCf/6HY5xIpWbk5sw0drc"',
125
+ "mtime": "2026-06-21T03:27:09.300Z",
126
+ "size": 332684,
127
+ "path": "../public/assets/main-CKnTJ4-O.js"
128
128
  },
129
129
  "/assets/qwen-CONDcHqt.png": {
130
130
  "type": "image/png",
131
131
  "etag": '"572c3-cdJAPaHdOvFCGzuaQjagdgOu6XE"',
132
- "mtime": "2026-06-20T09:50:40.188Z",
132
+ "mtime": "2026-06-21T03:27:09.300Z",
133
133
  "size": 357059,
134
134
  "path": "../public/assets/qwen-CONDcHqt.png"
135
135
  },
136
- "/assets/ProxyViewerContainer-D85_UANk.js": {
136
+ "/assets/ProxyViewerContainer-Cxpdziwd.js": {
137
137
  "type": "text/javascript; charset=utf-8",
138
- "etag": '"79ec4-8t+BfQ9tY8ia35/KlmoU69wDlc8"',
139
- "mtime": "2026-06-20T09:50:40.189Z",
140
- "size": 499396,
141
- "path": "../public/assets/ProxyViewerContainer-D85_UANk.js"
138
+ "etag": '"7d8f5-2o+HRUWRh8QXo5PbcEDo+/1GGt0"',
139
+ "mtime": "2026-06-21T03:27:09.300Z",
140
+ "size": 514293,
141
+ "path": "../public/assets/ProxyViewerContainer-Cxpdziwd.js"
142
142
  }
143
143
  };
144
144
  function readAsset(id) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tonyclaw/agent-inspector",
3
- "version": "2.0.4",
3
+ "version": "2.0.6",
4
4
  "type": "module",
5
5
  "description": "Agent observability and knowledge capture layer for AI coding tools.",
6
6
  "license": "MIT",
@@ -3,13 +3,8 @@ import type { JSX } from "react";
3
3
  import { useOnboarding } from "../lib/useOnboarding";
4
4
 
5
5
  /**
6
- * First-launch onboarding banner. Shows once on a fresh install (or
7
- * any user who hasn't yet dismissed it), explains the per-tab data
8
- * shapes the proxy captures, and disappears forever on dismissal.
9
- *
10
- * The "seen" state lives in the server's runtime config — see
11
- * `useOnboarding` — so the dismissal persists across browser sessions
12
- * and devices for the same install.
6
+ * First-launch onboarding banner. Shows once on a fresh install and persists
7
+ * dismissal through the server runtime config.
13
8
  */
14
9
  export function OnboardingBanner(): JSX.Element | null {
15
10
  const { hasSeenOnboarding, isLoading, markSeen } = useOnboarding();
@@ -22,22 +17,19 @@ export function OnboardingBanner(): JSX.Element | null {
22
17
  aria-label="Onboarding tip"
23
18
  className="mx-4 mt-2 mb-1 flex items-start gap-3 rounded-md border border-amber-500/30 bg-amber-500/5 px-4 py-3 text-sm"
24
19
  >
25
- <div className="flex-1 min-w-0">
26
- <div className="font-medium text-amber-600 dark:text-amber-400 mb-1">
27
- Quick tour of the log tabs
20
+ <div className="min-w-0 flex-1">
21
+ <div className="mb-1 font-medium text-amber-600 dark:text-amber-400">
22
+ Agent Inspector is ready
28
23
  </div>
29
- <ul className="space-y-0.5 text-muted-foreground text-xs leading-relaxed">
24
+ <ul className="space-y-0.5 text-xs leading-relaxed text-muted-foreground">
30
25
  <li>
31
- <strong>Request</strong> / <strong>Response</strong> structured views of what the
32
- proxy sent and received.
26
+ <strong>Trace</strong>: requests, responses, streaming chunks, tools, and timing.
33
27
  </li>
34
28
  <li>
35
- <strong>Headers</strong> request and response headers after proxy processing.
29
+ <strong>Replay</strong>: resend captured requests and compare provider behavior.
36
30
  </li>
37
31
  <li>
38
- <strong>Raw Headers</strong> / <strong>Raw Request</strong> /{" "}
39
- <strong>Raw Response</strong> — exact bytes from the upstream provider (visible in Full
40
- mode).
32
+ <strong>Memory</strong>: create reviewable candidates before promotion to OpenClaw.
41
33
  </li>
42
34
  </ul>
43
35
  </div>
@@ -46,7 +38,7 @@ export function OnboardingBanner(): JSX.Element | null {
46
38
  onClick={() => {
47
39
  void markSeen();
48
40
  }}
49
- className="inline-flex items-center gap-1.5 text-xs h-8 px-3 rounded-md border border-amber-500/40 text-amber-700 dark:text-amber-300 hover:bg-amber-500/10 transition-colors shrink-0"
41
+ className="inline-flex h-8 shrink-0 items-center gap-1.5 rounded-md border border-amber-500/40 px-3 text-xs text-amber-700 transition-colors hover:bg-amber-500/10 dark:text-amber-300"
50
42
  aria-label="Dismiss onboarding tip"
51
43
  >
52
44
  <Check className="size-3.5" />
@@ -57,7 +49,7 @@ export function OnboardingBanner(): JSX.Element | null {
57
49
  onClick={() => {
58
50
  void markSeen();
59
51
  }}
60
- className="text-muted-foreground hover:text-foreground transition-colors shrink-0 p-1 -m-1"
52
+ className="-m-1 shrink-0 p-1 text-muted-foreground transition-colors hover:text-foreground"
61
53
  aria-label="Dismiss"
62
54
  >
63
55
  <X className="size-3.5" />
@@ -253,7 +253,7 @@ export function ProxyViewer({
253
253
  );
254
254
  const logListRef = useRef<HTMLDivElement>(null);
255
255
  const logListWrapperRef = useRef<HTMLDivElement>(null);
256
- useKeyboardNavigation(logListRef, logListWrapperRef);
256
+ useKeyboardNavigation(logListRef, logListWrapperRef, { pageWide: true });
257
257
 
258
258
  useEffect(() => {
259
259
  const perCrabDuration = 400;
@@ -110,30 +110,16 @@ function TestStatus({ result }: { result: ProviderTestState }): JSX.Element {
110
110
  }
111
111
  if (result.cacheCreationInputTokens !== undefined && result.cacheCreationInputTokens > 0) {
112
112
  tokenParts.push(
113
- <TooltipProvider key="cache-create">
114
- <Tooltip>
115
- <TooltipTrigger asChild>
116
- <span className="font-mono tabular-nums text-emerald-400">
117
- +{result.cacheCreationInputTokens} cache
118
- </span>
119
- </TooltipTrigger>
120
- <TooltipContent>Tokens cached for reuse, reducing future API cost</TooltipContent>
121
- </Tooltip>
122
- </TooltipProvider>,
113
+ <span key="cache-create" className="font-mono tabular-nums text-emerald-400">
114
+ KV Cache +{result.cacheCreationInputTokens}
115
+ </span>,
123
116
  );
124
117
  }
125
118
  if (result.cacheReadInputTokens !== undefined && result.cacheReadInputTokens > 0) {
126
119
  tokenParts.push(
127
- <TooltipProvider key="cache-read">
128
- <Tooltip>
129
- <TooltipTrigger asChild>
130
- <span className="font-mono tabular-nums text-purple-400">
131
- ~{result.cacheReadInputTokens} cached
132
- </span>
133
- </TooltipTrigger>
134
- <TooltipContent>Tokens served from cache, reducing API cost</TooltipContent>
135
- </Tooltip>
136
- </TooltipProvider>,
120
+ <span key="cache-read" className="font-mono tabular-nums text-purple-400">
121
+ KV Cache ~{result.cacheReadInputTokens}
122
+ </span>,
137
123
  );
138
124
  }
139
125
  const displayTokens: ReactNode[] = [];
@@ -1,5 +1,5 @@
1
- import { type JSX, useState, useCallback } from "react";
2
- import { Settings } from "lucide-react";
1
+ import { type JSX, useState, useCallback, useMemo } from "react";
2
+ import { Check, Copy, Settings, Terminal } from "lucide-react";
3
3
  import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "../ui/dialog";
4
4
  import { Tabs, TabsList, TabsTrigger, TabsContent } from "../ui/tabs";
5
5
  import { Button } from "../ui/button";
@@ -72,6 +72,7 @@ export function SettingsDialog(): JSX.Element {
72
72
  <TabsList>
73
73
  <TabsTrigger value="providers">Providers</TabsTrigger>
74
74
  <TabsTrigger value="proxy">Proxy</TabsTrigger>
75
+ <TabsTrigger value="onboarding">Onboarding</TabsTrigger>
75
76
  </TabsList>
76
77
 
77
78
  <div className="mt-4 overflow-y-auto flex-1 pr-3">
@@ -93,6 +94,9 @@ export function SettingsDialog(): JSX.Element {
93
94
  <TabsContent value="proxy">
94
95
  <ProxySettingsTab />
95
96
  </TabsContent>
97
+ <TabsContent value="onboarding">
98
+ <OnboardingSettingsTab />
99
+ </TabsContent>
96
100
  </div>
97
101
  </Tabs>
98
102
  </DialogContent>
@@ -100,6 +104,95 @@ export function SettingsDialog(): JSX.Element {
100
104
  );
101
105
  }
102
106
 
107
+ function CopyableSetupValue({
108
+ id,
109
+ label,
110
+ value,
111
+ copiedId,
112
+ onCopy,
113
+ }: {
114
+ id: string;
115
+ label: string;
116
+ value: string;
117
+ copiedId: string | null;
118
+ onCopy: (id: string, value: string) => void;
119
+ }): JSX.Element {
120
+ const copied = copiedId === id;
121
+ return (
122
+ <div className="rounded-md border border-border bg-muted/20 px-3 py-2">
123
+ <div className="mb-1 text-xs font-medium text-muted-foreground">{label}</div>
124
+ <div className="flex min-w-0 items-center gap-2">
125
+ <code className="min-w-0 flex-1 truncate font-mono text-xs text-foreground">{value}</code>
126
+ <Button
127
+ type="button"
128
+ variant="ghost"
129
+ size="icon"
130
+ className="size-7 shrink-0"
131
+ onClick={() => onCopy(id, value)}
132
+ aria-label={copied ? `Copied ${label}` : `Copy ${label}`}
133
+ >
134
+ {copied ? <Check className="size-3.5 text-emerald-500" /> : <Copy className="size-3.5" />}
135
+ </Button>
136
+ </div>
137
+ </div>
138
+ );
139
+ }
140
+
141
+ function OnboardingSettingsTab(): JSX.Element {
142
+ const [copiedId, setCopiedId] = useState<string | null>(null);
143
+ const origin = useMemo(() => {
144
+ if (typeof window === "undefined") return "http://localhost:25947";
145
+ return window.location.origin;
146
+ }, []);
147
+ const values = useMemo(
148
+ () => [
149
+ { id: "skill", label: "Codex skill", value: "agent-inspector onboard --force" },
150
+ { id: "mcp", label: "MCP URL", value: `${origin}/api/mcp` },
151
+ { id: "proxy", label: "Proxy URL", value: `${origin}/proxy` },
152
+ { id: "anthropic", label: "Anthropic base", value: `ANTHROPIC_BASE_URL=${origin}/proxy` },
153
+ ],
154
+ [origin],
155
+ );
156
+
157
+ const handleCopy = useCallback((id: string, value: string) => {
158
+ void window.navigator.clipboard.writeText(value).then(() => {
159
+ setCopiedId(id);
160
+ setTimeout(() => setCopiedId(null), 1600);
161
+ });
162
+ }, []);
163
+
164
+ return (
165
+ <div className="space-y-4">
166
+ <div className="flex items-center gap-2">
167
+ <Terminal className="size-4 text-muted-foreground" />
168
+ <h3 className="text-sm font-semibold">Agent onboarding</h3>
169
+ </div>
170
+ <div className="grid gap-2">
171
+ {values.map((item) => (
172
+ <CopyableSetupValue
173
+ key={item.id}
174
+ id={item.id}
175
+ label={item.label}
176
+ value={item.value}
177
+ copiedId={copiedId}
178
+ onCopy={handleCopy}
179
+ />
180
+ ))}
181
+ </div>
182
+ <div className="grid gap-2 rounded-md border border-border bg-background px-3 py-2 text-xs text-muted-foreground">
183
+ <div className="flex items-center gap-2">
184
+ <Check className="size-3.5 text-emerald-500" />
185
+ <span>Provider test creates a traceable memory probe session.</span>
186
+ </div>
187
+ <div className="flex items-center gap-2">
188
+ <Check className="size-3.5 text-emerald-500" />
189
+ <span>Captured sessions can produce reviewable memory candidates.</span>
190
+ </div>
191
+ </div>
192
+ </div>
193
+ );
194
+ }
195
+
103
196
  function ProxySettingsTab(): JSX.Element {
104
197
  const {
105
198
  strip,