@tonyclaw/agent-inspector 2.1.14 → 2.1.16

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 (70) hide show
  1. package/.output/nitro.json +1 -1
  2. package/.output/public/assets/CompareDrawer-Ccrrcx1j.js +1 -0
  3. package/.output/public/assets/ProxyViewerContainer-DLqClc9A.js +106 -0
  4. package/.output/public/assets/ReplayDialog-C7axhr-l.js +1 -0
  5. package/.output/public/assets/{RequestAnatomy-BNahe83D.js → RequestAnatomy-WOptg8j_.js} +1 -1
  6. package/.output/public/assets/{ResponseView-DSOnGqi6.js → ResponseView-CSAcxh_M.js} +2 -2
  7. package/.output/public/assets/{StreamingChunkSequence-BEKTDklB.js → StreamingChunkSequence-DJS5KhPx.js} +1 -1
  8. package/.output/public/assets/_sessionId-DUSalzKH.js +1 -0
  9. package/.output/public/assets/index-BPpA21dY.css +1 -0
  10. package/.output/public/assets/index-Bt0Az2I2.js +1 -0
  11. package/.output/public/assets/{index-DWOkqdCa.js → index-DMPNh46t.js} +1 -1
  12. package/.output/public/assets/{json-viewer-C2JpgcW0.js → json-viewer-inX5QSa3.js} +1 -1
  13. package/.output/public/assets/{main-CSONBwwn.js → main-aCAKYGSD.js} +2 -2
  14. package/.output/server/_libs/lucide-react.mjs +224 -194
  15. package/.output/server/{_sessionId-CPAa37n5.mjs → _sessionId-C0fhvQnn.mjs} +2 -2
  16. package/.output/server/_ssr/{CompareDrawer-ceW5VxMo.mjs → CompareDrawer-CO-Ti5sg.mjs} +36 -15
  17. package/.output/server/_ssr/{ProxyViewerContainer-CDfEE_w-.mjs → ProxyViewerContainer-N4J7uBCX.mjs} +1153 -494
  18. package/.output/server/_ssr/{ReplayDialog-V0s_eEbR.mjs → ReplayDialog-J1VxC0In.mjs} +14 -7
  19. package/.output/server/_ssr/{RequestAnatomy-f1ccwR9d.mjs → RequestAnatomy-DBH-F3rq.mjs} +3 -3
  20. package/.output/server/_ssr/{ResponseView-BIRrqG4H.mjs → ResponseView-DLFwV7Hd.mjs} +3 -3
  21. package/.output/server/_ssr/{StreamingChunkSequence-V3JFjCgX.mjs → StreamingChunkSequence-BywmuND0.mjs} +3 -3
  22. package/.output/server/_ssr/{index-DsykulzS.mjs → index-CStymIc0.mjs} +2 -2
  23. package/.output/server/_ssr/index.mjs +2 -2
  24. package/.output/server/_ssr/{json-viewer-Dcnm0Ivf.mjs → json-viewer-DlQu0N1x.mjs} +3 -3
  25. package/.output/server/_ssr/{router-4bdm6Mt2.mjs → router-CQ4Zxhmr.mjs} +118 -47
  26. package/.output/server/{_tanstack-start-manifest_v-Xp4CO64V.mjs → _tanstack-start-manifest_v-BHeJBGfo.mjs} +1 -1
  27. package/.output/server/index.mjs +75 -75
  28. package/package.json +1 -1
  29. package/src/components/ProxyViewer.tsx +174 -107
  30. package/src/components/ProxyViewerContainer.tsx +77 -67
  31. package/src/components/alerts/AlertsDialog.tsx +2 -1
  32. package/src/components/clients/ClientLogo.tsx +132 -0
  33. package/src/components/groups/GroupsDialog.tsx +37 -14
  34. package/src/components/providers/ProviderCard.tsx +1 -1
  35. package/src/components/providers/ProviderForm.tsx +18 -18
  36. package/src/components/providers/ProviderLogo.tsx +6 -1
  37. package/src/components/providers/ProvidersPanel.tsx +6 -6
  38. package/src/components/providers/SettingsDialog.tsx +13 -6
  39. package/src/components/proxy-viewer/AgentTraceSummary.tsx +62 -29
  40. package/src/components/proxy-viewer/CompareDrawer.tsx +38 -8
  41. package/src/components/proxy-viewer/ConversationGroup.tsx +43 -32
  42. package/src/components/proxy-viewer/ConversationGroupList.tsx +452 -89
  43. package/src/components/proxy-viewer/ConversationHeader.tsx +65 -61
  44. package/src/components/proxy-viewer/LogEntry.tsx +31 -18
  45. package/src/components/proxy-viewer/LogEntryHeader.tsx +42 -49
  46. package/src/components/proxy-viewer/ProviderLogoStack.tsx +60 -0
  47. package/src/components/proxy-viewer/ReplayDialog.tsx +8 -2
  48. package/src/components/proxy-viewer/RequestToolsPanel.tsx +9 -9
  49. package/src/components/proxy-viewer/ThreadConnector.tsx +22 -11
  50. package/src/components/proxy-viewer/TurnGroup.tsx +30 -36
  51. package/src/components/proxy-viewer/TurnGroupList.tsx +3 -0
  52. package/src/components/proxy-viewer/viewerState.ts +5 -6
  53. package/src/components/ui/icon-trigger.ts +2 -0
  54. package/src/components/ui/transient-toast.tsx +104 -0
  55. package/src/lib/sessionInfoContract.ts +5 -0
  56. package/src/lib/stopReason.ts +48 -16
  57. package/src/mcp/server.ts +71 -27
  58. package/src/mcp/toolHandlers.ts +23 -4
  59. package/src/proxy/formats/openai/alibabaProvider.ts +0 -4
  60. package/src/proxy/sessionInfo.ts +36 -3
  61. package/src/proxy/sessionSupervisor.ts +20 -1
  62. package/src/proxy/store.ts +1 -1
  63. package/src/routes/api/providers.$providerId.test.log.ts +8 -4
  64. package/styles/globals.css +180 -180
  65. package/.output/public/assets/CompareDrawer-DjgjIFx7.js +0 -1
  66. package/.output/public/assets/ProxyViewerContainer-CWUQZLYy.js +0 -106
  67. package/.output/public/assets/ReplayDialog-CU0Tbb2c.js +0 -1
  68. package/.output/public/assets/_sessionId-Cif8JZdn.js +0 -1
  69. package/.output/public/assets/index-D_WfwzUi.js +0 -1
  70. package/.output/public/assets/index-DtLuQrs0.css +0 -1
@@ -65,6 +65,9 @@ export function buildSessionLogSummary(log: CapturedLog): SessionLogSummary {
65
65
  cacheRead: log.cacheReadInputTokens,
66
66
  },
67
67
  sessionId: normalizeString(log.sessionId),
68
+ userAgent: normalizeString(log.userAgent),
69
+ clientPid: log.clientPid ?? null,
70
+ clientProjectFolder: normalizeString(log.clientProjectFolder),
68
71
  };
69
72
  }
70
73
 
@@ -118,6 +121,30 @@ function collectSortedValues(values: readonly (string | null)[]): string[] {
118
121
  return [...set].sort();
119
122
  }
120
123
 
124
+ function firstSummaryUserAgent(summaries: readonly SessionLogSummary[]): string | null {
125
+ for (const summary of summaries) {
126
+ const value = normalizeString(summary.userAgent);
127
+ if (value !== null) return value;
128
+ }
129
+ return null;
130
+ }
131
+
132
+ function firstSummaryClientPid(summaries: readonly SessionLogSummary[]): number | null {
133
+ for (const summary of summaries) {
134
+ const value = summary.clientPid;
135
+ if (value !== null && value !== undefined) return value;
136
+ }
137
+ return null;
138
+ }
139
+
140
+ function firstSummaryProjectFolder(summaries: readonly SessionLogSummary[]): string | null {
141
+ for (const summary of summaries) {
142
+ const value = normalizeString(summary.clientProjectFolder);
143
+ if (value !== null) return value;
144
+ }
145
+ return null;
146
+ }
147
+
121
148
  function countCompletedLogs(summaries: readonly SessionLogSummary[]): number {
122
149
  let count = 0;
123
150
  for (const summary of summaries) {
@@ -180,6 +207,10 @@ export function buildSessionInfo(input: BuildSessionInfoInput): SessionInfo {
180
207
  const inspectorPath = getSessionPath(input.sessionId);
181
208
  const apiPath = buildApiPath(input.sessionId);
182
209
  const compactLogsPath = buildCompactLogsPath(input.sessionId);
210
+ const latestLogs = summaries.slice(0, latestLogLimit).map((summary, index) => ({
211
+ ...summary,
212
+ sessionLogNumber: Math.max(1, requestCount - index),
213
+ }));
183
214
 
184
215
  return {
185
216
  id: input.sessionId,
@@ -211,8 +242,10 @@ export function buildSessionInfo(input: BuildSessionInfoInput): SessionInfo {
211
242
  tokenUsage,
212
243
  lastLogId: input.snapshot?.lastLogId ?? latestLog?.id ?? null,
213
244
  lastModel: normalizeString(input.snapshot?.lastModel) ?? latestLog?.model ?? null,
214
- clientPid: input.snapshot?.clientPid ?? null,
215
- clientProjectFolder: normalizeString(input.snapshot?.clientProjectFolder),
245
+ clientUserAgent: firstSummaryUserAgent(summaries),
246
+ clientPid: input.snapshot?.clientPid ?? firstSummaryClientPid(summaries),
247
+ clientProjectFolder:
248
+ normalizeString(input.snapshot?.clientProjectFolder) ?? firstSummaryProjectFolder(summaries),
216
249
  inspectorPath,
217
250
  inspectorUrl: buildAbsoluteUrl(input.baseUrl, inspectorPath),
218
251
  apiPath,
@@ -220,6 +253,6 @@ export function buildSessionInfo(input: BuildSessionInfoInput): SessionInfo {
220
253
  compactLogsPath,
221
254
  compactLogsUrl: buildAbsoluteUrl(input.baseUrl, compactLogsPath),
222
255
  latestLogLimit,
223
- latestLogs: summaries.slice(0, latestLogLimit),
256
+ latestLogs,
224
257
  };
225
258
  }
@@ -60,6 +60,18 @@ function normalizeExplicitSessionId(sessionId: string | null | undefined): strin
60
60
  return trimmed.length > 0 ? trimmed : null;
61
61
  }
62
62
 
63
+ export function buildProviderTestSessionId(providerId: string): string {
64
+ const normalizedProviderId = normalizeExplicitSessionId(providerId);
65
+ if (normalizedProviderId === null) return PROVIDER_TEST_SESSION_ID;
66
+ return `${PROVIDER_TEST_SESSION_ID}:${normalizedProviderId}`;
67
+ }
68
+
69
+ function isProviderTestSessionId(sessionId: string): boolean {
70
+ return (
71
+ sessionId === PROVIDER_TEST_SESSION_ID || sessionId.startsWith(`${PROVIDER_TEST_SESSION_ID}:`)
72
+ );
73
+ }
74
+
63
75
  function buildClientSessionId(clientInfo: SessionClientInfo): SessionIdentity {
64
76
  const projectFolder = normalizeExplicitSessionId(clientInfo.projectFolder);
65
77
 
@@ -88,11 +100,18 @@ export function resolveSessionIdentity(input: {
88
100
  clientInfo?: SessionClientInfo;
89
101
  isTest?: boolean;
90
102
  }): SessionIdentity {
103
+ const explicit = normalizeExplicitSessionId(input.explicitSessionId);
104
+
91
105
  if (input.isTest === true) {
106
+ if (explicit !== null) {
107
+ return {
108
+ id: explicit,
109
+ source: isProviderTestSessionId(explicit) ? "provider-test" : "explicit",
110
+ };
111
+ }
92
112
  return { id: PROVIDER_TEST_SESSION_ID, source: "provider-test" };
93
113
  }
94
114
 
95
- const explicit = normalizeExplicitSessionId(input.explicitSessionId);
96
115
  if (explicit !== null) {
97
116
  return { id: explicit, source: "explicit" };
98
117
  }
@@ -322,7 +322,7 @@ function prepareLogForList(log: CapturedLog, includeBodies: boolean): CapturedLo
322
322
 
323
323
  /**
324
324
  * Add a test log entry to the in-memory store and persistent log file.
325
- * This is used by the provider test endpoint to seed the provider-test session.
325
+ * This is used by the provider test endpoint to seed provider-test sessions.
326
326
  */
327
327
  export async function addTestLogEntry(entry: Omit<CapturedLog, "id">): Promise<CapturedLog> {
328
328
  const id = await getNextLogId();
@@ -2,6 +2,7 @@ import { createFileRoute } from "@tanstack/react-router";
2
2
  import { getProvider, getModelUsageName } from "../../proxy/providers";
3
3
  import { addTestLogEntry } from "../../proxy/store";
4
4
  import { getConfig } from "../../proxy/config";
5
+ import { buildProviderTestSessionId } from "../../proxy/sessionSupervisor";
5
6
  import { buildProviderTestRequestBody } from "../../lib/providerTestPrompt";
6
7
  import {
7
8
  ProviderTestResultsSchema,
@@ -52,6 +53,7 @@ function getResultTokensPerSecond(result: TestResult): number | null {
52
53
  async function logModelResults(
53
54
  displayName: string,
54
55
  providerName: string,
56
+ providerSessionId: string,
55
57
  anthropicUrl: string | undefined,
56
58
  openaiUrl: string | undefined,
57
59
  modelResults: {
@@ -76,7 +78,7 @@ async function logModelResults(
76
78
  method: "POST",
77
79
  path: "/v1/messages",
78
80
  model: nonStreamingResult.model ?? displayName,
79
- sessionId: null,
81
+ sessionId: providerSessionId,
80
82
  rawRequestBody: requestBody,
81
83
  responseStatus: getResultResponseStatus(nonStreamingResult),
82
84
  responseText: getResultResponseText(nonStreamingResult),
@@ -106,7 +108,7 @@ async function logModelResults(
106
108
  method: "POST",
107
109
  path: "/v1/messages",
108
110
  model: streamingResult.model ?? displayName,
109
- sessionId: null,
111
+ sessionId: providerSessionId,
110
112
  rawRequestBody: streamingRequestBody,
111
113
  responseStatus: getResultResponseStatus(streamingResult),
112
114
  responseText: getResultResponseText(streamingResult),
@@ -144,7 +146,7 @@ async function logModelResults(
144
146
  method: "POST",
145
147
  path: "/v1/chat/completions",
146
148
  model: nonStreamingResult.model ?? displayName,
147
- sessionId: null,
149
+ sessionId: providerSessionId,
148
150
  rawRequestBody: requestBody,
149
151
  responseStatus: getResultResponseStatus(nonStreamingResult),
150
152
  responseText: getResultResponseText(nonStreamingResult),
@@ -174,7 +176,7 @@ async function logModelResults(
174
176
  method: "POST",
175
177
  path: "/v1/chat/completions",
176
178
  model: streamingResult.model ?? displayName,
177
- sessionId: null,
179
+ sessionId: providerSessionId,
178
180
  rawRequestBody: streamingRequestBody,
179
181
  responseStatus: getResultResponseStatus(streamingResult),
180
182
  responseText: getResultResponseText(streamingResult),
@@ -224,6 +226,7 @@ export const Route = createFileRoute("/api/providers/$providerId/test/log")({
224
226
  }
225
227
 
226
228
  const results = parsed.data;
229
+ const providerSessionId = buildProviderTestSessionId(params.providerId);
227
230
  const captureFullDetails = getConfig().captureMode === "full";
228
231
  const anthropicUrl =
229
232
  provider.anthropicBaseUrl !== undefined && provider.anthropicBaseUrl.length > 0
@@ -241,6 +244,7 @@ export const Route = createFileRoute("/api/providers/$providerId/test/log")({
241
244
  logModelResults(
242
245
  modelName,
243
246
  provider.name,
247
+ providerSessionId,
244
248
  anthropicUrl,
245
249
  openaiUrl,
246
250
  modelResult,
@@ -1,183 +1,183 @@
1
- @import "tailwindcss";
2
- @import "tw-animate-css";
3
- @plugin "@tailwindcss/typography";
4
-
5
- @custom-variant dark (&:is(.dark *));
6
-
7
- @theme inline {
8
- --color-background: var(--background);
9
- --color-foreground: var(--foreground);
10
- --color-sidebar-ring: var(--sidebar-ring);
11
- --color-sidebar-border: var(--sidebar-border);
12
- --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
13
- --color-sidebar-accent: var(--sidebar-accent);
14
- --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
15
- --color-sidebar-primary: var(--sidebar-primary);
16
- --color-sidebar-foreground: var(--sidebar-foreground);
17
- --color-sidebar: var(--sidebar);
18
- --color-chart-5: var(--chart-5);
19
- --color-chart-4: var(--chart-4);
20
- --color-chart-3: var(--chart-3);
21
- --color-chart-2: var(--chart-2);
22
- --color-chart-1: var(--chart-1);
23
- --color-ring: var(--ring);
24
- --color-input: var(--input);
25
- --color-border: var(--border);
26
- --color-destructive: var(--destructive);
27
- --color-accent-foreground: var(--accent-foreground);
28
- --color-accent: var(--accent);
29
- --color-muted-foreground: var(--muted-foreground);
30
- --color-muted: var(--muted);
31
- --color-secondary-foreground: var(--secondary-foreground);
32
- --color-secondary: var(--secondary);
33
- --color-primary-foreground: var(--primary-foreground);
34
- --color-primary: var(--primary);
35
- --color-popover-foreground: var(--popover-foreground);
36
- --color-popover: var(--popover);
37
- --color-card-foreground: var(--card-foreground);
38
- --color-card: var(--card);
39
- --radius-sm: calc(var(--radius) - 4px);
40
- --radius-md: calc(var(--radius) - 2px);
41
- --radius-lg: var(--radius);
42
- --radius-xl: calc(var(--radius) + 4px);
43
- --animate-crab-crawl: crab-crawl-down 0.6s ease-in-out infinite;
44
- --animate-crab-appear: crab-appear 300ms ease-out;
45
- --animate-crab-settle: crab-settle 400ms ease-in-out;
46
- --animate-crab-piano-pop: crab-piano-pop 400ms cubic-bezier(0.34, 1.56, 0.64, 1) backwards;
47
- }
48
-
49
- :root {
50
- --radius: 0.625rem;
51
- --background: oklch(1 0 0);
52
- --foreground: oklch(0.145 0 0);
53
- --card: oklch(1 0 0);
54
- --card-foreground: oklch(0.145 0 0);
55
- --popover: oklch(1 0 0);
56
- --popover-foreground: oklch(0.145 0 0);
57
- --primary: oklch(0.205 0 0);
58
- --primary-foreground: oklch(0.985 0 0);
59
- --secondary: oklch(0.97 0 0);
60
- --secondary-foreground: oklch(0.205 0 0);
61
- --muted: oklch(0.97 0 0);
62
- --muted-foreground: oklch(0.556 0 0);
63
- --accent: oklch(0.97 0 0);
64
- --accent-foreground: oklch(0.205 0 0);
65
- --destructive: oklch(0.577 0.245 27.325);
66
- --border: oklch(0.922 0 0);
67
- --input: oklch(0.922 0 0);
68
- --ring: oklch(0.708 0 0);
69
- --chart-1: oklch(0.646 0.222 41.116);
70
- --chart-2: oklch(0.6 0.118 184.704);
71
- --chart-3: oklch(0.398 0.07 227.392);
72
- --chart-4: oklch(0.828 0.189 84.429);
73
- --chart-5: oklch(0.769 0.188 70.08);
74
- --sidebar: oklch(0.985 0 0);
75
- --sidebar-foreground: oklch(0.145 0 0);
76
- --sidebar-primary: oklch(0.205 0 0);
77
- --sidebar-primary-foreground: oklch(0.985 0 0);
78
- --sidebar-accent: oklch(0.97 0 0);
79
- --sidebar-accent-foreground: oklch(0.205 0 0);
80
- --sidebar-border: oklch(0.922 0 0);
81
- --sidebar-ring: oklch(0.708 0 0);
82
- }
83
-
84
- .dark {
85
- --background: oklch(0.145 0 0);
86
- --foreground: oklch(0.985 0 0);
87
- --card: oklch(0.205 0 0);
88
- --card-foreground: oklch(0.985 0 0);
89
- --popover: oklch(0.205 0 0);
90
- --popover-foreground: oklch(0.985 0 0);
91
- --primary: oklch(0.922 0 0);
92
- --primary-foreground: oklch(0.205 0 0);
93
- --secondary: oklch(0.269 0 0);
94
- --secondary-foreground: oklch(0.985 0 0);
95
- --muted: oklch(0.269 0 0);
96
- --muted-foreground: oklch(0.708 0 0);
97
- --accent: oklch(0.269 0 0);
98
- --accent-foreground: oklch(0.985 0 0);
99
- --destructive: oklch(0.704 0.191 22.216);
100
- --border: oklch(1 0 0 / 10%);
101
- --input: oklch(1 0 0 / 15%);
102
- --ring: oklch(0.556 0 0);
103
- --chart-1: oklch(0.488 0.243 264.376);
104
- --chart-2: oklch(0.696 0.17 162.48);
105
- --chart-3: oklch(0.769 0.188 70.08);
106
- --chart-4: oklch(0.627 0.265 303.9);
107
- --chart-5: oklch(0.645 0.246 16.439);
108
- --sidebar: oklch(0.205 0 0);
109
- --sidebar-foreground: oklch(0.985 0 0);
110
- --sidebar-primary: oklch(0.488 0.243 264.376);
111
- --sidebar-primary-foreground: oklch(0.985 0 0);
112
- --sidebar-accent: oklch(0.269 0 0);
113
- --sidebar-accent-foreground: oklch(0.985 0 0);
114
- --sidebar-border: oklch(1 0 0 / 10%);
115
- --sidebar-ring: oklch(0.556 0 0);
116
- }
117
-
118
- @keyframes crab-crawl-down {
119
- 0%, 100% {
120
- transform: translateY(0px);
121
- }
122
- 25% {
123
- transform: translateY(2px);
124
- }
125
- 75% {
126
- transform: translateY(-1px);
127
- }
128
- }
129
-
130
- @keyframes crab-appear {
131
- 0% {
132
- transform: scale(0.5);
133
- opacity: 0;
134
- }
135
- 100% {
136
- transform: scale(1);
137
- opacity: 1;
138
- }
139
- }
140
-
141
- @keyframes crab-settle {
142
- 0% {
143
- transform: scale(1);
144
- }
145
- 50% {
146
- transform: scale(1.15);
147
- }
148
- 100% {
149
- transform: scale(1);
150
- }
151
- }
152
-
153
- @keyframes crab-piano-pop {
154
- 0% {
155
- transform: scale(0) translateY(0);
156
- opacity: 0;
157
- }
158
- 60% {
159
- transform: scale(1.3) translateY(-4px);
160
- opacity: 1;
161
- }
162
- 100% {
163
- transform: scale(1) translateY(0);
164
- opacity: 1;
165
- }
166
- }
167
-
168
- @media (prefers-reduced-motion: reduce) {
169
- .animate-crab-piano-pop {
170
- animation: none !important;
171
- }
172
- }
173
-
174
- [data-deep-link-highlight="true"] {
175
- background: color-mix(in oklch, var(--chart-2) 18%, transparent);
176
- box-shadow:
177
- inset 0 0 0 1px color-mix(in oklch, var(--chart-2) 65%, transparent),
178
- 0 0 0 3px color-mix(in oklch, var(--chart-2) 20%, transparent);
179
- }
180
-
1
+ @import "tailwindcss";
2
+ @import "tw-animate-css";
3
+ @plugin "@tailwindcss/typography";
4
+
5
+ @custom-variant dark (&:is(.dark *));
6
+
7
+ @theme inline {
8
+ --color-background: var(--background);
9
+ --color-foreground: var(--foreground);
10
+ --color-sidebar-ring: var(--sidebar-ring);
11
+ --color-sidebar-border: var(--sidebar-border);
12
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
13
+ --color-sidebar-accent: var(--sidebar-accent);
14
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
15
+ --color-sidebar-primary: var(--sidebar-primary);
16
+ --color-sidebar-foreground: var(--sidebar-foreground);
17
+ --color-sidebar: var(--sidebar);
18
+ --color-chart-5: var(--chart-5);
19
+ --color-chart-4: var(--chart-4);
20
+ --color-chart-3: var(--chart-3);
21
+ --color-chart-2: var(--chart-2);
22
+ --color-chart-1: var(--chart-1);
23
+ --color-ring: var(--ring);
24
+ --color-input: var(--input);
25
+ --color-border: var(--border);
26
+ --color-destructive: var(--destructive);
27
+ --color-accent-foreground: var(--accent-foreground);
28
+ --color-accent: var(--accent);
29
+ --color-muted-foreground: var(--muted-foreground);
30
+ --color-muted: var(--muted);
31
+ --color-secondary-foreground: var(--secondary-foreground);
32
+ --color-secondary: var(--secondary);
33
+ --color-primary-foreground: var(--primary-foreground);
34
+ --color-primary: var(--primary);
35
+ --color-popover-foreground: var(--popover-foreground);
36
+ --color-popover: var(--popover);
37
+ --color-card-foreground: var(--card-foreground);
38
+ --color-card: var(--card);
39
+ --radius-sm: calc(var(--radius) - 4px);
40
+ --radius-md: calc(var(--radius) - 2px);
41
+ --radius-lg: var(--radius);
42
+ --radius-xl: calc(var(--radius) + 4px);
43
+ --animate-crab-crawl: crab-crawl-down 0.6s ease-in-out infinite;
44
+ --animate-crab-appear: crab-appear 300ms ease-out;
45
+ --animate-crab-settle: crab-settle 400ms ease-in-out;
46
+ --animate-crab-piano-pop: crab-piano-pop 400ms cubic-bezier(0.34, 1.56, 0.64, 1) backwards;
47
+ }
48
+
49
+ :root {
50
+ --radius: 0.625rem;
51
+ --background: oklch(1 0 0);
52
+ --foreground: oklch(0.145 0 0);
53
+ --card: oklch(1 0 0);
54
+ --card-foreground: oklch(0.145 0 0);
55
+ --popover: oklch(1 0 0);
56
+ --popover-foreground: oklch(0.145 0 0);
57
+ --primary: oklch(0.205 0 0);
58
+ --primary-foreground: oklch(0.985 0 0);
59
+ --secondary: oklch(0.97 0 0);
60
+ --secondary-foreground: oklch(0.205 0 0);
61
+ --muted: oklch(0.97 0 0);
62
+ --muted-foreground: oklch(0.556 0 0);
63
+ --accent: oklch(0.97 0 0);
64
+ --accent-foreground: oklch(0.205 0 0);
65
+ --destructive: oklch(0.577 0.245 27.325);
66
+ --border: oklch(0.922 0 0);
67
+ --input: oklch(0.922 0 0);
68
+ --ring: oklch(0.708 0 0);
69
+ --chart-1: oklch(0.646 0.222 41.116);
70
+ --chart-2: oklch(0.6 0.118 184.704);
71
+ --chart-3: oklch(0.398 0.07 227.392);
72
+ --chart-4: oklch(0.828 0.189 84.429);
73
+ --chart-5: oklch(0.769 0.188 70.08);
74
+ --sidebar: oklch(0.985 0 0);
75
+ --sidebar-foreground: oklch(0.145 0 0);
76
+ --sidebar-primary: oklch(0.205 0 0);
77
+ --sidebar-primary-foreground: oklch(0.985 0 0);
78
+ --sidebar-accent: oklch(0.97 0 0);
79
+ --sidebar-accent-foreground: oklch(0.205 0 0);
80
+ --sidebar-border: oklch(0.922 0 0);
81
+ --sidebar-ring: oklch(0.708 0 0);
82
+ }
83
+
84
+ .dark {
85
+ --background: oklch(0.145 0 0);
86
+ --foreground: oklch(0.985 0 0);
87
+ --card: oklch(0.205 0 0);
88
+ --card-foreground: oklch(0.985 0 0);
89
+ --popover: oklch(0.205 0 0);
90
+ --popover-foreground: oklch(0.985 0 0);
91
+ --primary: oklch(0.922 0 0);
92
+ --primary-foreground: oklch(0.205 0 0);
93
+ --secondary: oklch(0.269 0 0);
94
+ --secondary-foreground: oklch(0.985 0 0);
95
+ --muted: oklch(0.269 0 0);
96
+ --muted-foreground: oklch(0.708 0 0);
97
+ --accent: oklch(0.269 0 0);
98
+ --accent-foreground: oklch(0.985 0 0);
99
+ --destructive: oklch(0.704 0.191 22.216);
100
+ --border: oklch(1 0 0 / 10%);
101
+ --input: oklch(1 0 0 / 15%);
102
+ --ring: oklch(0.556 0 0);
103
+ --chart-1: oklch(0.488 0.243 264.376);
104
+ --chart-2: oklch(0.696 0.17 162.48);
105
+ --chart-3: oklch(0.769 0.188 70.08);
106
+ --chart-4: oklch(0.627 0.265 303.9);
107
+ --chart-5: oklch(0.645 0.246 16.439);
108
+ --sidebar: oklch(0.205 0 0);
109
+ --sidebar-foreground: oklch(0.985 0 0);
110
+ --sidebar-primary: oklch(0.488 0.243 264.376);
111
+ --sidebar-primary-foreground: oklch(0.985 0 0);
112
+ --sidebar-accent: oklch(0.269 0 0);
113
+ --sidebar-accent-foreground: oklch(0.985 0 0);
114
+ --sidebar-border: oklch(1 0 0 / 10%);
115
+ --sidebar-ring: oklch(0.556 0 0);
116
+ }
117
+
118
+ @keyframes crab-crawl-down {
119
+ 0%, 100% {
120
+ transform: translateY(0px);
121
+ }
122
+ 25% {
123
+ transform: translateY(2px);
124
+ }
125
+ 75% {
126
+ transform: translateY(-1px);
127
+ }
128
+ }
129
+
130
+ @keyframes crab-appear {
131
+ 0% {
132
+ transform: scale(0.5);
133
+ opacity: 0;
134
+ }
135
+ 100% {
136
+ transform: scale(1);
137
+ opacity: 1;
138
+ }
139
+ }
140
+
141
+ @keyframes crab-settle {
142
+ 0% {
143
+ transform: scale(1);
144
+ }
145
+ 50% {
146
+ transform: scale(1.15);
147
+ }
148
+ 100% {
149
+ transform: scale(1);
150
+ }
151
+ }
152
+
153
+ @keyframes crab-piano-pop {
154
+ 0% {
155
+ transform: scale(0) translateY(0);
156
+ opacity: 0;
157
+ }
158
+ 60% {
159
+ transform: scale(1.3) translateY(-4px);
160
+ opacity: 1;
161
+ }
162
+ 100% {
163
+ transform: scale(1) translateY(0);
164
+ opacity: 1;
165
+ }
166
+ }
167
+
168
+ @media (prefers-reduced-motion: reduce) {
169
+ .animate-crab-piano-pop {
170
+ animation: none !important;
171
+ }
172
+ }
173
+
174
+ [data-deep-link-highlight="true"] {
175
+ background: color-mix(in oklch, var(--chart-2) 18%, transparent);
176
+ box-shadow:
177
+ inset 0 0 0 1px color-mix(in oklch, var(--chart-2) 65%, transparent),
178
+ 0 0 0 3px color-mix(in oklch, var(--chart-2) 20%, transparent);
179
+ }
180
+
181
181
  @layer base {
182
182
  * {
183
183
  @apply border-border outline-ring/50;
@@ -1 +0,0 @@
1
- import{r as h,j as t}from"./main-CSONBwwn.js";import{c as X,g as I,r as P,a as q,X as Y,b as m,B as Z,f as $,R as ee,C as te,M as J,d as V,e as _,h as M,i as re,j as ne,k as se,L as ae}from"./ProxyViewerContainer-CWUQZLYy.js";const oe=[["line",{x1:"5",x2:"19",y1:"9",y2:"9",key:"1nwqeh"}],["line",{x1:"5",x2:"19",y1:"15",y2:"15",key:"g8yjpy"}]],de=X("equal",oe),ie="";function j(e){if(e.length===0)return ie;let r="";for(let n=0;n<e.length;n++){const s=e[n];s!==void 0&&(typeof s=="number"?r+=`[${s}]`:n===0?r+=s:r+=`.${s}`)}return r}function le(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function D(e){if(typeof e=="string")try{return C(JSON.parse(e))}catch{return{kind:"primitive",value:e}}return C(e)}function C(e){if(e===null)return{kind:"primitive",value:null};if(typeof e=="string")return{kind:"primitive",value:e};if(typeof e=="number")return{kind:"primitive",value:e};if(typeof e=="boolean")return{kind:"primitive",value:e};if(Array.isArray(e))return{kind:"array",value:e.map(r=>C(r))};if(le(e)){const r={};for(const n of Object.keys(e).sort())r[n]=C(e[n]);return{kind:"object",value:r}}return{kind:"primitive",value:null}}function ce(e,r){const n=[];return R([],e,r,n),n}function R(e,r,n,s){const d=j(e);if(S(r,n)){s.push({kind:"equal",path:d,value:r});return}if(r.kind!==n.kind){s.push({kind:"changed",path:d,left:r,right:n});return}if(r.kind==="primitive"&&n.kind==="primitive"){s.push({kind:"changed",path:d,left:r,right:n});return}if(r.kind==="object"&&n.kind==="object"){const o=Object.keys(r.value),a=Object.keys(n.value),x=new Set(a);for(const i of o){const f=r.value[i];if(f!==void 0)if(!x.has(i))s.push({kind:"removed",path:j([...e,i]),value:f});else{const p=n.value[i];if(p===void 0)continue;R([...e,i],f,p,s)}}for(const i of a){if(o.includes(i))continue;const f=n.value[i];f!==void 0&&s.push({kind:"added",path:j([...e,i]),value:f})}return}if(r.kind==="array"&&n.kind==="array"){const o=Math.min(r.value.length,n.value.length);for(let a=0;a<o;a++){const x=r.value[a],i=n.value[a];x===void 0||i===void 0||R([...e,a],x,i,s)}for(let a=o;a<n.value.length;a++){const x=n.value[a];x!==void 0&&s.push({kind:"added",path:j([...e,a]),value:x})}for(let a=o;a<r.value.length;a++){const x=r.value[a];x!==void 0&&s.push({kind:"removed",path:j([...e,a]),value:x})}}}function S(e,r){if(e.kind!==r.kind)return!1;if(e.kind==="primitive"&&r.kind==="primitive")return e.value===r.value;if(e.kind==="array"&&r.kind==="array"){if(e.value.length!==r.value.length)return!1;for(let n=0;n<e.value.length;n++){const s=e.value[n],d=r.value[n];if(s===void 0||d===void 0||!S(s,d))return!1}return!0}if(e.kind==="object"&&r.kind==="object"){const n=Object.keys(e.value),s=Object.keys(r.value);if(n.length!==s.length)return!1;for(const d of n){const o=e.value[d],a=r.value[d];if(o===void 0||a===void 0||!S(o,a))return!1}return!0}return!1}function v(e,r=80){let n;switch(e.kind){case"primitive":n=e.value===null?"null":JSON.stringify(e.value);break;case"array":n=`[… ${e.value.length} items]`;break;case"object":n=`{… ${Object.keys(e.value).length} keys}`;break}return n.length>r&&(n=`${n.slice(0,r-1)}…`),n}function N(e,r=2){return JSON.stringify(E(e),null,r)}function E(e){switch(e.kind){case"primitive":return e.value;case"array":return e.value.map(E);case"object":{const r={};for(const[n,s]of Object.entries(e.value))r[n]=E(s);return r}}}function w({text:e,defaultExpandDepth:r}){return t.jsx(h.Suspense,{fallback:t.jsx("div",{className:"text-xs text-muted-foreground",children:"Loading JSON..."}),children:t.jsx(ae,{text:e,defaultExpandDepth:r})})}function L(e){if(e==="")return"";for(let r=e.length-1;r>=0;r--){const n=e[r];if(n==="."||n==="[")return e.substring(0,r)}return""}function K(e){return e.kind==="equal"&&(e.value.kind==="object"||e.value.kind==="array")}function ue(e){const r=[];let n=0;for(;n<e.length;){const s=e[n];if(s!==void 0&&K(s)){const d=L(s.path);let o=n+1;for(;o<e.length;){const a=e[o];if(a===void 0||!K(a)||L(a.path)!==d)break;o++}if(o-n>1){const a=[];for(let x=n;x<o;x++){const i=e[x];i!==void 0&&i.kind==="equal"&&a.push(i)}r.push({kind:"equal-run",ops:a}),n=o;continue}}s!==void 0&&r.push({kind:"single",op:s}),n++}return r}const B={added:{icon:V,accent:"text-emerald-600 dark:text-emerald-400",bg:"bg-emerald-500/5 hover:bg-emerald-500/10",border:"border-l-emerald-500",label:"ADDED"},removed:{icon:J,accent:"text-rose-600 dark:text-rose-400",bg:"bg-rose-500/5 hover:bg-rose-500/10",border:"border-l-rose-500",label:"REMOVED"},changed:{icon:_,accent:"text-amber-600 dark:text-amber-400",bg:"bg-amber-500/5 hover:bg-amber-500/10",border:"border-l-amber-500",label:"CHANGED"},equal:{icon:de,accent:"text-muted-foreground/70",bg:"bg-muted/20 hover:bg-muted/30",border:"border-l-muted-foreground/20",label:"EQUAL"}};function xe({ops:e,expanded:r,onToggle:n}){const s=e[0],d=e[e.length-1];if(s===void 0||d===void 0)return t.jsx("div",{className:"text-muted-foreground/40 text-xs",children:"—"});const o=s.path,a=d.path,x=e.length===1?o:`${o} … ${a}`,i=s.value.kind==="array"?`${e.length} equal arrays`:s.value.kind==="object"?`${e.length} equal objects`:"equal",f=B.equal;return t.jsxs("div",{className:m("border-l-4 rounded-sm",f.border,f.bg),children:[t.jsxs("button",{type:"button",onClick:n,className:"w-full text-left flex items-center gap-2 px-3 py-1.5 text-xs text-muted-foreground cursor-pointer",children:[t.jsx(M,{className:m("size-3 transition-transform shrink-0",r&&"rotate-90")}),t.jsx(f.icon,{className:m("size-3 shrink-0",f.accent)}),t.jsx("span",{className:"font-mono truncate flex-1",title:`${o} … ${a}`,children:x}),t.jsx("span",{className:m("text-[10px] uppercase tracking-wider shrink-0",f.accent),children:f.label}),t.jsxs("span",{className:"text-muted-foreground/60 shrink-0",children:["(",i,")"]})]}),r&&t.jsx("div",{className:"ml-5 mt-1 mb-2 space-y-2 pr-2",children:e.map(p=>t.jsxs("div",{className:"border border-border/50 rounded p-2 bg-muted/20",children:[t.jsx("div",{className:"font-mono text-xs text-muted-foreground mb-1",children:p.path}),t.jsx(w,{text:N(p.value),defaultExpandDepth:0})]},p.path))})]})}function me({op:e,idx:r,copiedPath:n,onCopyPath:s,expanded:d,onToggle:o}){const a=B[e.kind],x=a.icon,i=e.kind==="added"||e.kind==="removed"?e.value.kind==="object"||e.value.kind==="array":e.kind==="changed"?e.left.kind==="object"||e.left.kind==="array"||e.right.kind==="object"||e.right.kind==="array":!1,f=e.kind==="changed"?[{text:v(e.left,400),tone:"text-rose-700 dark:text-rose-300 line-through"},{text:v(e.right,400),tone:"text-emerald-700 dark:text-emerald-300"}]:e.kind==="removed"?[{text:v(e.value,400),tone:"text-rose-700 dark:text-rose-300 line-through"}]:e.kind==="added"?[{text:v(e.value,400),tone:"text-emerald-700 dark:text-emerald-300"}]:[{text:v(e.value,400),tone:"text-muted-foreground"}],p=n===e.path&&e.path!=="";return t.jsxs("div",{"data-diff-idx":r,"data-diff-kind":e.kind,className:m("border-l-4 rounded-sm px-3 py-2 my-0.5 transition-colors",a.border,a.bg),children:[t.jsxs("button",{type:"button",onClick:o,disabled:!i,className:m("w-full flex items-center gap-2 text-xs text-left rounded-sm",i?"cursor-pointer":"cursor-default"),"aria-expanded":i?d:void 0,"aria-label":i?d?`Collapse ${e.path||"root"}`:`Expand ${e.path||"root"}`:void 0,children:[i?t.jsx(M,{className:m("size-3 shrink-0 transition-transform",a.accent,d&&"rotate-90")}):t.jsx("span",{className:"size-3 shrink-0","aria-hidden":"true"}),t.jsx(x,{className:m("size-3.5 shrink-0",a.accent),strokeWidth:2.5}),t.jsx("span",{className:"font-mono truncate flex-1 min-w-0",title:e.path||"(root)",children:e.path===""?"(root)":e.path}),t.jsx("span",{className:m("text-[9px] font-bold uppercase tracking-wider shrink-0 px-1.5 py-0.5 rounded",a.accent,e.kind==="equal"?"bg-muted/40":"bg-background/60"),children:a.label}),e.path!==""&&t.jsx("span",{role:"button",tabIndex:0,onClick:b=>{b.stopPropagation(),s(e.path)},onKeyDown:b=>{(b.key==="Enter"||b.key===" ")&&(b.stopPropagation(),b.preventDefault(),s(e.path))},className:m("shrink-0 p-1 rounded transition-colors cursor-pointer inline-flex items-center justify-center",p?"text-emerald-500":"text-muted-foreground/50 hover:text-foreground hover:bg-muted"),"aria-label":p?"Copied":"Copy",title:p?"Copied!":"Copy",children:p?t.jsx(re,{className:"size-3"}):t.jsx(ne,{className:"size-3"})})]}),f.map((b,y)=>t.jsx("div",{className:m("font-mono text-xs mt-1 break-all pl-5",b.tone),children:b.text},y)),t.jsx("div",{className:"overflow-hidden transition-all duration-200",style:{maxHeight:d&&i?"2000px":"0"},"aria-hidden":!d,children:d&&i&&e.kind!=="equal"?t.jsx(fe,{op:e}):null})]})}function fe({op:e}){if(e.kind==="added"||e.kind==="removed")return t.jsx("div",{className:"pl-5 mt-2 border border-border/50 rounded p-2 bg-muted/20",children:t.jsx(w,{text:N(e.value),defaultExpandDepth:0})});const r=e.left.kind==="object"||e.left.kind==="array",n=e.right.kind==="object"||e.right.kind==="array";return!r&&!n?t.jsx("div",{className:"pl-5 mt-2 text-xs text-muted-foreground/70 italic",children:"Primitive values are shown inline above."}):t.jsxs("div",{className:"pl-5 mt-2 grid grid-cols-1 md:grid-cols-2 gap-2",children:[t.jsxs("div",{className:"border border-rose-500/30 rounded p-2 bg-rose-500/5",children:[t.jsx("div",{className:"text-[10px] uppercase tracking-wider text-rose-500 mb-1",children:"Old"}),t.jsx(w,{text:N(e.left),defaultExpandDepth:0})]}),t.jsxs("div",{className:"border border-emerald-500/30 rounded p-2 bg-emerald-500/5",children:[t.jsx("div",{className:"text-[10px] uppercase tracking-wider text-emerald-500 mb-1",children:"New"}),t.jsx(w,{text:N(e.right),defaultExpandDepth:0})]})]})}function pe({counts:e,onJumpTo:r}){const n=e.added+e.removed+e.changed;return t.jsxs("div",{className:"px-4 py-2 border-b border-border bg-muted/20 flex items-center gap-2 text-xs flex-wrap",children:[t.jsxs("span",{className:"text-muted-foreground font-medium",children:[n," ",n===1?"change":"changes"]}),t.jsxs("button",{type:"button",onClick:()=>r("removed"),disabled:e.removed===0,className:m("inline-flex items-center gap-1 px-2 py-0.5 rounded-full border cursor-pointer transition-colors",e.removed>0?"border-rose-500/40 text-rose-600 dark:text-rose-400 bg-rose-500/10 hover:bg-rose-500/20":"border-border text-muted-foreground/40 cursor-not-allowed"),title:e.removed>0?"Jump to first removed":"No removals",children:[t.jsx(J,{className:"size-3"}),e.removed," removed"]}),t.jsxs("button",{type:"button",onClick:()=>r("added"),disabled:e.added===0,className:m("inline-flex items-center gap-1 px-2 py-0.5 rounded-full border cursor-pointer transition-colors",e.added>0?"border-emerald-500/40 text-emerald-600 dark:text-emerald-400 bg-emerald-500/10 hover:bg-emerald-500/20":"border-border text-muted-foreground/40 cursor-not-allowed"),title:e.added>0?"Jump to first added":"No additions",children:[t.jsx(V,{className:"size-3"}),e.added," added"]}),t.jsxs("button",{type:"button",onClick:()=>r("changed"),disabled:e.changed===0,className:m("inline-flex items-center gap-1 px-2 py-0.5 rounded-full border cursor-pointer transition-colors",e.changed>0?"border-amber-500/40 text-amber-600 dark:text-amber-400 bg-amber-500/10 hover:bg-amber-500/20":"border-border text-muted-foreground/40 cursor-not-allowed"),title:e.changed>0?"Jump to first changed":"No changes",children:[t.jsx(_,{className:"size-3"}),e.changed," changed"]})]})}function he({mode:e,onChange:r}){return t.jsxs("div",{className:"inline-flex rounded-md border border-border overflow-hidden",children:[t.jsxs("button",{type:"button",onClick:()=>r("unified"),"aria-pressed":e==="unified",className:m("flex items-center gap-1 px-2 py-1 text-xs transition-colors cursor-pointer",e==="unified"?"bg-muted text-foreground":"hover:bg-muted/50 text-muted-foreground"),title:"Unified view (single column, emphasized diffs)",children:[t.jsx(ee,{className:"size-3"}),"Unified"]}),t.jsxs("button",{type:"button",onClick:()=>r("split"),"aria-pressed":e==="split",className:m("flex items-center gap-1 px-2 py-1 text-xs transition-colors border-l border-border cursor-pointer",e==="split"?"bg-muted text-foreground":"hover:bg-muted/50 text-muted-foreground"),title:"Split view (path | left | right)",children:[t.jsx(te,{className:"size-3"}),"Split"]})]})}function A({log:e,side:r}){const n=q(e);return t.jsxs("div",{className:"flex-1 min-w-0 space-y-1 text-xs",children:[t.jsxs("div",{className:"flex items-center gap-2",children:[t.jsx(Z,{variant:"outline",className:m("text-[10px] px-1.5 py-0 h-5 font-mono shrink-0",r==="left"?"border-rose-500/40 text-rose-400":"border-emerald-500/40 text-emerald-400"),children:r==="left"?"← Left":"Right →"}),t.jsxs("span",{className:"font-mono text-blue-400/80",children:["#",e.id]}),e.model!==null&&t.jsx("span",{className:"font-mono text-muted-foreground truncate",children:e.model})]}),t.jsxs("div",{className:"flex items-center gap-3 text-muted-foreground font-mono",children:[e.cacheCreationInputTokens!==null&&e.cacheCreationInputTokens>0&&t.jsxs("span",{className:"text-emerald-400",children:["KV Cache +",$(e.cacheCreationInputTokens)]}),e.cacheReadInputTokens!==null&&e.cacheReadInputTokens>0&&t.jsxs("span",{className:"text-purple-400",children:["KV Cache ~",$(e.cacheReadInputTokens)]}),t.jsx("span",{className:"truncate",title:e.timestamp,children:e.timestamp})]}),t.jsxs("div",{className:"text-muted-foreground/70 font-mono truncate",title:n,children:["session: ",n]})]})}function ke({left:e,right:r,onClose:n}){const s=h.useMemo(()=>{const l=I(P(e)).analyzeRequest(e.rawRequestBody),c=I(P(r)).analyzeRequest(r.rawRequestBody),u=D(l.comparisonValue),g=D(c.comparisonValue);return ce(u,g)},[e.apiFormat,e.path,e.rawRequestBody,r.apiFormat,r.path,r.rawRequestBody]),d=h.useMemo(()=>ue(s),[s]),o=h.useMemo(()=>{let l=0,c=0,u=0;for(const g of d)if(g.kind==="single")switch(g.op.kind){case"added":l++;break;case"removed":c++;break;case"changed":u++;break}return{added:l,removed:c,changed:u}},[d]),[a,x]=h.useState(new Set),i=l=>{x(c=>{const u=new Set(c);return u.has(l)?u.delete(l):u.add(l),u})},[f,p]=h.useState(new Set),b=l=>{p(c=>{const u=new Set(c);return u.has(l)?u.delete(l):u.add(l),u})};h.useEffect(()=>{p(new Set)},[e.id,r.id]);const[y,F]=h.useState("unified"),T=h.useRef(null),[U,z]=h.useState(null),k=h.useRef(null),H=l=>{se(l).then(c=>{c&&(z(l),k.current!==null&&clearTimeout(k.current),k.current=setTimeout(()=>z(null),1500))})};h.useEffect(()=>()=>{k.current!==null&&clearTimeout(k.current)},[]);const G=l=>{const c=d.findIndex(O=>O.kind==="single"&&O.op.kind===l);if(c===-1)return;const u=T.current;if(u===null)return;const g=u.querySelector(`[data-diff-idx="${c}"]`);g!==null&&g.scrollIntoView({behavior:"smooth",block:"center"})};h.useEffect(()=>{const l=u=>{u.key==="Escape"&&n()};document.addEventListener("keydown",l);const c=document.body.style.overflow;return document.body.style.overflow="hidden",()=>{document.removeEventListener("keydown",l),document.body.style.overflow=c}},[n]);const Q=q(e)===q(r),W=s.length===1&&s[0]?.kind==="equal";return t.jsxs("div",{className:"fixed inset-0 z-50 flex justify-end",role:"dialog","aria-modal":"true","aria-label":"Compare two log requests",children:[t.jsx("button",{type:"button",onClick:n,"aria-label":"Close compare drawer",className:"absolute inset-0 bg-black/40 cursor-default",tabIndex:-1}),t.jsxs("div",{className:m("relative bg-background border-l border-border shadow-xl","w-full md:w-[70vw] max-w-[1100px] flex flex-col h-full"),onClick:l=>l.stopPropagation(),onKeyDown:l=>l.stopPropagation(),children:[t.jsxs("div",{className:"flex items-start gap-4 px-4 py-3 border-b border-border",children:[t.jsxs("div",{className:"flex-1 flex gap-4 min-w-0",children:[t.jsx(A,{log:e,side:"left"}),t.jsx(A,{log:r,side:"right"})]}),t.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[t.jsx(he,{mode:y,onChange:F}),t.jsx("button",{type:"button",onClick:n,"aria-label":"Close",className:"p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted cursor-pointer",children:t.jsx(Y,{className:"size-4"})})]})]}),!Q&&t.jsx("div",{className:"px-4 py-1.5 text-xs text-amber-400 bg-amber-500/10 border-b border-border",children:"Heads up: the two selected logs are from different sessions."}),W?t.jsx("div",{className:"flex-1 min-h-0 overflow-y-auto flex items-center justify-center text-muted-foreground text-sm",children:"The two Request payloads are identical."}):t.jsxs(t.Fragment,{children:[t.jsx(pe,{counts:o,onJumpTo:G}),t.jsx("div",{ref:T,className:"flex-1 min-h-0 overflow-y-auto",children:y==="unified"?t.jsx("div",{className:"px-3 py-2 space-y-0.5",children:d.map((l,c)=>{if(l.kind==="equal-run")return t.jsx(xe,{ops:l.ops,expanded:a.has(c),onToggle:()=>i(c)},`r${c}`);const u=l.op;return t.jsx(me,{op:u,idx:c,copiedPath:U,onCopyPath:H,expanded:f.has(c),onToggle:()=>b(c)},`o${c}`)})}):t.jsx(be,{grouped:d,left:e,right:r})})]})]})]})}function be({grouped:e,left:r,right:n}){return t.jsxs("div",{className:"grid grid-cols-[200px_1fr_1fr] gap-x-2 gap-y-0.5 px-3 py-2 text-xs",children:[t.jsxs("div",{className:"grid grid-cols-[200px_1fr_1fr] gap-x-2 col-span-3 pb-2 mb-2 border-b border-border text-[10px] uppercase tracking-wider text-muted-foreground",children:[t.jsx("span",{children:"Path"}),t.jsxs("span",{children:["Left (Log #",r.id,")"]}),t.jsxs("span",{children:["Right (Log #",n.id,")"]})]}),e.map((s,d)=>{if(s.kind==="equal-run")return t.jsxs("div",{className:"col-span-3 px-2 py-1 text-xs text-muted-foreground/60",children:[s.ops.length," equal siblings collapsed — switch to Unified to expand"]},d);const o=s.op;return o.kind==="equal"?t.jsxs("div",{className:"col-span-3 grid grid-cols-[200px_1fr_1fr] gap-x-2 px-2 py-0.5 text-muted-foreground",children:[t.jsx("span",{className:"font-mono text-xs truncate",title:o.path,children:o.path}),t.jsx("span",{className:"font-mono text-xs break-all opacity-60",children:v(o.value,200)}),t.jsx("span",{className:"font-mono text-xs break-all opacity-60",children:v(o.value,200)})]},d):o.kind==="added"?t.jsxs("div",{className:"col-span-3 px-2 py-1 rounded text-xs border-l-2 border-l-emerald-400/70 bg-emerald-500/5",children:[t.jsx("div",{className:"font-mono text-xs text-muted-foreground mb-0.5",children:o.path}),t.jsxs("div",{className:"font-mono break-all text-emerald-300/90",children:["+ ",v(o.value,400)]})]},d):o.kind==="removed"?t.jsxs("div",{className:"col-span-3 px-2 py-1 rounded text-xs border-l-2 border-l-rose-400/70 bg-rose-500/5",children:[t.jsx("div",{className:"font-mono text-xs text-muted-foreground mb-0.5",children:o.path}),t.jsxs("div",{className:"font-mono break-all text-rose-300/90 line-through",children:["− ",v(o.value,400)]})]},d):t.jsxs("div",{className:"col-span-3 px-2 py-1 rounded text-xs border-l-2 border-l-amber-400/70 bg-amber-500/5",children:[t.jsx("div",{className:"font-mono text-xs text-muted-foreground mb-1",children:o.path}),t.jsxs("div",{className:"grid grid-cols-2 gap-2",children:[t.jsx("div",{className:"font-mono text-rose-300/90 break-all line-through",children:v(o.left,400)}),t.jsx("div",{className:"font-mono text-emerald-300/90 break-all",children:v(o.right,400)})]})]},d)})]})}export{ke as CompareDrawer};