@tonyclaw/agent-inspector 3.0.28 → 3.0.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.output/cli.js +791 -191
- package/.output/nitro.json +1 -1
- package/.output/public/assets/CompareDrawer-B6cXJohL.js +1 -0
- package/.output/public/assets/InspectorPet-mAzeGmEE.js +4108 -0
- package/.output/public/assets/ProxyViewerContainer-CkFWv_Nm.js +126 -0
- package/.output/public/assets/{ReplayDialog-CZMApaF4.js → ReplayDialog-DodiTL6E.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-DNWccR7O.js → RequestAnatomy-B3IauToI.js} +1 -1
- package/.output/public/assets/ResponseView-Hn-5ordK.js +3 -0
- package/.output/public/assets/StreamingChunkSequence-vLDOVQM_.js +1 -0
- package/.output/public/assets/_sessionId-BFH4TOaI.js +1 -0
- package/.output/public/assets/{_sessionId-DRfvuE2k.js → _sessionId-Cj_HIFZx.js} +1 -1
- package/.output/public/assets/{index-D4HkS7Ct.js → index-Bmj2lcWE.js} +1 -1
- package/.output/public/assets/index-CgJj-HBC.css +1 -0
- package/.output/public/assets/index-Ch7uqnCT.js +1 -0
- package/.output/public/assets/index-DkDdKvLl.js +76 -0
- package/.output/public/assets/{index-B3aAuqWq.js → index-ZlhqCrSg.js} +6 -6
- package/.output/public/assets/{json-viewer-wuJSKaed.js → json-viewer-BdrnVQu-.js} +1 -1
- package/.output/public/assets/jszip.min-CS_nt_o1.js +2 -0
- package/.output/public/assets/qwen-mMn3f5ul.webp +0 -0
- package/.output/server/_libs/jszip.mjs +35 -9
- package/.output/server/_libs/lucide-react.mjs +86 -86
- package/.output/server/_libs/radix-ui__react-dialog.mjs +3 -3
- package/.output/server/_libs/tanstack__react-router.mjs +1 -1
- package/.output/server/{_sessionId-BJTNiP_O.mjs → _sessionId-C5S3pGZd.mjs} +15 -15
- package/.output/server/_sessionId-g6D69lKq.mjs +81 -0
- package/.output/server/_ssr/{CompareDrawer-BMRH3N97.mjs → CompareDrawer-CqUmGHal.mjs} +138 -103
- package/.output/server/_ssr/InspectorPet-DI0UJd01.mjs +925 -0
- package/.output/server/_ssr/{ProxyViewerContainer-AFwcHAIR.mjs → ProxyViewerContainer-CvsUmbJ3.mjs} +1216 -1659
- package/.output/server/_ssr/{ReplayDialog-CbWvRHiN.mjs → ReplayDialog-DS48dpFG.mjs} +18 -18
- package/.output/server/_ssr/{RequestAnatomy-C4kcPyqN.mjs → RequestAnatomy-DxYVQU1C.mjs} +58 -58
- package/.output/server/_ssr/{ResponseView-D8VYt-gZ.mjs → ResponseView-BLXW73eq.mjs} +60 -60
- package/.output/server/_ssr/{StreamingChunkSequence-BUUo6vU0.mjs → StreamingChunkSequence-DD0iFuy0.mjs} +16 -16
- package/.output/server/_ssr/{index-DTwMEEXO.mjs → index-B10LIaK0.mjs} +15 -15
- package/.output/server/_ssr/index-RHVJnU2p.mjs +81 -0
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{json-viewer-BqF1pSQD.mjs → json-viewer-LDu2XBaK.mjs} +58 -58
- package/.output/server/_ssr/{router-C8BOns7y.mjs → router-GKvrwifJ.mjs} +9005 -6488
- package/.output/server/_tanstack-start-manifest_v-Df2n4mbT.mjs +4 -0
- package/.output/server/index.mjs +105 -77
- package/.output/workers/logFinalizer.worker.js +16908 -0
- package/.output/workers/sessionWorkerEntry.js +16904 -0
- package/README.md +21 -5
- package/package.json +6 -2
- package/src/assets/logos/qwen.webp +0 -0
- package/src/cli.ts +85 -10
- package/src/components/OnboardingBanner.tsx +41 -21
- package/src/components/ProxyViewer.tsx +198 -269
- package/src/components/ProxyViewerContainer.tsx +128 -17
- package/src/components/clients/ClientLogo.tsx +9 -6
- package/src/components/ecosystem/AgentLabDialog.tsx +166 -19
- package/src/components/errors/SafeErrorBoundary.tsx +201 -0
- package/src/components/pi-agent/PiAgentPanel.tsx +4 -1
- package/src/components/providers/ImportWizardDialog.tsx +18 -42
- package/src/components/providers/ProviderLogo.tsx +1 -1
- package/src/components/providers/ProvidersPanel.tsx +8 -5
- package/src/components/providers/SettingsDialog.tsx +34 -11
- package/src/components/proxy-viewer/ApplicationBar.tsx +63 -0
- package/src/components/proxy-viewer/CompareDrawer.tsx +92 -49
- package/src/components/proxy-viewer/ConversationGroupList.tsx +49 -34
- package/src/components/proxy-viewer/ConversationHeader.tsx +22 -18
- package/src/components/proxy-viewer/LiveConnectionStatus.tsx +186 -0
- package/src/components/proxy-viewer/LogEntry.tsx +283 -275
- package/src/components/proxy-viewer/RawExportWarning.tsx +77 -0
- package/src/components/proxy-viewer/SessionLoadProgressBar.tsx +61 -0
- package/src/components/proxy-viewer/ThreadConnector.tsx +16 -1
- package/src/components/proxy-viewer/TurnGroup.tsx +13 -2
- package/src/components/proxy-viewer/accessibility.ts +8 -0
- package/src/components/proxy-viewer/lazy.ts +4 -0
- package/src/components/proxy-viewer/liveConnectionState.ts +158 -0
- package/src/components/proxy-viewer/proxyViewerLogic.ts +10 -0
- package/src/components/proxy-viewer/viewerState.ts +2 -6
- package/src/components/ui/select.tsx +1 -1
- package/src/components/ui/tabs.tsx +3 -3
- package/src/components/ui/transient-toast.tsx +1 -1
- package/src/lib/apiClient.ts +17 -2
- package/src/lib/ecosystemContract.ts +34 -0
- package/src/lib/export-logs.ts +1 -1
- package/src/lib/providerContract.ts +70 -4
- package/src/lib/providerImportContract.ts +27 -0
- package/src/lib/providerModelMetadata.ts +16 -7
- package/src/lib/resourceLimits.ts +152 -0
- package/src/lib/safeDiagnostic.ts +38 -0
- package/src/lib/useProviders.ts +4 -4
- package/src/lib/utils.ts +5 -1
- package/src/mcp/server.ts +39 -6
- package/src/mcp/toolHandlers.ts +131 -4
- package/src/proxy/chunkStorage.ts +20 -6
- package/src/proxy/config.ts +20 -6
- package/src/proxy/dataDir.ts +3 -0
- package/src/proxy/ecosystemExecutionConfirmation.ts +114 -0
- package/src/proxy/ecosystemExecutionRoute.ts +116 -0
- package/src/proxy/ecosystemTasks.ts +48 -0
- package/src/proxy/evidenceExporter.ts +23 -9
- package/src/proxy/groupEvidenceExporter.ts +26 -5
- package/src/proxy/groupStore.ts +13 -3
- package/src/proxy/handler.ts +103 -20
- package/src/proxy/identityProxy.ts +333 -14
- package/src/proxy/logFinalizer.ts +73 -6
- package/src/proxy/logImportUpload.ts +128 -0
- package/src/proxy/logImporter.ts +321 -70
- package/src/proxy/logIndex.ts +16 -6
- package/src/proxy/logger.ts +294 -41
- package/src/proxy/privateDataPath.ts +183 -0
- package/src/proxy/providerScanStore.ts +87 -0
- package/src/proxy/providerSecretStore.ts +58 -19
- package/src/proxy/providers.ts +175 -58
- package/src/proxy/rawStreamCapture.ts +66 -5
- package/src/proxy/runStore.ts +13 -3
- package/src/proxy/runtimeAdmission.ts +52 -0
- package/src/proxy/runtimeHealth.ts +206 -0
- package/src/proxy/runtimeShutdown.ts +75 -0
- package/src/proxy/sessionArchive.ts +15 -2
- package/src/proxy/sessionProcess.ts +19 -0
- package/src/proxy/sessionRuntime.ts +7 -0
- package/src/proxy/shutdownCoordinator.ts +90 -0
- package/src/proxy/sqliteLogIndex.ts +18 -2
- package/src/proxy/store.ts +18 -2
- package/src/routes/__root.tsx +18 -1
- package/src/routes/api/alerts.summary.ts +12 -8
- package/src/routes/api/alerts.ts +27 -9
- package/src/routes/api/ecosystem.packages.$packageId.help.ts +3 -8
- package/src/routes/api/ecosystem.packages.$packageId.install.ts +3 -8
- package/src/routes/api/ecosystem.packages.$packageId.runner-presets.ts +3 -11
- package/src/routes/api/ecosystem.packages.$packageId.upgrade.ts +3 -8
- package/src/routes/api/ecosystem.recipes.$recipeId.run.ts +3 -8
- package/src/routes/api/health.ts +9 -2
- package/src/routes/api/knowledge.project-context.ts +11 -0
- package/src/routes/api/knowledge.search.ts +33 -2
- package/src/routes/api/logs.$id.body.ts +16 -2
- package/src/routes/api/logs.import.ts +7 -18
- package/src/routes/api/logs.stream.ts +147 -69
- package/src/routes/api/logs.ts +55 -14
- package/src/routes/api/providers.$providerId.model-metadata.ts +22 -4
- package/src/routes/api/providers.$providerId.ts +37 -6
- package/src/routes/api/providers.export.ts +34 -16
- package/src/routes/api/providers.import.ts +42 -8
- package/src/routes/api/providers.scan.ts +13 -8
- package/src/routes/api/providers.ts +36 -5
- package/src/routes/api/runs.ts +12 -12
- package/src/routes/api/sessions.ts +15 -8
- package/src/routes/index.tsx +6 -0
- package/src/routes/livez.ts +13 -0
- package/src/routes/readyz.ts +18 -0
- package/src/routes/session/$sessionId.tsx +6 -0
- package/styles/globals.css +19 -3
- package/.output/public/assets/CompareDrawer-TghZr5t1.js +0 -1
- package/.output/public/assets/ProxyViewerContainer-fShBAZjj.js +0 -4234
- package/.output/public/assets/ResponseView-d25MdFhY.js +0 -3
- package/.output/public/assets/StreamingChunkSequence-DIFZEnWe.js +0 -1
- package/.output/public/assets/index-BsxAGqMA.css +0 -1
- package/.output/public/assets/index-DzARL2Fi.js +0 -76
- package/.output/public/assets/qwen-CONDcHqt.png +0 -0
- package/.output/server/_tanstack-start-manifest_v-BBf2nRhb.mjs +0 -4
- package/src/assets/logos/mcp.png +0 -0
- package/src/assets/logos/qwen.png +0 -0
- package/src/components/ui/mcp-logo.tsx +0 -20
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { getProviders, addProvider, redactProvider, redactProviders } from "../../proxy/providers";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
getProviderModelLimitViolation,
|
|
6
|
+
ProviderModelMetadataListSchema,
|
|
7
|
+
ProviderModelNameSchema,
|
|
8
|
+
ProviderModelsSchema,
|
|
9
|
+
} from "../../lib/providerContract";
|
|
5
10
|
import { evaluateUpstreamUrl } from "../../lib/ssrfGuard";
|
|
11
|
+
import { resourceLimitResponse } from "../../lib/resourceLimits";
|
|
6
12
|
|
|
7
13
|
const ALLOW_LOOPBACK = process.env["AGENT_INSPECTOR_ALLOW_LOOPBACK"] === "1";
|
|
8
14
|
|
|
@@ -13,12 +19,12 @@ const ProviderInputSchema = z.object({
|
|
|
13
19
|
anthropicBaseUrl: z.string().optional(),
|
|
14
20
|
openaiBaseUrl: z.string().optional(),
|
|
15
21
|
openaiResponsesBaseUrl: z.string().optional(),
|
|
16
|
-
models:
|
|
17
|
-
model:
|
|
22
|
+
models: ProviderModelsSchema.min(1, "At least one model is required"),
|
|
23
|
+
model: ProviderModelNameSchema.optional(),
|
|
18
24
|
authHeader: z.enum(["bearer", "x-api-key"]).optional().default("bearer"),
|
|
19
25
|
apiDocsUrl: z.string().optional(),
|
|
20
26
|
modelMetadataUrl: z.string().optional(),
|
|
21
|
-
modelMetadata:
|
|
27
|
+
modelMetadata: ProviderModelMetadataListSchema.optional(),
|
|
22
28
|
source: z.enum(["company", "personal"]).optional(),
|
|
23
29
|
});
|
|
24
30
|
|
|
@@ -29,7 +35,26 @@ export const Route = createFileRoute("/api/providers")({
|
|
|
29
35
|
return Response.json(redactProviders(getProviders()));
|
|
30
36
|
},
|
|
31
37
|
POST: async ({ request }: { request: Request }) => {
|
|
32
|
-
|
|
38
|
+
let body: unknown;
|
|
39
|
+
try {
|
|
40
|
+
body = await request.json();
|
|
41
|
+
} catch {
|
|
42
|
+
return Response.json({ error: "Invalid JSON body" }, { status: 400 });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const violation = getProviderModelLimitViolation(body);
|
|
46
|
+
if (violation !== null) {
|
|
47
|
+
return resourceLimitResponse({
|
|
48
|
+
error: `Provider model collections may contain at most ${String(violation.limit)} entries.`,
|
|
49
|
+
code: "provider-model-limit-exceeded",
|
|
50
|
+
status: 413,
|
|
51
|
+
resource: violation.resource,
|
|
52
|
+
limit: violation.limit,
|
|
53
|
+
retryable: false,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const parsed = ProviderInputSchema.safeParse(body);
|
|
33
58
|
if (!parsed.success) {
|
|
34
59
|
return Response.json({ error: parsed.error.message }, { status: 400 });
|
|
35
60
|
}
|
|
@@ -59,6 +84,12 @@ export const Route = createFileRoute("/api/providers")({
|
|
|
59
84
|
parsed.data.modelMetadata,
|
|
60
85
|
parsed.data.openaiResponsesBaseUrl,
|
|
61
86
|
);
|
|
87
|
+
if (newProvider === null) {
|
|
88
|
+
return Response.json(
|
|
89
|
+
{ error: "Secure provider storage is unavailable; provider was not created" },
|
|
90
|
+
{ status: 503 },
|
|
91
|
+
);
|
|
92
|
+
}
|
|
62
93
|
return Response.json(redactProvider(newProvider), { status: 201 });
|
|
63
94
|
},
|
|
64
95
|
},
|
package/src/routes/api/runs.ts
CHANGED
|
@@ -6,6 +6,8 @@ import {
|
|
|
6
6
|
listInspectorRecentFailures,
|
|
7
7
|
listInspectorRuns,
|
|
8
8
|
} from "../../services/runs";
|
|
9
|
+
import { RECENT_FAILURES_MAX_LIMIT } from "../../proxy/runFailures";
|
|
10
|
+
import { parseBoundedIntegerParameter } from "../../lib/resourceLimits";
|
|
9
11
|
|
|
10
12
|
type JsonBodyResult = { ok: true; value: unknown } | { ok: false };
|
|
11
13
|
|
|
@@ -19,24 +21,22 @@ async function readJsonBody(request: Request): Promise<JsonBodyResult> {
|
|
|
19
21
|
}
|
|
20
22
|
}
|
|
21
23
|
|
|
22
|
-
function parsePositiveInt(value: string | null, fallback: number): number {
|
|
23
|
-
if (value === null) return fallback;
|
|
24
|
-
const parsed = Number(value);
|
|
25
|
-
if (!Number.isInteger(parsed) || parsed < 1) return fallback;
|
|
26
|
-
return parsed;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
24
|
export const Route = createFileRoute("/api/runs")({
|
|
30
25
|
server: {
|
|
31
26
|
handlers: {
|
|
32
27
|
GET: ({ request }: { request: Request }) => {
|
|
33
28
|
const url = new URL(request.url);
|
|
34
29
|
if (url.searchParams.get("failures") === "1") {
|
|
35
|
-
const
|
|
36
|
-
url.searchParams.get("limit"),
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
30
|
+
const limitResult = parseBoundedIntegerParameter({
|
|
31
|
+
value: url.searchParams.get("limit"),
|
|
32
|
+
parameter: "limit",
|
|
33
|
+
fallback: RECENT_FAILURES_DEFAULT_LIMIT,
|
|
34
|
+
minimum: 1,
|
|
35
|
+
maximum: RECENT_FAILURES_MAX_LIMIT,
|
|
36
|
+
resource: "recent-failures-page-size",
|
|
37
|
+
});
|
|
38
|
+
if (!limitResult.ok) return limitResult.response;
|
|
39
|
+
return Response.json(listInspectorRecentFailures(limitResult.value));
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
return Response.json(listInspectorRuns());
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
2
|
import { getSessionInfo, getSessionSnapshots, listSessions } from "../../proxy/store";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
return parsed;
|
|
9
|
-
}
|
|
3
|
+
import {
|
|
4
|
+
SESSION_INFO_DEFAULT_LATEST_LOG_LIMIT,
|
|
5
|
+
SESSION_INFO_MAX_LATEST_LOG_LIMIT,
|
|
6
|
+
} from "../../proxy/sessionInfo";
|
|
7
|
+
import { parseBoundedIntegerParameter } from "../../lib/resourceLimits";
|
|
10
8
|
|
|
11
9
|
function parseBooleanFlag(value: string | null): boolean {
|
|
12
10
|
return value === "1" || value === "true";
|
|
@@ -22,10 +20,19 @@ export const Route = createFileRoute("/api/sessions")({
|
|
|
22
20
|
if (sessionId.length === 0) {
|
|
23
21
|
return Response.json({ error: "sessionId is required" }, { status: 400 });
|
|
24
22
|
}
|
|
23
|
+
const limitResult = parseBoundedIntegerParameter({
|
|
24
|
+
value: url.searchParams.get("limit"),
|
|
25
|
+
parameter: "limit",
|
|
26
|
+
fallback: SESSION_INFO_DEFAULT_LATEST_LOG_LIMIT,
|
|
27
|
+
minimum: 1,
|
|
28
|
+
maximum: SESSION_INFO_MAX_LATEST_LOG_LIMIT,
|
|
29
|
+
resource: "session-log-page-size",
|
|
30
|
+
});
|
|
31
|
+
if (!limitResult.ok) return limitResult.response;
|
|
25
32
|
const info = await getSessionInfo(sessionId, {
|
|
26
33
|
baseUrl: url.origin,
|
|
27
34
|
includeHistory: parseBooleanFlag(url.searchParams.get("includeHistory")),
|
|
28
|
-
latestLogLimit:
|
|
35
|
+
latestLogLimit: limitResult.value,
|
|
29
36
|
});
|
|
30
37
|
if (info === null) {
|
|
31
38
|
return Response.json({ error: "Session not found" }, { status: 404 });
|
package/src/routes/index.tsx
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
2
|
import { useEffect, useState, type JSX } from "react";
|
|
3
|
+
import { SafeRouteError } from "../components/errors/SafeErrorBoundary";
|
|
3
4
|
import { ProxyViewerContainer } from "../components/ProxyViewerContainer";
|
|
4
5
|
|
|
5
6
|
export const Route = createFileRoute("/")({
|
|
6
7
|
ssr: false,
|
|
7
8
|
component: ClientOnlyProxyViewerRoute,
|
|
9
|
+
errorComponent: HomeRouteError,
|
|
8
10
|
});
|
|
9
11
|
|
|
12
|
+
function HomeRouteError({ error, reset }: { error: Error; reset: () => void }): JSX.Element {
|
|
13
|
+
return <SafeRouteError error={error} reset={reset} scope="home-route" />;
|
|
14
|
+
}
|
|
15
|
+
|
|
10
16
|
function ClientOnlyProxyViewerRoute(): JSX.Element {
|
|
11
17
|
const [mounted, setMounted] = useState(false);
|
|
12
18
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
2
|
+
|
|
3
|
+
export function livenessResponse(): Response {
|
|
4
|
+
return Response.json({ status: "ok" }, { headers: { "cache-control": "no-store" } });
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const Route = createFileRoute("/livez")({
|
|
8
|
+
server: {
|
|
9
|
+
handlers: {
|
|
10
|
+
GET: livenessResponse,
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { createFileRoute } from "@tanstack/react-router";
|
|
2
|
+
import { getRuntimeReadiness } from "../proxy/runtimeHealth";
|
|
3
|
+
|
|
4
|
+
export async function readinessResponse(): Promise<Response> {
|
|
5
|
+
const readiness = await getRuntimeReadiness();
|
|
6
|
+
return Response.json(readiness, {
|
|
7
|
+
status: readiness.status === "unavailable" ? 503 : 200,
|
|
8
|
+
headers: { "cache-control": "no-store" },
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const Route = createFileRoute("/readyz")({
|
|
13
|
+
server: {
|
|
14
|
+
handlers: {
|
|
15
|
+
GET: readinessResponse,
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createFileRoute } from "@tanstack/react-router";
|
|
2
2
|
import { useEffect, useState, type JSX } from "react";
|
|
3
|
+
import { SafeRouteError } from "../../components/errors/SafeErrorBoundary";
|
|
3
4
|
import { ProxyViewerContainer } from "../../components/ProxyViewerContainer";
|
|
4
5
|
import { decodeSessionIdFromPath, encodeSessionIdForPath } from "../../lib/sessionUrl";
|
|
5
6
|
|
|
@@ -11,6 +12,7 @@ import { decodeSessionIdFromPath, encodeSessionIdForPath } from "../../lib/sessi
|
|
|
11
12
|
export const Route = createFileRoute("/session/$sessionId")({
|
|
12
13
|
ssr: false,
|
|
13
14
|
component: SessionViewerRoute,
|
|
15
|
+
errorComponent: SessionRouteError,
|
|
14
16
|
parseParams: (params) => ({
|
|
15
17
|
sessionId: decodeSessionIdFromPath(params.sessionId),
|
|
16
18
|
}),
|
|
@@ -19,6 +21,10 @@ export const Route = createFileRoute("/session/$sessionId")({
|
|
|
19
21
|
}),
|
|
20
22
|
});
|
|
21
23
|
|
|
24
|
+
function SessionRouteError({ error, reset }: { error: Error; reset: () => void }): JSX.Element {
|
|
25
|
+
return <SafeRouteError error={error} reset={reset} scope="session-route" />;
|
|
26
|
+
}
|
|
27
|
+
|
|
22
28
|
function SessionViewerRoute(): JSX.Element {
|
|
23
29
|
const { sessionId } = Route.useParams();
|
|
24
30
|
return <ClientOnlySessionViewer sessionId={sessionId} />;
|
package/styles/globals.css
CHANGED
|
@@ -25,6 +25,13 @@
|
|
|
25
25
|
--color-input: var(--input);
|
|
26
26
|
--color-border: var(--border);
|
|
27
27
|
--color-destructive: var(--destructive);
|
|
28
|
+
--color-warning: var(--warning);
|
|
29
|
+
--color-status-cool: var(--inspector-status-cool);
|
|
30
|
+
--color-status-info: var(--inspector-status-info);
|
|
31
|
+
--color-status-success: var(--inspector-status-success);
|
|
32
|
+
--color-status-watch: var(--inspector-status-watch);
|
|
33
|
+
--color-status-danger: var(--inspector-status-danger);
|
|
34
|
+
--color-status-accent: var(--inspector-status-accent);
|
|
28
35
|
--color-accent-foreground: var(--accent-foreground);
|
|
29
36
|
--color-accent: var(--accent);
|
|
30
37
|
--color-muted-foreground: var(--muted-foreground);
|
|
@@ -51,9 +58,11 @@
|
|
|
51
58
|
--radius: 0.625rem;
|
|
52
59
|
--inspector-ui-scale: 1;
|
|
53
60
|
--inspector-root-font-size: 16px;
|
|
54
|
-
--inspector-font-
|
|
55
|
-
--inspector-font-
|
|
56
|
-
--inspector-font-
|
|
61
|
+
--inspector-minimum-font-size: 0.6875rem;
|
|
62
|
+
--inspector-font-8: var(--inspector-minimum-font-size);
|
|
63
|
+
--inspector-font-9: var(--inspector-minimum-font-size);
|
|
64
|
+
--inspector-font-10: var(--inspector-minimum-font-size);
|
|
65
|
+
--inspector-font-11: var(--inspector-minimum-font-size);
|
|
57
66
|
--inspector-font-13: 13px;
|
|
58
67
|
--inspector-surface-low: color-mix(in oklch, var(--foreground) 3.5%, transparent);
|
|
59
68
|
--inspector-surface-medium: color-mix(in oklch, var(--foreground) 6%, transparent);
|
|
@@ -78,6 +87,7 @@
|
|
|
78
87
|
--accent: oklch(0.91 0.018 235);
|
|
79
88
|
--accent-foreground: oklch(0.24 0.035 240);
|
|
80
89
|
--destructive: oklch(0.5 0.2 27);
|
|
90
|
+
--warning: oklch(0.43 0.12 70);
|
|
81
91
|
--border: oklch(0.85 0.01 250);
|
|
82
92
|
--input: oklch(0.78 0.015 250);
|
|
83
93
|
--ring: oklch(0.48 0.11 230);
|
|
@@ -112,6 +122,7 @@
|
|
|
112
122
|
--accent: oklch(0.269 0 0);
|
|
113
123
|
--accent-foreground: oklch(0.985 0 0);
|
|
114
124
|
--destructive: oklch(0.704 0.191 22.216);
|
|
125
|
+
--warning: oklch(0.76 0.14 78);
|
|
115
126
|
--border: oklch(1 0 0 / 10%);
|
|
116
127
|
--input: oklch(1 0 0 / 15%);
|
|
117
128
|
--ring: oklch(0.556 0 0);
|
|
@@ -152,6 +163,7 @@
|
|
|
152
163
|
--accent: oklch(0.84 0.045 148);
|
|
153
164
|
--accent-foreground: oklch(0.25 0.055 151);
|
|
154
165
|
--destructive: oklch(0.47 0.17 28);
|
|
166
|
+
--warning: oklch(0.4 0.1 70);
|
|
155
167
|
--border: oklch(0.76 0.028 132);
|
|
156
168
|
--input: oklch(0.7 0.034 132);
|
|
157
169
|
--ring: oklch(0.42 0.1 154);
|
|
@@ -331,6 +343,10 @@
|
|
|
331
343
|
}
|
|
332
344
|
|
|
333
345
|
@layer utilities {
|
|
346
|
+
[class~="text-[8px]"] {
|
|
347
|
+
font-size: var(--inspector-font-8);
|
|
348
|
+
}
|
|
349
|
+
|
|
334
350
|
[class~="text-[9px]"] {
|
|
335
351
|
font-size: var(--inspector-font-9);
|
|
336
352
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as h,j as t}from"./index-DzARL2Fi.js";import{c as Z,g as $,r as L,a as q,X as ee,b as m,B as te,f as P,R as re,C as ne,M as V,d as _,e as M,h as B,i as se,j as ae,k as oe,L as ie}from"./ProxyViewerContainer-fShBAZjj.js";const de=[["line",{x1:"5",x2:"19",y1:"9",y2:"9",key:"1nwqeh"}],["line",{x1:"5",x2:"19",y1:"15",y2:"15",key:"g8yjpy"}]],le=Z("equal",de),ce="";function j(e){if(e.length===0)return ce;let r="";for(let n=0;n<e.length;n++){const a=e[n];a!==void 0&&(typeof a=="number"?r+=`[${a}]`:n===0?r+=a:r+=`.${a}`)}return r}function ue(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(ue(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 xe(e,r){const n=[];return R([],e,r,n),n}function R(e,r,n,a){const d=j(e);if(S(r,n)){a.push({kind:"equal",path:d,value:r});return}if(r.kind!==n.kind){a.push({kind:"changed",path:d,left:r,right:n});return}if(r.kind==="primitive"&&n.kind==="primitive"){a.push({kind:"changed",path:d,left:r,right:n});return}if(r.kind==="object"&&n.kind==="object"){const i=Object.keys(r.value),s=Object.keys(n.value),o=new Set(s);for(const l of i){const f=r.value[l];if(f!==void 0)if(!o.has(l))a.push({kind:"removed",path:j([...e,l]),value:f});else{const p=n.value[l];if(p===void 0)continue;R([...e,l],f,p,a)}}for(const l of s){if(i.includes(l))continue;const f=n.value[l];f!==void 0&&a.push({kind:"added",path:j([...e,l]),value:f})}return}if(r.kind==="array"&&n.kind==="array"){const i=Math.min(r.value.length,n.value.length);for(let s=0;s<i;s++){const o=r.value[s],l=n.value[s];o===void 0||l===void 0||R([...e,s],o,l,a)}for(let s=i;s<n.value.length;s++){const o=n.value[s];o!==void 0&&a.push({kind:"added",path:j([...e,s]),value:o})}for(let s=i;s<r.value.length;s++){const o=r.value[s];o!==void 0&&a.push({kind:"removed",path:j([...e,s]),value:o})}}}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 a=e.value[n],d=r.value[n];if(a===void 0||d===void 0||!S(a,d))return!1}return!0}if(e.kind==="object"&&r.kind==="object"){const n=Object.keys(e.value),a=Object.keys(r.value);if(n.length!==a.length)return!1;for(const d of n){const i=e.value[d],s=r.value[d];if(i===void 0||s===void 0||!S(i,s))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,a]of Object.entries(e.value))r[n]=E(a);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(ie,{text:e,defaultExpandDepth:r})})}function K(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 A(e){return e.kind==="equal"&&(e.value.kind==="object"||e.value.kind==="array")}function me(e){const r=[];let n=0;for(;n<e.length;){const a=e[n];if(a!==void 0&&A(a)){const d=K(a.path);let i=n+1;for(;i<e.length;){const s=e[i];if(s===void 0||!A(s)||K(s.path)!==d)break;i++}if(i-n>1){const s=[];for(let o=n;o<i;o++){const l=e[o];l!==void 0&&l.kind==="equal"&&s.push(l)}r.push({kind:"equal-run",ops:s}),n=i;continue}}a!==void 0&&r.push({kind:"single",op:a}),n++}return r}const F={added:{icon:_,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:V,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:M,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:le,accent:"text-muted-foreground/70",bg:"bg-muted/20 hover:bg-muted/30",border:"border-l-muted-foreground/20",label:"EQUAL"}};function fe({ops:e,expanded:r,onToggle:n}){const a=e[0],d=e[e.length-1];if(a===void 0||d===void 0)return t.jsx("div",{className:"text-muted-foreground/40 text-xs",children:"—"});const i=a.path,s=d.path,o=e.length===1?i:`${i} … ${s}`,l=a.value.kind==="array"?`${e.length} equal arrays`:a.value.kind==="object"?`${e.length} equal objects`:"equal",f=F.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(B,{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:`${i} … ${s}`,children:o}),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:["(",l,")"]})]}),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 pe({op:e,idx:r,copiedPath:n,onCopyPath:a,expanded:d,onToggle:i}){const s=F[e.kind],o=s.icon,l=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",s.border,s.bg),children:[t.jsxs("button",{type:"button",onClick:i,disabled:!l,className:m("w-full flex items-center gap-2 text-xs text-left rounded-sm",l?"cursor-pointer":"cursor-default"),"aria-expanded":l?d:void 0,"aria-label":l?d?`Collapse ${e.path||"root"}`:`Expand ${e.path||"root"}`:void 0,children:[l?t.jsx(B,{className:m("size-3 shrink-0 transition-transform",s.accent,d&&"rotate-90")}):t.jsx("span",{className:"size-3 shrink-0","aria-hidden":"true"}),t.jsx(o,{className:m("size-3.5 shrink-0",s.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",s.accent,e.kind==="equal"?"bg-muted/40":"bg-background/60"),children:s.label}),e.path!==""&&t.jsx("span",{role:"button",tabIndex:0,onClick:b=>{b.stopPropagation(),a(e.path)},onKeyDown:b=>{(b.key==="Enter"||b.key===" ")&&(b.stopPropagation(),b.preventDefault(),a(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(se,{className:"size-3"}):t.jsx(ae,{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&&l?"2000px":"0"},"aria-hidden":!d,children:d&&l&&e.kind!=="equal"?t.jsx(he,{op:e}):null})]})}function he({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 be({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(V,{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(_,{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(M,{className:"size-3"}),e.changed," changed"]})]})}function ve({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(re,{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(ne,{className:"size-3"}),"Split"]})]})}function J({log:e,side:r,displayNumber:n}){const a=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(te,{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",title:`Log ID ${String(e.id)}`,children:["#",n]}),e.model!==null&&t.jsx("span",{className:"font-mono leading-snug text-muted-foreground",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 +",P(e.cacheCreationInputTokens)]}),e.cacheReadInputTokens!==null&&e.cacheReadInputTokens>0&&t.jsxs("span",{className:"text-purple-400",children:["KV Cache ~",P(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:a,children:["session: ",a]})]})}function ye({left:e,right:r,leftDisplayNumber:n,rightDisplayNumber:a,onClose:d}){const i=h.useMemo(()=>{const c=$(L(e)).analyzeRequest(e.rawRequestBody),u=$(L(r)).analyzeRequest(r.rawRequestBody),x=D(c.comparisonValue),g=D(u.comparisonValue);return xe(x,g)},[e.apiFormat,e.path,e.rawRequestBody,r.apiFormat,r.path,r.rawRequestBody]),s=h.useMemo(()=>me(i),[i]),o=h.useMemo(()=>{let c=0,u=0,x=0;for(const g of s)if(g.kind==="single")switch(g.op.kind){case"added":c++;break;case"removed":u++;break;case"changed":x++;break}return{added:c,removed:u,changed:x}},[s]),[l,f]=h.useState(new Set),p=c=>{f(u=>{const x=new Set(u);return x.has(c)?x.delete(c):x.add(c),x})},[b,y]=h.useState(new Set),U=c=>{y(u=>{const x=new Set(u);return x.has(c)?x.delete(c):x.add(c),x})};h.useEffect(()=>{y(new Set)},[e.id,r.id]);const[T,H]=h.useState("unified"),I=h.useRef(null),[G,z]=h.useState(null),k=h.useRef(null),Q=c=>{oe(c).then(u=>{u&&(z(c),k.current!==null&&clearTimeout(k.current),k.current=setTimeout(()=>z(null),1500))})};h.useEffect(()=>()=>{k.current!==null&&clearTimeout(k.current)},[]);const W=c=>{const u=s.findIndex(O=>O.kind==="single"&&O.op.kind===c);if(u===-1)return;const x=I.current;if(x===null)return;const g=x.querySelector(`[data-diff-idx="${u}"]`);g!==null&&g.scrollIntoView({behavior:"smooth",block:"center"})};h.useEffect(()=>{const c=x=>{x.key==="Escape"&&d()};document.addEventListener("keydown",c);const u=document.body.style.overflow;return document.body.style.overflow="hidden",()=>{document.removeEventListener("keydown",c),document.body.style.overflow=u}},[d]);const X=q(e)===q(r),Y=i.length===1&&i[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:d,"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:c=>c.stopPropagation(),onKeyDown:c=>c.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(J,{log:e,side:"left",displayNumber:n}),t.jsx(J,{log:r,side:"right",displayNumber:a})]}),t.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[t.jsx(ve,{mode:T,onChange:H}),t.jsx("button",{type:"button",onClick:d,"aria-label":"Close",className:"p-1 rounded text-muted-foreground hover:text-foreground hover:bg-muted cursor-pointer",children:t.jsx(ee,{className:"size-4"})})]})]}),!X&&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."}),Y?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(be,{counts:o,onJumpTo:W}),t.jsx("div",{ref:I,className:"flex-1 min-h-0 overflow-y-auto",children:T==="unified"?t.jsx("div",{className:"px-3 py-2 space-y-0.5",children:s.map((c,u)=>{if(c.kind==="equal-run")return t.jsx(fe,{ops:c.ops,expanded:l.has(u),onToggle:()=>p(u)},`r${u}`);const x=c.op;return t.jsx(pe,{op:x,idx:u,copiedPath:G,onCopyPath:Q,expanded:b.has(u),onToggle:()=>U(u)},`o${u}`)})}):t.jsx(ge,{grouped:s,left:e,right:r,leftDisplayNumber:n,rightDisplayNumber:a})})]})]})]})}function ge({grouped:e,left:r,right:n,leftDisplayNumber:a,rightDisplayNumber:d}){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",{title:`Log ID ${String(r.id)}`,children:["Left (Log #",a,")"]}),t.jsxs("span",{title:`Log ID ${String(n.id)}`,children:["Right (Log #",d,")"]})]}),e.map((i,s)=>{if(i.kind==="equal-run")return t.jsxs("div",{className:"col-span-3 px-2 py-1 text-xs text-muted-foreground/60",children:[i.ops.length," equal siblings collapsed — switch to Unified to expand"]},s);const o=i.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)})]},s):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)]})]},s):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)]})]},s):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)})]})]},s)})]})}export{ye as CompareDrawer};
|