@post-print/agent-test 2.0.0 → 2.0.1

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 (134) hide show
  1. package/dist/sdk/cli.d.ts +1 -1
  2. package/dist/sdk/cli.d.ts.map +1 -1
  3. package/dist/sdk/cli.js +49 -14
  4. package/dist/sdk/cli.js.map +1 -1
  5. package/dist/sdk/definitions.js +1 -1
  6. package/dist/sdk/definitions.js.map +1 -1
  7. package/dist/sdk/execution-reporter.d.ts +18 -0
  8. package/dist/sdk/execution-reporter.d.ts.map +1 -0
  9. package/dist/sdk/execution-reporter.js +171 -0
  10. package/dist/sdk/execution-reporter.js.map +1 -0
  11. package/dist/sdk/execution-runner.d.ts +14 -0
  12. package/dist/sdk/execution-runner.d.ts.map +1 -0
  13. package/dist/sdk/execution-runner.js +80 -0
  14. package/dist/sdk/execution-runner.js.map +1 -0
  15. package/dist/sdk/execution-store.d.ts +92 -0
  16. package/dist/sdk/execution-store.d.ts.map +1 -0
  17. package/dist/sdk/execution-store.js +357 -0
  18. package/dist/sdk/execution-store.js.map +1 -0
  19. package/dist/sdk/expect.d.ts.map +1 -1
  20. package/dist/sdk/expect.js +33 -5
  21. package/dist/sdk/expect.js.map +1 -1
  22. package/dist/sdk/playwright-cli.d.ts +2 -0
  23. package/dist/sdk/playwright-cli.d.ts.map +1 -0
  24. package/dist/sdk/playwright-cli.js +6 -0
  25. package/dist/sdk/playwright-cli.js.map +1 -0
  26. package/dist/sdk/reporter.d.ts.map +1 -1
  27. package/dist/sdk/reporter.js +40 -0
  28. package/dist/sdk/reporter.js.map +1 -1
  29. package/dist/sdk/runtime.d.ts +1 -1
  30. package/dist/sdk/runtime.d.ts.map +1 -1
  31. package/dist/sdk/runtime.js +14 -5
  32. package/dist/sdk/runtime.js.map +1 -1
  33. package/dist/sdk/test.d.ts +10 -1
  34. package/dist/sdk/test.d.ts.map +1 -1
  35. package/dist/sdk/test.js +45 -4
  36. package/dist/sdk/test.js.map +1 -1
  37. package/dist/sdk/types.d.ts +2 -1
  38. package/dist/sdk/types.d.ts.map +1 -1
  39. package/dist/sdk/viewer.d.ts +3 -9
  40. package/dist/sdk/viewer.d.ts.map +1 -1
  41. package/dist/sdk/viewer.js +41 -127
  42. package/dist/sdk/viewer.js.map +1 -1
  43. package/dist/viewer/bootstrap.d.ts +10 -0
  44. package/dist/viewer/bootstrap.d.ts.map +1 -0
  45. package/dist/viewer/bootstrap.js +2 -0
  46. package/dist/viewer/bootstrap.js.map +1 -0
  47. package/dist/viewer/client-entry.d.ts +2 -0
  48. package/dist/viewer/client-entry.d.ts.map +1 -0
  49. package/dist/viewer/client-entry.js +31 -0
  50. package/dist/viewer/client-entry.js.map +1 -0
  51. package/dist/viewer/generated-api.d.ts +15 -0
  52. package/dist/viewer/generated-api.d.ts.map +1 -0
  53. package/dist/viewer/generated-api.js +42 -0
  54. package/dist/viewer/generated-api.js.map +1 -0
  55. package/dist/viewer/generated-contracts.d.ts +13 -0
  56. package/dist/viewer/generated-contracts.d.ts.map +1 -0
  57. package/dist/viewer/generated-contracts.js +12 -0
  58. package/dist/viewer/generated-contracts.js.map +1 -0
  59. package/dist/viewer/main.js +64 -3
  60. package/dist/viewer/main.js.map +1 -1
  61. package/dist/viewer/page.d.ts +2 -4
  62. package/dist/viewer/page.d.ts.map +1 -1
  63. package/dist/viewer/page.js +18 -194
  64. package/dist/viewer/page.js.map +1 -1
  65. package/dist/viewer/presentation.d.ts +8 -0
  66. package/dist/viewer/presentation.d.ts.map +1 -0
  67. package/dist/viewer/presentation.js +45 -0
  68. package/dist/viewer/presentation.js.map +1 -0
  69. package/dist/viewer/protocol.d.ts +21 -0
  70. package/dist/viewer/protocol.d.ts.map +1 -0
  71. package/dist/viewer/protocol.js +6 -0
  72. package/dist/viewer/protocol.js.map +1 -0
  73. package/dist/viewer/server.d.ts +5 -10
  74. package/dist/viewer/server.d.ts.map +1 -1
  75. package/dist/viewer/server.js +301 -199
  76. package/dist/viewer/server.js.map +1 -1
  77. package/dist/viewer/styles.d.ts +1 -1
  78. package/dist/viewer/styles.d.ts.map +1 -1
  79. package/dist/viewer/styles.js +82 -429
  80. package/dist/viewer/styles.js.map +1 -1
  81. package/dist/viewer/stylex.css +1322 -0
  82. package/dist/viewer/test-catalog.d.ts +43 -0
  83. package/dist/viewer/test-catalog.d.ts.map +1 -0
  84. package/dist/viewer/test-catalog.js +27 -0
  85. package/dist/viewer/test-catalog.js.map +1 -0
  86. package/dist/viewer/v2-client.d.ts +7 -0
  87. package/dist/viewer/v2-client.d.ts.map +1 -0
  88. package/dist/viewer/v2-client.js +1862 -0
  89. package/dist/viewer/v2-client.js.map +1 -0
  90. package/package.json +14 -4
  91. package/dist/compare-scenario.d.ts +0 -65
  92. package/dist/compare-scenario.d.ts.map +0 -1
  93. package/dist/compare-scenario.js +0 -325
  94. package/dist/compare-scenario.js.map +0 -1
  95. package/dist/failures.d.ts +0 -8
  96. package/dist/failures.d.ts.map +0 -1
  97. package/dist/failures.js +0 -7
  98. package/dist/failures.js.map +0 -1
  99. package/dist/scenario-story.d.ts +0 -41
  100. package/dist/scenario-story.d.ts.map +0 -1
  101. package/dist/scenario-story.js +0 -477
  102. package/dist/scenario-story.js.map +0 -1
  103. package/dist/scenario-usage.d.ts +0 -15
  104. package/dist/scenario-usage.d.ts.map +0 -1
  105. package/dist/scenario-usage.js +0 -18
  106. package/dist/scenario-usage.js.map +0 -1
  107. package/dist/sdk/viewer-results.d.ts +0 -43
  108. package/dist/sdk/viewer-results.d.ts.map +0 -1
  109. package/dist/sdk/viewer-results.js +0 -126
  110. package/dist/sdk/viewer-results.js.map +0 -1
  111. package/dist/types.d.ts +0 -328
  112. package/dist/types.d.ts.map +0 -1
  113. package/dist/types.js +0 -2
  114. package/dist/types.js.map +0 -1
  115. package/dist/viewer/catalog.d.ts +0 -66
  116. package/dist/viewer/catalog.d.ts.map +0 -1
  117. package/dist/viewer/catalog.js +0 -49
  118. package/dist/viewer/catalog.js.map +0 -1
  119. package/dist/viewer/client.d.ts +0 -7
  120. package/dist/viewer/client.d.ts.map +0 -1
  121. package/dist/viewer/client.js +0 -14
  122. package/dist/viewer/client.js.map +0 -1
  123. package/dist/viewer/events.d.ts +0 -118
  124. package/dist/viewer/events.d.ts.map +0 -1
  125. package/dist/viewer/events.js +0 -51
  126. package/dist/viewer/events.js.map +0 -1
  127. package/dist/viewer/run-controller.d.ts +0 -43
  128. package/dist/viewer/run-controller.d.ts.map +0 -1
  129. package/dist/viewer/run-controller.js +0 -475
  130. package/dist/viewer/run-controller.js.map +0 -1
  131. package/dist/worker-pool.d.ts +0 -12
  132. package/dist/worker-pool.d.ts.map +0 -1
  133. package/dist/worker-pool.js +0 -26
  134. package/dist/worker-pool.js.map +0 -1
@@ -0,0 +1,1862 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import * as stylex from "@stylexjs/stylex";
3
+ import { useMutation, useQueries, useQuery, useQueryClient } from "@tanstack/react-query";
4
+ import { createRootRoute, createRoute, createRouter, Link, Outlet, useNavigate, } from "@tanstack/react-router";
5
+ import { createContext, useContext, useState } from "react";
6
+ import Markdown from "react-markdown";
7
+ import { viewerApi } from "./generated-api.js";
8
+ import { assertionComparison, conversationPlaceholder, stripAnsi } from "./presentation.js";
9
+ const SENTENCE_BOUNDARY = /(?<=[.!?])\s+/;
10
+ const LOCAL_PATH_LINK = /\[([^\]]+)\]\(<local-path>[^)]*\)/g;
11
+ const runningPulse = stylex.keyframes({
12
+ "0%, 60%, 100%": { opacity: 0.3, transform: "translateY(0)" },
13
+ "30%": { opacity: 1, transform: "translateY(-2px)" },
14
+ });
15
+ const CAMEL_CASE_BOUNDARY = /([a-z])([A-Z])/g;
16
+ const INITIAL_CHARACTER = /^./;
17
+ const WorkerContext = createContext({ workers: 1, setWorkers: () => undefined });
18
+ const rootRoute = createRootRoute({ component: ViewerLayout });
19
+ const indexRoute = createRoute({
20
+ getParentRoute: () => rootRoute,
21
+ path: "/",
22
+ component: TestCatalogPage,
23
+ });
24
+ const testRoute = createRoute({
25
+ getParentRoute: () => rootRoute,
26
+ path: "/tests/$testId",
27
+ validateSearch: (search) => ({
28
+ execution: typeof search.execution === "string" ? search.execution : undefined,
29
+ view: search.view === "setup" || search.view === "history" || search.view === "current"
30
+ ? search.view
31
+ : undefined,
32
+ }),
33
+ component: TestPage,
34
+ });
35
+ const executionRoute = createRoute({
36
+ getParentRoute: () => rootRoute,
37
+ path: "/executions/$executionId",
38
+ component: ExecutionPage,
39
+ });
40
+ const compareRoute = createRoute({
41
+ getParentRoute: () => rootRoute,
42
+ path: "/compare/$left/$right",
43
+ component: ComparePage,
44
+ });
45
+ export const viewerRouter = createRouter({
46
+ routeTree: rootRoute.addChildren([indexRoute, testRoute, executionRoute, compareRoute]),
47
+ });
48
+ const styles = stylex.create({
49
+ skipLink: {
50
+ position: "fixed",
51
+ top: "0.75rem",
52
+ left: "0.75rem",
53
+ zIndex: 10,
54
+ padding: "0.55rem 0.75rem",
55
+ borderRadius: 8,
56
+ backgroundColor: "var(--accent)",
57
+ color: "oklch(0.18 0.03 175)",
58
+ fontSize: "0.8rem",
59
+ fontWeight: 750,
60
+ textDecoration: "none",
61
+ transform: { default: "translateY(-200%)", ":focus": "translateY(0)" },
62
+ transition: {
63
+ default: "transform 120ms ease",
64
+ "@media (prefers-reduced-motion: reduce)": "none",
65
+ },
66
+ },
67
+ shell: {
68
+ display: "grid",
69
+ gridTemplateColumns: {
70
+ default: "18rem minmax(0, 1fr)",
71
+ "@media (max-width: 820px)": "14rem minmax(0, 1fr)",
72
+ "@media (max-width: 620px)": "1fr",
73
+ },
74
+ height: "100dvh",
75
+ minHeight: 0,
76
+ },
77
+ shellCollapsed: { gridTemplateColumns: "3.75rem minmax(0, 1fr)" },
78
+ sidebar: {
79
+ borderRight: "1px solid var(--border)",
80
+ overflow: "hidden",
81
+ display: "flex",
82
+ flexDirection: "column",
83
+ padding: "1rem 0 0",
84
+ backgroundColor: "var(--sidebar)",
85
+ minHeight: 0,
86
+ height: { default: "100dvh", "@media (max-width: 620px)": "auto" },
87
+ maxHeight: { default: "none", "@media (max-width: 620px)": "18rem" },
88
+ },
89
+ sidebarCollapsed: { paddingTop: "1rem", height: "100dvh", maxHeight: "none" },
90
+ main: {
91
+ overflow: "auto",
92
+ minWidth: 0,
93
+ padding: {
94
+ default: "2rem clamp(1.5rem, 3vw, 3rem) 3rem",
95
+ "@media (max-width: 820px)": "1.5rem 1.25rem 3rem",
96
+ "@media (max-width: 620px)": "1rem 0.85rem 2rem",
97
+ },
98
+ maxWidth: "88rem",
99
+ width: "100%",
100
+ margin: "0 auto",
101
+ },
102
+ brand: {
103
+ color: "var(--accent)",
104
+ fontSize: "0.66rem",
105
+ fontWeight: 750,
106
+ letterSpacing: "0.11em",
107
+ textTransform: "uppercase",
108
+ },
109
+ sidebarHeader: {
110
+ display: "grid",
111
+ gap: "0.65rem",
112
+ padding: "0 0.45rem 1rem",
113
+ margin: "0 0.8rem",
114
+ borderBottom: "1px solid var(--border)",
115
+ },
116
+ sidebarHeaderCollapsed: {
117
+ padding: 0,
118
+ margin: 0,
119
+ borderBottom: 0,
120
+ display: "flex",
121
+ justifyContent: "center",
122
+ },
123
+ toggleButton: {
124
+ width: "1.85rem",
125
+ height: "1.85rem",
126
+ display: "inline-grid",
127
+ placeItems: "center",
128
+ flex: "none",
129
+ padding: 0,
130
+ borderRadius: 8,
131
+ backgroundColor: {
132
+ default: "var(--panel-2)",
133
+ ":hover": "var(--panel-3)",
134
+ ":active": "var(--panel-3)",
135
+ },
136
+ color: "var(--text)",
137
+ cursor: "pointer",
138
+ fontSize: "0.95rem",
139
+ lineHeight: 1,
140
+ boxShadow: "none",
141
+ },
142
+ sidebarTitleRow: {
143
+ display: "flex",
144
+ alignItems: "center",
145
+ justifyContent: "space-between",
146
+ gap: "0.75rem",
147
+ },
148
+ sidebarTitleIdentity: { display: "flex", alignItems: "center", gap: "0.65rem" },
149
+ suiteRunButton: {
150
+ width: "fit-content",
151
+ minHeight: "1.8rem",
152
+ padding: "0.3rem 0.55rem",
153
+ borderWidth: 1,
154
+ borderStyle: "solid",
155
+ borderColor: "var(--border)",
156
+ borderRadius: 8,
157
+ backgroundColor: {
158
+ default: "var(--panel-2)",
159
+ ":hover": "var(--panel-3)",
160
+ ":disabled": "var(--panel-2)",
161
+ },
162
+ color: "var(--text)",
163
+ cursor: { default: "pointer", ":disabled": "wait" },
164
+ display: "flex",
165
+ alignItems: "center",
166
+ justifyContent: "center",
167
+ gap: "0.45rem",
168
+ fontSize: "0.7rem",
169
+ fontWeight: 700,
170
+ },
171
+ suiteControls: {
172
+ display: "grid",
173
+ gridTemplateColumns: "max-content minmax(0, 1fr)",
174
+ alignItems: "center",
175
+ columnGap: "0.75rem",
176
+ },
177
+ workerControl: {
178
+ display: "flex",
179
+ alignItems: "center",
180
+ justifySelf: "end",
181
+ gap: "0.35rem",
182
+ color: "var(--muted)",
183
+ fontSize: "0.68rem",
184
+ fontWeight: 650,
185
+ },
186
+ workerInput: {
187
+ width: "2.8rem",
188
+ height: "1.8rem",
189
+ padding: "0.25rem 0.35rem",
190
+ borderWidth: 1,
191
+ borderStyle: "solid",
192
+ borderColor: { default: "var(--border)", ":focus": "var(--accent)" },
193
+ borderRadius: 7,
194
+ backgroundColor: "var(--panel-2)",
195
+ color: "var(--text)",
196
+ fontSize: "0.72rem",
197
+ fontVariantNumeric: "tabular-nums",
198
+ outline: "none",
199
+ },
200
+ groupHeaderActions: { display: "flex", alignItems: "center", gap: "0.4rem" },
201
+ groupRunButton: {
202
+ width: "1.45rem",
203
+ height: "1.45rem",
204
+ padding: 0,
205
+ borderRadius: 6,
206
+ backgroundColor: { default: "transparent", ":hover": "var(--panel-3)" },
207
+ color: "var(--accent)",
208
+ cursor: { default: "pointer", ":disabled": "wait" },
209
+ fontSize: "0.62rem",
210
+ lineHeight: 1,
211
+ },
212
+ countBadge: {
213
+ padding: "0.22rem 0.55rem",
214
+ borderRadius: 999,
215
+ backgroundColor: "var(--panel-3)",
216
+ color: "var(--muted)",
217
+ fontSize: "0.72rem",
218
+ fontWeight: 700,
219
+ fontVariantNumeric: "tabular-nums",
220
+ },
221
+ title: {
222
+ margin: 0,
223
+ fontSize: { default: "clamp(1.08rem, 1.5vw, 1.3rem)", "@media (max-width: 620px)": "1.08rem" },
224
+ lineHeight: 1.18,
225
+ letterSpacing: "-0.025em",
226
+ fontWeight: 720,
227
+ },
228
+ sidebarTitle: { fontSize: "1.08rem" },
229
+ sectionTitle: { margin: 0, fontSize: "0.92rem", letterSpacing: "-0.01em" },
230
+ section: { display: "grid", gap: "0.75rem", marginTop: "1.5rem" },
231
+ list: { display: "grid", gap: "0.45rem" },
232
+ card: {
233
+ border: "1px solid var(--border)",
234
+ borderRadius: 14,
235
+ backgroundColor: "var(--panel-2)",
236
+ padding: "0.75rem",
237
+ },
238
+ link: { color: "var(--text)", textDecoration: "none" },
239
+ buttonReset: {
240
+ appearance: "none",
241
+ borderWidth: 0,
242
+ borderStyle: "solid",
243
+ borderColor: "transparent",
244
+ outlineWidth: { default: 0, ":focus-visible": 2 },
245
+ outlineStyle: "solid",
246
+ outlineColor: "var(--accent)",
247
+ outlineOffset: 2,
248
+ },
249
+ button: {
250
+ minHeight: "2.5rem",
251
+ padding: "0.6rem 0.95rem",
252
+ borderRadius: 8,
253
+ backgroundColor: {
254
+ default: "var(--accent)",
255
+ ":hover": "oklch(0.82 0.14 175)",
256
+ ":active": "oklch(0.72 0.14 175)",
257
+ },
258
+ color: "oklch(0.18 0.03 175)",
259
+ fontSize: "0.82rem",
260
+ fontWeight: 720,
261
+ letterSpacing: "0.01em",
262
+ display: "inline-flex",
263
+ alignItems: "center",
264
+ justifyContent: "center",
265
+ gap: "0.4rem",
266
+ cursor: "pointer",
267
+ boxShadow: "0 1px 2px oklch(0.08 0.02 258 / 0.35)",
268
+ transition: "background-color 120ms ease, border-color 120ms ease, transform 120ms ease",
269
+ transform: { default: "translateY(0)", ":active": "translateY(1px)" },
270
+ },
271
+ secondaryButton: {
272
+ borderWidth: 1,
273
+ borderStyle: "solid",
274
+ borderColor: { default: "var(--border)", ":hover": "var(--border-strong)" },
275
+ backgroundColor: {
276
+ default: "var(--panel-2)",
277
+ ":hover": "var(--panel-3)",
278
+ ":active": "var(--panel)",
279
+ },
280
+ color: "var(--text)",
281
+ boxShadow: "none",
282
+ },
283
+ buttonIcon: { fontSize: "0.68rem", opacity: 0.8 },
284
+ navigation: {
285
+ overflow: "auto",
286
+ minHeight: 0,
287
+ padding: "0.75rem 0.65rem 1rem",
288
+ display: "grid",
289
+ alignContent: "start",
290
+ gap: "0.75rem",
291
+ },
292
+ navSection: {
293
+ display: "grid",
294
+ gap: "0.18rem",
295
+ padding: "0.35rem",
296
+ borderWidth: 1,
297
+ borderStyle: "solid",
298
+ borderColor: "var(--border)",
299
+ borderRadius: 10,
300
+ backgroundColor: "var(--bg)",
301
+ },
302
+ groupHeader: {
303
+ display: "flex",
304
+ alignItems: "center",
305
+ justifyContent: "space-between",
306
+ gap: "0.75rem",
307
+ padding: "0.48rem 0.52rem 0.55rem",
308
+ borderBottom: "1px solid var(--border)",
309
+ marginBottom: "0.08rem",
310
+ },
311
+ groupLabel: {
312
+ color: "var(--text)",
313
+ fontSize: "0.66rem",
314
+ fontWeight: 780,
315
+ letterSpacing: "0.08em",
316
+ textTransform: "uppercase",
317
+ },
318
+ groupCount: { color: "var(--subtle)", fontSize: "0.66rem", fontVariantNumeric: "tabular-nums" },
319
+ navLink: {
320
+ display: "block",
321
+ padding: "0.55rem 0.6rem",
322
+ borderRadius: 8,
323
+ fontSize: "0.78rem",
324
+ fontWeight: 540,
325
+ lineHeight: 1.38,
326
+ color: "var(--muted)",
327
+ textDecoration: "none",
328
+ border: "1px solid transparent",
329
+ backgroundColor: { default: "transparent", ":hover": "var(--panel)" },
330
+ },
331
+ navItemHeader: {
332
+ display: "grid",
333
+ gridTemplateColumns: "0.65rem minmax(0, 1fr)",
334
+ alignItems: "flex-start",
335
+ gap: "0.5rem",
336
+ },
337
+ navItemTitle: { minWidth: 0 },
338
+ navStatus: {
339
+ display: "grid",
340
+ placeItems: "center",
341
+ width: "0.65rem",
342
+ height: "1.1rem",
343
+ },
344
+ navStatusDot: { width: 7, height: 7, borderRadius: 999, backgroundColor: "var(--muted)" },
345
+ navStatusDotPass: { backgroundColor: "var(--pass)" },
346
+ navStatusDotFail: { backgroundColor: "var(--fail)" },
347
+ navStatusDotRunning: { backgroundColor: "var(--skip)", boxShadow: "0 0 0 3px var(--skip-soft)" },
348
+ active: {
349
+ backgroundColor: "var(--panel-2)",
350
+ color: "var(--text)",
351
+ borderColor: "transparent",
352
+ boxShadow: "none",
353
+ },
354
+ hero: {
355
+ padding: { default: "1.1rem 1.25rem", "@media (max-width: 620px)": "1rem" },
356
+ border: "1px solid var(--border)",
357
+ borderRadius: 12,
358
+ backgroundColor: "var(--panel)",
359
+ display: "grid",
360
+ gap: "0.7rem",
361
+ boxShadow: "0 10px 30px oklch(0.08 0.02 258 / 0.14)",
362
+ },
363
+ heroTop: {
364
+ display: "grid",
365
+ gridTemplateColumns: {
366
+ default: "minmax(0, 1fr) max-content",
367
+ "@media (max-width: 620px)": "1fr",
368
+ },
369
+ alignItems: "flex-start",
370
+ gap: "1rem",
371
+ },
372
+ heroCopy: { display: "grid", gap: "0.35rem", maxWidth: "56rem", minWidth: 0 },
373
+ heroAction: {
374
+ justifySelf: { default: "end", "@media (max-width: 620px)": "start" },
375
+ alignSelf: "start",
376
+ },
377
+ description: { color: "var(--muted)", fontSize: "0.82rem", lineHeight: 1.5, maxWidth: "54rem" },
378
+ path: {
379
+ color: "var(--subtle)",
380
+ fontSize: "0.7rem",
381
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
382
+ wordBreak: "break-word",
383
+ paddingTop: "0.6rem",
384
+ borderTopWidth: 1,
385
+ borderTopStyle: "solid",
386
+ borderTopColor: "var(--border)",
387
+ },
388
+ meta: { color: "var(--muted)", fontSize: "0.8rem", lineHeight: 1.45 },
389
+ contextPanel: {
390
+ border: "1px solid var(--border)",
391
+ borderRadius: 12,
392
+ backgroundColor: "var(--panel)",
393
+ overflow: "hidden",
394
+ },
395
+ contextHeader: {
396
+ display: "flex",
397
+ alignItems: "flex-start",
398
+ justifyContent: "space-between",
399
+ gap: "1rem",
400
+ padding: "0.75rem 0.9rem",
401
+ borderBottom: "1px solid var(--border)",
402
+ },
403
+ contextIntro: { display: "grid", gap: "0.2rem" },
404
+ resourceCount: { color: "var(--accent)", fontSize: "0.75rem", fontWeight: 700 },
405
+ detailsBody: { padding: "0.75rem", display: "grid", gap: "0.6rem" },
406
+ setupBody: { padding: "0.85rem 0.9rem", display: "grid", gap: "1.15rem" },
407
+ setupSection: { display: "grid", gap: "0.55rem" },
408
+ setupSectionHeader: {
409
+ display: "flex",
410
+ alignItems: "flex-start",
411
+ justifyContent: "space-between",
412
+ gap: "1rem",
413
+ },
414
+ setupSectionCopy: { display: "grid", gap: "0.12rem" },
415
+ resourceGrid: {
416
+ display: "grid",
417
+ gridTemplateColumns: "repeat(auto-fill, minmax(min(17rem, 100%), 22rem))",
418
+ gap: "0.6rem",
419
+ },
420
+ resourceCard: {
421
+ display: "grid",
422
+ alignContent: "start",
423
+ gap: "0.5rem",
424
+ padding: "0.7rem 0.75rem",
425
+ },
426
+ resourceHeader: {
427
+ display: "flex",
428
+ alignItems: "center",
429
+ justifyContent: "space-between",
430
+ gap: "0.75rem",
431
+ },
432
+ resourceKind: {
433
+ color: "var(--accent)",
434
+ backgroundColor: "var(--accent-soft)",
435
+ borderRadius: 999,
436
+ padding: "0.16rem 0.48rem",
437
+ fontSize: "0.65rem",
438
+ fontWeight: 750,
439
+ textTransform: "uppercase",
440
+ letterSpacing: "0.05em",
441
+ },
442
+ resourceBody: { display: "grid", gap: "0.5rem" },
443
+ resourceFacts: { display: "grid", gap: "0.22rem" },
444
+ resourceDescription: {
445
+ color: "var(--text)",
446
+ fontSize: "0.77rem",
447
+ lineHeight: 1.5,
448
+ margin: 0,
449
+ },
450
+ resourceFact: {
451
+ display: "grid",
452
+ gridTemplateColumns: "4.5rem minmax(0, 1fr)",
453
+ gap: "0.65rem",
454
+ alignItems: "baseline",
455
+ },
456
+ resourceFactLabel: {
457
+ color: "var(--subtle)",
458
+ fontSize: "0.7rem",
459
+ fontWeight: 700,
460
+ textTransform: "uppercase",
461
+ letterSpacing: "0.04em",
462
+ },
463
+ resourceFactValue: { color: "var(--muted)", fontSize: "0.78rem", wordBreak: "break-word" },
464
+ resourcePrompt: {
465
+ marginTop: "0.5rem",
466
+ padding: "0.55rem",
467
+ borderRadius: 8,
468
+ border: "1px solid var(--border)",
469
+ backgroundColor: "var(--bg)",
470
+ display: "grid",
471
+ gap: "0.25rem",
472
+ },
473
+ disclosureIcon: { color: "var(--accent)", fontSize: "0.8rem" },
474
+ workspaceRow: {
475
+ padding: "0.65rem 0.75rem",
476
+ border: "1px solid var(--border)",
477
+ borderRadius: 9,
478
+ backgroundColor: "var(--panel-2)",
479
+ display: "grid",
480
+ gap: "0.25rem",
481
+ },
482
+ tabList: {
483
+ display: "flex",
484
+ gap: "1.25rem",
485
+ marginTop: "0.75rem",
486
+ padding: "0 0.25rem",
487
+ borderBottomWidth: 1,
488
+ borderBottomStyle: "solid",
489
+ borderBottomColor: "var(--border)",
490
+ overflowX: "auto",
491
+ overflowY: "hidden",
492
+ },
493
+ tab: {
494
+ flex: "0 0 auto",
495
+ minHeight: "2.35rem",
496
+ marginBottom: -1,
497
+ padding: "0.7rem 0.15rem 0.65rem",
498
+ borderBottomWidth: 2,
499
+ borderBottomColor: "transparent",
500
+ borderRadius: 0,
501
+ backgroundColor: "transparent",
502
+ color: "var(--muted)",
503
+ fontSize: "0.8rem",
504
+ fontWeight: 680,
505
+ cursor: "pointer",
506
+ whiteSpace: "nowrap",
507
+ },
508
+ tabActive: {
509
+ color: "var(--text)",
510
+ borderBottomColor: "var(--accent)",
511
+ },
512
+ tabPanel: { marginTop: "0.7rem" },
513
+ tabSection: { display: "grid", gap: "1rem" },
514
+ historyList: { display: "grid", gap: "0.65rem", marginTop: "1rem" },
515
+ historyButton: {
516
+ width: "100%",
517
+ padding: "0.65rem 0.8rem",
518
+ borderWidth: 1,
519
+ borderStyle: "solid",
520
+ borderColor: { default: "var(--border)", ":hover": "var(--border-strong)" },
521
+ borderRadius: 10,
522
+ backgroundColor: { default: "var(--panel-2)", ":hover": "var(--panel-3)" },
523
+ color: "var(--text)",
524
+ cursor: "pointer",
525
+ display: "flex",
526
+ alignItems: "center",
527
+ justifyContent: "space-between",
528
+ gap: "1rem",
529
+ textAlign: "left",
530
+ },
531
+ historyIdentity: { display: "grid", gap: "0.2rem", minWidth: 0 },
532
+ historyDate: { color: "var(--muted)", fontSize: "0.78rem" },
533
+ historyId: {
534
+ color: "var(--subtle)",
535
+ fontSize: "0.72rem",
536
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
537
+ },
538
+ sectionHeading: {
539
+ display: "flex",
540
+ alignItems: "flex-end",
541
+ justifyContent: "space-between",
542
+ gap: "1rem",
543
+ flexWrap: "wrap",
544
+ },
545
+ quietHeader: {
546
+ display: "flex",
547
+ justifyContent: "flex-end",
548
+ marginBottom: "0.75rem",
549
+ },
550
+ statusPanel: {
551
+ display: "grid",
552
+ gap: "0.85rem",
553
+ },
554
+ runControls: { display: "flex", justifyContent: "flex-end" },
555
+ row: { display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: "1rem" },
556
+ attemptActions: { display: "flex", alignItems: "center", gap: "0.55rem", flex: "none" },
557
+ copyFailureButton: {
558
+ minHeight: "1.75rem",
559
+ padding: "0.3rem 0.55rem",
560
+ borderWidth: 1,
561
+ borderStyle: "solid",
562
+ borderColor: "var(--border)",
563
+ borderRadius: 7,
564
+ backgroundColor: { default: "var(--panel-2)", ":hover": "var(--panel-3)" },
565
+ color: "var(--text)",
566
+ fontSize: "0.68rem",
567
+ fontWeight: 680,
568
+ cursor: "pointer",
569
+ },
570
+ attemptCard: {
571
+ border: "1px solid var(--border)",
572
+ borderRadius: 12,
573
+ backgroundColor: "var(--panel)",
574
+ padding: "0.85rem",
575
+ display: "grid",
576
+ gap: "0.7rem",
577
+ },
578
+ attemptTitle: { fontSize: "0.84rem", lineHeight: 1.4 },
579
+ resultPanel: {
580
+ display: "grid",
581
+ gap: "0.55rem",
582
+ padding: "0.75rem",
583
+ borderRadius: 10,
584
+ backgroundColor: "var(--panel-2)",
585
+ border: "1px solid var(--border)",
586
+ },
587
+ contentHeading: { margin: 0, fontSize: "0.79rem", color: "var(--text)" },
588
+ resultOutput: {
589
+ margin: 0,
590
+ whiteSpace: "pre-wrap",
591
+ wordBreak: "break-word",
592
+ fontSize: "0.82rem",
593
+ lineHeight: 1.6,
594
+ color: "var(--text)",
595
+ },
596
+ assertionCard: {
597
+ display: "grid",
598
+ gap: "0.4rem",
599
+ marginTop: "-0.1rem",
600
+ marginLeft: "1.5rem",
601
+ padding: "0.15rem 0 0.15rem 0.75rem",
602
+ borderLeftWidth: 2,
603
+ borderLeftStyle: "solid",
604
+ borderLeftColor: "var(--fail)",
605
+ },
606
+ assertionTitle: { color: "var(--fail)", fontSize: "0.74rem" },
607
+ assertionValues: {
608
+ display: "grid",
609
+ gap: "0.35rem",
610
+ margin: 0,
611
+ },
612
+ assertionValue: {
613
+ display: "grid",
614
+ gridTemplateColumns: "5rem minmax(0, 1fr)",
615
+ alignItems: "baseline",
616
+ gap: "0.65rem",
617
+ },
618
+ assertionLabel: {
619
+ color: "var(--subtle)",
620
+ fontSize: "0.65rem",
621
+ fontWeight: 750,
622
+ letterSpacing: "0.05em",
623
+ textTransform: "uppercase",
624
+ },
625
+ assertionCode: {
626
+ margin: 0,
627
+ whiteSpace: "pre-wrap",
628
+ wordBreak: "break-word",
629
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
630
+ fontSize: "0.75rem",
631
+ lineHeight: 1.5,
632
+ color: "var(--text)",
633
+ },
634
+ metricGrid: {
635
+ display: "grid",
636
+ gridTemplateColumns: "repeat(auto-fit, minmax(6rem, 1fr))",
637
+ gap: "0.4rem",
638
+ },
639
+ metric: {
640
+ display: "grid",
641
+ gap: "0.15rem",
642
+ padding: "0.5rem 0.6rem",
643
+ borderRadius: 8,
644
+ backgroundColor: "var(--bg)",
645
+ border: "1px solid var(--border)",
646
+ },
647
+ metricValue: { color: "var(--text)", fontSize: "0.77rem", fontWeight: 700 },
648
+ conversation: {
649
+ display: "grid",
650
+ gap: "0.55rem",
651
+ padding: "0.75rem",
652
+ border: "1px solid var(--border)",
653
+ borderRadius: 10,
654
+ backgroundColor: "var(--bg)",
655
+ },
656
+ conversationSwitcher: {
657
+ display: "flex",
658
+ alignItems: "center",
659
+ gap: "0.35rem",
660
+ padding: "0 0.15rem",
661
+ },
662
+ conversationHeader: {
663
+ display: "flex",
664
+ alignItems: "center",
665
+ justifyContent: "space-between",
666
+ gap: "0.75rem",
667
+ },
668
+ runTabs: { display: "inline-flex", alignItems: "center", gap: "0.12rem" },
669
+ runTab: {
670
+ padding: "0.12rem 0.3rem",
671
+ borderRadius: 4,
672
+ backgroundColor: { default: "transparent", ":hover": "var(--panel-3)" },
673
+ color: "var(--subtle)",
674
+ fontSize: "0.5rem",
675
+ fontWeight: 750,
676
+ letterSpacing: "0.04em",
677
+ textTransform: "uppercase",
678
+ cursor: "pointer",
679
+ },
680
+ runTabActive: { backgroundColor: "var(--accent-soft)", color: "var(--accent)" },
681
+ conversationTabs: { display: "flex", flexWrap: "wrap", gap: "0.25rem" },
682
+ conversationTab: {
683
+ display: "inline-flex",
684
+ alignItems: "center",
685
+ gap: "0.2rem",
686
+ boxSizing: "border-box",
687
+ height: "1.1rem",
688
+ minHeight: 0,
689
+ lineHeight: 1,
690
+ padding: "0.08rem 0.32rem",
691
+ fontSize: "0.5rem",
692
+ fontWeight: 750,
693
+ letterSpacing: "0.04em",
694
+ textTransform: "uppercase",
695
+ borderColor: "var(--border)",
696
+ backgroundColor: { default: "transparent", ":hover": "var(--panel-3)" },
697
+ color: "var(--muted)",
698
+ cursor: "pointer",
699
+ },
700
+ conversationTabActive: {
701
+ borderColor: "var(--pass)",
702
+ backgroundColor: "var(--pass-soft)",
703
+ color: "var(--pass)",
704
+ },
705
+ conversationTabDot: {
706
+ width: "0.28rem",
707
+ height: "0.28rem",
708
+ borderRadius: 999,
709
+ backgroundColor: "var(--skip)",
710
+ animationName: runningPulse,
711
+ animationDuration: {
712
+ default: "1.2s",
713
+ "@media (prefers-reduced-motion: reduce)": "0.01ms",
714
+ },
715
+ animationIterationCount: {
716
+ default: "infinite",
717
+ "@media (prefers-reduced-motion: reduce)": 1,
718
+ },
719
+ animationTimingFunction: "ease-in-out",
720
+ },
721
+ conversationThread: { display: "grid", gap: "0.55rem" },
722
+ runningIndicator: {
723
+ display: "inline-flex",
724
+ alignItems: "baseline",
725
+ justifySelf: "start",
726
+ gap: "0.35rem",
727
+ padding: "0.48rem 0.65rem",
728
+ border: "1px solid var(--border)",
729
+ borderRadius: 999,
730
+ backgroundColor: "var(--panel-2)",
731
+ color: "var(--muted)",
732
+ fontSize: "0.74rem",
733
+ fontWeight: 650,
734
+ },
735
+ runningDots: { display: "inline-flex", gap: "0.15rem", color: "var(--accent)" },
736
+ runningDot: {
737
+ animationName: runningPulse,
738
+ animationDuration: {
739
+ default: "1.2s",
740
+ "@media (prefers-reduced-motion: reduce)": "0.01ms",
741
+ },
742
+ animationIterationCount: {
743
+ default: "infinite",
744
+ "@media (prefers-reduced-motion: reduce)": 1,
745
+ },
746
+ animationTimingFunction: "ease-in-out",
747
+ },
748
+ runningDotSecond: { animationDelay: "0.16s" },
749
+ runningDotThird: { animationDelay: "0.32s" },
750
+ message: {
751
+ display: "grid",
752
+ gap: "0.28rem",
753
+ padding: "0.65rem 0.75rem",
754
+ borderRadius: 10,
755
+ border: "1px solid var(--border)",
756
+ backgroundColor: "var(--panel-2)",
757
+ maxWidth: "78%",
758
+ },
759
+ messageUser: {
760
+ justifySelf: "end",
761
+ backgroundColor: "var(--accent-soft)",
762
+ borderColor: "oklch(0.75 0.12 175 / 0.3)",
763
+ },
764
+ messageAssistant: { justifySelf: "start", backgroundColor: "var(--panel-2)" },
765
+ messageJudge: {
766
+ justifySelf: "start",
767
+ backgroundColor: "var(--accent-soft)",
768
+ borderColor: "oklch(0.75 0.12 175 / 0.3)",
769
+ },
770
+ messageRole: {
771
+ color: "var(--subtle)",
772
+ fontSize: "0.61rem",
773
+ fontWeight: 750,
774
+ letterSpacing: "0.06em",
775
+ textTransform: "uppercase",
776
+ },
777
+ messageContent: { margin: 0, color: "var(--text)", fontSize: "0.79rem", lineHeight: 1.5 },
778
+ judgeResponse: {
779
+ display: "grid",
780
+ justifySelf: "start",
781
+ gap: "0.4rem",
782
+ padding: "0.65rem 0.7rem",
783
+ border: "1px solid var(--border)",
784
+ borderRadius: 10,
785
+ backgroundColor: "var(--panel-2)",
786
+ maxWidth: "78%",
787
+ },
788
+ judgeResponseHeading: {
789
+ margin: 0,
790
+ color: "var(--subtle)",
791
+ fontSize: "0.61rem",
792
+ fontWeight: 750,
793
+ letterSpacing: "0.06em",
794
+ textTransform: "uppercase",
795
+ },
796
+ judgeOutcomeList: { display: "grid", gap: "0.25rem" },
797
+ judgeOutcome: {
798
+ display: "grid",
799
+ gridTemplateColumns: "0.9rem minmax(0, 1fr)",
800
+ gap: "0.15rem 0.6rem",
801
+ },
802
+ judgeOutcomeLabel: { color: "var(--text)", fontSize: "0.75rem", lineHeight: 1.35 },
803
+ judgeOutcomeExplanation: {
804
+ gridColumn: 2,
805
+ margin: 0,
806
+ color: "var(--muted)",
807
+ fontSize: "0.75rem",
808
+ lineHeight: 1.5,
809
+ },
810
+ toolEvent: {
811
+ display: "grid",
812
+ gridTemplateColumns: "1.5rem minmax(0, 1fr) max-content",
813
+ alignItems: "center",
814
+ gap: "0.55rem",
815
+ width: "min(86%, 46rem)",
816
+ padding: "0.5rem 0.65rem",
817
+ borderRadius: 8,
818
+ border: "1px solid var(--border)",
819
+ backgroundColor: "var(--panel)",
820
+ },
821
+ toolIcon: {
822
+ width: "1.5rem",
823
+ height: "1.5rem",
824
+ display: "grid",
825
+ placeItems: "center",
826
+ borderRadius: 6,
827
+ backgroundColor: "var(--panel-3)",
828
+ color: "var(--accent)",
829
+ fontSize: "0.7rem",
830
+ },
831
+ toolCopy: { display: "grid", gap: "0.08rem", minWidth: 0 },
832
+ toolTitle: { color: "var(--text)", fontSize: "0.74rem", fontWeight: 680 },
833
+ toolDetail: {
834
+ color: "var(--muted)",
835
+ fontSize: "0.69rem",
836
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
837
+ overflow: "hidden",
838
+ textOverflow: "ellipsis",
839
+ whiteSpace: "nowrap",
840
+ },
841
+ toolOutcome: { color: "var(--pass)", fontSize: "0.64rem", fontWeight: 700 },
842
+ toolOutcomeFail: { color: "var(--fail)" },
843
+ toolActions: {
844
+ display: "flex",
845
+ alignItems: "center",
846
+ justifyContent: "flex-end",
847
+ gap: "0.45rem",
848
+ },
849
+ toolResultSummary: {
850
+ padding: "0.14rem 0.3rem",
851
+ borderRadius: 4,
852
+ backgroundColor: { default: "transparent", ":hover": "var(--accent-soft)" },
853
+ color: { default: "var(--accent)", ":hover": "var(--accent)" },
854
+ cursor: "pointer",
855
+ fontSize: "0.66rem",
856
+ fontWeight: 700,
857
+ whiteSpace: "nowrap",
858
+ },
859
+ toolResultPre: {
860
+ gridColumn: "2 / -1",
861
+ margin: 0,
862
+ paddingTop: "0.4rem",
863
+ borderTop: "1px solid var(--border)",
864
+ maxHeight: "12rem",
865
+ overflow: "auto",
866
+ whiteSpace: "pre-wrap",
867
+ wordBreak: "break-word",
868
+ fontSize: "0.66rem",
869
+ lineHeight: 1.45,
870
+ color: "var(--muted)",
871
+ },
872
+ criteriaPanel: {
873
+ display: "grid",
874
+ gap: "0.55rem",
875
+ padding: "0.75rem 0.9rem",
876
+ borderBottom: "1px solid var(--border)",
877
+ },
878
+ criteriaList: { display: "grid", gap: "0.55rem", margin: 0, padding: 0, listStyle: "none" },
879
+ criterion: { display: "flex", gap: "0.6rem", color: "var(--muted)", fontSize: "0.82rem" },
880
+ criterionIcon: { color: "var(--accent)", fontWeight: 800 },
881
+ passReasonList: { display: "grid", gap: "0.35rem", margin: 0, padding: 0, listStyle: "none" },
882
+ passReason: { display: "flex", gap: "0.5rem", color: "var(--text)", fontSize: "0.76rem" },
883
+ passReasonIcon: { color: "var(--pass)", fontWeight: 800 },
884
+ criterionResults: { display: "grid" },
885
+ criterionResultList: {
886
+ display: "grid",
887
+ gap: "0.55rem",
888
+ margin: 0,
889
+ padding: 0,
890
+ listStyle: "none",
891
+ },
892
+ criterionResult: {
893
+ display: "grid",
894
+ gap: "0.45rem",
895
+ },
896
+ criterionResultHeader: {
897
+ display: "flex",
898
+ alignItems: "flex-start",
899
+ gap: "0.6rem",
900
+ color: "var(--muted)",
901
+ fontSize: "0.82rem",
902
+ },
903
+ criterionExplanation: {
904
+ margin: "0 0 0 1.5rem",
905
+ color: "var(--subtle)",
906
+ fontSize: "0.75rem",
907
+ lineHeight: 1.45,
908
+ },
909
+ criterionOutcome: {
910
+ display: "inline-flex",
911
+ justifyContent: "center",
912
+ width: "0.9rem",
913
+ flex: "0 0 0.9rem",
914
+ fontSize: "0.8rem",
915
+ fontWeight: 800,
916
+ lineHeight: 1.25,
917
+ },
918
+ criterionOutcomePass: { color: "var(--pass)" },
919
+ criterionOutcomeFail: { color: "var(--fail)" },
920
+ criterionOutcomePending: { color: "var(--skip)" },
921
+ criterionOutcomeUnknown: { color: "var(--subtle)" },
922
+ status: {
923
+ fontSize: "0.68rem",
924
+ fontWeight: 750,
925
+ letterSpacing: "0.06em",
926
+ textTransform: "uppercase",
927
+ padding: "0.2rem 0.55rem",
928
+ borderRadius: 999,
929
+ border: "1px solid var(--border)",
930
+ color: "var(--muted)",
931
+ },
932
+ statusPass: {
933
+ color: "var(--pass)",
934
+ borderColor: "var(--pass)",
935
+ backgroundColor: "var(--pass-soft)",
936
+ },
937
+ statusFail: {
938
+ color: "var(--fail)",
939
+ borderColor: "var(--fail)",
940
+ backgroundColor: "var(--fail-soft)",
941
+ },
942
+ statusRunning: {
943
+ color: "var(--skip)",
944
+ borderColor: "var(--skip)",
945
+ backgroundColor: "var(--skip-soft)",
946
+ },
947
+ error: {
948
+ margin: 0,
949
+ padding: "0.85rem 1rem",
950
+ border: "1px solid oklch(0.73 0.18 25 / 0.36)",
951
+ borderRadius: 9,
952
+ backgroundColor: "var(--fail-soft)",
953
+ color: "oklch(0.88 0.08 25)",
954
+ },
955
+ evidence: { borderTop: "1px solid var(--border)", paddingTop: "0.7rem" },
956
+ evidenceSummary: {
957
+ display: "flex",
958
+ alignItems: "center",
959
+ gap: "0.5rem",
960
+ cursor: "pointer",
961
+ color: "var(--muted)",
962
+ fontSize: "0.82rem",
963
+ fontWeight: 650,
964
+ padding: "0.2rem 0",
965
+ },
966
+ pre: {
967
+ margin: "0.7rem 0 0",
968
+ overflow: "auto",
969
+ whiteSpace: "pre-wrap",
970
+ wordBreak: "break-word",
971
+ fontSize: "0.76rem",
972
+ lineHeight: 1.55,
973
+ fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace",
974
+ color: "oklch(0.86 0.02 255)",
975
+ backgroundColor: "var(--bg)",
976
+ border: "1px solid var(--border)",
977
+ borderRadius: 9,
978
+ padding: "0.85rem",
979
+ },
980
+ empty: { color: "var(--muted)", fontStyle: "italic", padding: "1rem 0" },
981
+ });
982
+ function ViewerLayout() {
983
+ const [sidebarOpen, setSidebarOpen] = useState(true);
984
+ const [workers, setWorkers] = useState(1);
985
+ return (_jsx(WorkerContext.Provider, { value: { workers, setWorkers }, children: _jsxs("div", { ...stylex.props(styles.shell, !sidebarOpen && styles.shellCollapsed), children: [_jsx("a", { href: "#viewer-main", ...stylex.props(styles.skipLink), children: "Skip to content" }), _jsx(ViewerSidebar, { open: sidebarOpen, onToggle: () => setSidebarOpen((open) => !open) }), _jsx("main", { id: "viewer-main", tabIndex: -1, ...stylex.props(styles.main), children: _jsx(Outlet, {}) })] }) }));
986
+ }
987
+ function useCatalog() {
988
+ return useQuery({ queryKey: ["test-catalog"], queryFn: fetchTestCatalog });
989
+ }
990
+ function ViewerSidebar({ open, onToggle }) {
991
+ const catalog = useCatalog();
992
+ const history = useExecutionHistory();
993
+ const groups = groupTests(catalog.data?.tests ?? []);
994
+ const statuses = latestTestStatuses(history.data ?? []);
995
+ return (_jsxs("aside", { ...stylex.props(styles.sidebar, !open && styles.sidebarCollapsed), children: [_jsx(SidebarHeader, { open: open, count: catalog.data?.tests.length ?? 0, onToggle: onToggle }), open ? (_jsx(SidebarNavigation, { groups: groups, statuses: statuses, error: catalog.isError })) : null] }));
996
+ }
997
+ function SidebarHeader({ open, count, onToggle, }) {
998
+ const { workers } = useContext(WorkerContext);
999
+ const navigate = useNavigate();
1000
+ const client = useQueryClient();
1001
+ const run = useMutation({
1002
+ mutationFn: () => startSuite(workers),
1003
+ onSuccess: ({ executionId }) => {
1004
+ void client.invalidateQueries({ queryKey: ["execution-history"] });
1005
+ void navigate({ to: "/executions/$executionId", params: { executionId } });
1006
+ },
1007
+ });
1008
+ return (_jsx("header", { ...stylex.props(styles.sidebarHeader, !open && styles.sidebarHeaderCollapsed), children: open ? (_jsxs(_Fragment, { children: [_jsxs("div", { ...stylex.props(styles.sidebarTitleRow), children: [_jsxs("div", { ...stylex.props(styles.sidebarTitleIdentity), children: [_jsx("h1", { ...stylex.props(styles.title, styles.sidebarTitle), children: "Tests" }), _jsx("span", { ...stylex.props(styles.countBadge), children: count })] }), _jsx(SidebarToggle, { open: open, onToggle: onToggle })] }), _jsxs("div", { ...stylex.props(styles.suiteControls), children: [_jsxs("button", { type: "button", ...stylex.props(styles.buttonReset, styles.suiteRunButton), onClick: () => run.mutate(), disabled: run.isPending || count === 0, children: [_jsx("span", { "aria-hidden": "true", children: run.isPending ? "●" : "▶" }), run.isPending ? "Starting suite…" : "Run all tests"] }), _jsx(WorkerControl, {})] }), run.isError ? _jsx("p", { role: "alert", children: run.error.message }) : null] })) : (_jsx(SidebarToggle, { open: open, onToggle: onToggle })) }));
1009
+ }
1010
+ function WorkerControl() {
1011
+ const { workers, setWorkers } = useContext(WorkerContext);
1012
+ return (_jsxs("label", { ...stylex.props(styles.workerControl), children: [_jsx("span", { children: "Workers" }), _jsx("input", { type: "number", "aria-label": "Concurrent workers", min: 1, max: 32, value: workers, ...stylex.props(styles.workerInput), onChange: (event) => {
1013
+ const next = Number(event.currentTarget.value);
1014
+ if (Number.isInteger(next))
1015
+ setWorkers(Math.min(32, Math.max(1, next)));
1016
+ } })] }));
1017
+ }
1018
+ function SidebarToggle({ open, onToggle }) {
1019
+ return (_jsx("button", { type: "button", "aria-controls": "test-navigation", "aria-expanded": open, "aria-label": open ? "Collapse test sidebar" : "Expand test sidebar", ...stylex.props(styles.buttonReset, styles.toggleButton), onClick: onToggle, children: open ? "←" : "→" }));
1020
+ }
1021
+ function SidebarNavigation({ groups, statuses, error, }) {
1022
+ return (_jsxs(_Fragment, { children: [error ? _jsx("p", { role: "alert", children: "Test discovery is unavailable." }) : null, _jsx("nav", { id: "test-navigation", "aria-label": "Tests", ...stylex.props(styles.navigation), children: [...groups].map(([name, tests]) => (_jsxs("section", { "aria-label": `${name} tests`, ...stylex.props(styles.navSection), children: [_jsxs("div", { ...stylex.props(styles.groupHeader), children: [_jsx("strong", { ...stylex.props(styles.groupLabel), children: name }), _jsxs("div", { ...stylex.props(styles.groupHeaderActions), children: [_jsx("span", { ...stylex.props(styles.groupCount), children: tests.length }), _jsx(RunTestGroupButton, { name: name, tests: tests })] })] }), tests.map((test) => (_jsx(TestLink, { test: test, status: statuses.get(test.id) }, test.id)))] }, name))) })] }));
1023
+ }
1024
+ function RunTestGroupButton({ name, tests }) {
1025
+ const { workers } = useContext(WorkerContext);
1026
+ const navigate = useNavigate();
1027
+ const client = useQueryClient();
1028
+ const run = useMutation({
1029
+ mutationFn: () => startTestGroup(tests.map((test) => test.id), workers),
1030
+ onSuccess: ({ executionId }) => {
1031
+ void client.invalidateQueries({ queryKey: ["execution-history"] });
1032
+ void navigate({ to: "/executions/$executionId", params: { executionId } });
1033
+ },
1034
+ });
1035
+ return (_jsx("button", { type: "button", "aria-label": `Run ${name} suite`, title: `Run ${name} suite`, ...stylex.props(styles.buttonReset, styles.groupRunButton), onClick: () => run.mutate(), disabled: run.isPending, children: run.isPending ? "●" : "▶" }));
1036
+ }
1037
+ function TestLink({ test, status }) {
1038
+ return (_jsxs(Link, { to: "/tests/$testId", params: { testId: test.id }, search: {}, ...stylex.props(styles.navLink), activeProps: stylex.props(styles.navLink, styles.active), children: [_jsxs("div", { ...stylex.props(styles.navItemHeader), children: [status ? _jsx(TestStatus, { status: status }) : _jsx("span", { "aria-hidden": "true" }), _jsx("span", { ...stylex.props(styles.navItemTitle), children: test.title.at(-1) })] }), test.project !== "default" ? _jsx("div", { ...stylex.props(styles.meta), children: test.project }) : null] }));
1039
+ }
1040
+ function TestStatus({ status }) {
1041
+ return (_jsx("span", { role: "img", "aria-label": `Latest execution: ${status}`, title: `Latest execution: ${status}`, ...stylex.props(styles.navStatus), children: _jsx("span", { "aria-hidden": "true", ...stylex.props(styles.navStatusDot, status === "passed" && styles.navStatusDotPass, status === "failed" && styles.navStatusDotFail, status === "running" && styles.navStatusDotRunning) }) }));
1042
+ }
1043
+ function TestCatalogPage() {
1044
+ return (_jsxs("section", { ...stylex.props(styles.hero), children: [_jsx("div", { ...stylex.props(styles.brand), children: "Test explorer" }), _jsx("h2", { ...stylex.props(styles.title), children: "Choose a test from the sidebar" }), _jsx("p", { ...stylex.props(styles.description), children: "Read what it checks, see its agents and judges, then start a run or inspect a saved execution." })] }));
1045
+ }
1046
+ function TestPage() {
1047
+ const { testId } = testRoute.useParams();
1048
+ const catalog = useCatalog();
1049
+ if (catalog.isPending)
1050
+ return _jsx("p", { children: "Loading test\u2026" });
1051
+ const test = catalog.data?.tests.find((item) => item.id === testId);
1052
+ if (!test)
1053
+ return (_jsx("p", { role: "alert", children: "This test is no longer available. Choose another test in the sidebar." }));
1054
+ return _jsx(TestDetail, { test: test }, test.id);
1055
+ }
1056
+ function TestDetail({ test }) {
1057
+ const { execution, view } = testRoute.useSearch();
1058
+ const history = useExecutionHistory();
1059
+ const navigate = useNavigate();
1060
+ const runs = history.data?.filter((item) => item.testIds?.includes(test.id)) ?? [];
1061
+ const selected = execution ?? runs[0]?.id;
1062
+ const activeView = view ?? "current";
1063
+ const chooseExecution = (id) => void navigate({
1064
+ to: "/tests/$testId",
1065
+ params: { testId: test.id },
1066
+ search: { execution: id },
1067
+ });
1068
+ const chooseView = (next) => void navigate({
1069
+ to: "/tests/$testId",
1070
+ params: { testId: test.id },
1071
+ search: { execution, view: next === "current" ? undefined : next },
1072
+ });
1073
+ return (_jsxs(_Fragment, { children: [_jsx(TestHeader, { test: test, onStarted: chooseExecution }), _jsx(TestTabs, { active: activeView, onChange: chooseView }), _jsx(TestViewPanel, { view: activeView, test: test, runs: runs, selected: selected, onChooseExecution: chooseExecution })] }));
1074
+ }
1075
+ function TestHeader({ test, onStarted }) {
1076
+ return (_jsxs("header", { ...stylex.props(styles.hero), children: [_jsxs("div", { ...stylex.props(styles.heroTop), children: [_jsxs("div", { ...stylex.props(styles.heroCopy), children: [_jsx("div", { ...stylex.props(styles.brand), children: test.title.slice(0, -1).join(" / ") }), _jsx("h2", { ...stylex.props(styles.title), children: test.title.at(-1) }), _jsx("p", { ...stylex.props(styles.description), children: test.description ?? "This test has no additional description." })] }), _jsx(RunTestButton, { test: test, onStarted: onStarted })] }), _jsxs("div", { ...stylex.props(styles.path), children: [test.project, " \u00B7 ", test.file] })] }));
1077
+ }
1078
+ const TEST_VIEWS = [
1079
+ { id: "current", label: "Current run" },
1080
+ { id: "setup", label: "Test setup" },
1081
+ { id: "history", label: "Run history" },
1082
+ ];
1083
+ function TestTabs({ active, onChange }) {
1084
+ return (_jsx("div", { role: "tablist", "aria-label": "Test views", ...stylex.props(styles.tabList), children: TEST_VIEWS.map((view) => (_jsx("button", { id: `test-tab-${view.id}`, type: "button", role: "tab", "aria-controls": `test-panel-${view.id}`, "aria-selected": active === view.id, tabIndex: active === view.id ? 0 : -1, ...stylex.props(styles.buttonReset, styles.tab, active === view.id && styles.tabActive), onClick: () => onChange(view.id), onKeyDown: (event) => handleTabKeyDown(event, view.id, onChange), children: view.label }, view.id))) }));
1085
+ }
1086
+ function handleTabKeyDown(event, active, onChange) {
1087
+ if (!["ArrowLeft", "ArrowRight", "Home", "End"].includes(event.key))
1088
+ return;
1089
+ event.preventDefault();
1090
+ const index = TEST_VIEWS.findIndex((view) => view.id === active);
1091
+ const nextIndex = event.key === "Home"
1092
+ ? 0
1093
+ : event.key === "End"
1094
+ ? TEST_VIEWS.length - 1
1095
+ : (index + (event.key === "ArrowRight" ? 1 : -1) + TEST_VIEWS.length) % TEST_VIEWS.length;
1096
+ const next = TEST_VIEWS[nextIndex];
1097
+ if (!next)
1098
+ return;
1099
+ onChange(next.id);
1100
+ document.getElementById(`test-tab-${next.id}`)?.focus();
1101
+ }
1102
+ function TestViewPanel(props) {
1103
+ return (_jsxs("div", { id: `test-panel-${props.view}`, role: "tabpanel", "aria-labelledby": `test-tab-${props.view}`, ...stylex.props(styles.tabPanel), children: [props.view === "setup" ? _jsx(TestResources, { test: props.test }) : null, props.view === "current" ? (_jsx(CurrentRun, { test: props.test, executionId: props.selected })) : null, props.view === "history" ? (_jsx(RunHistory, { runs: props.runs, onChoose: props.onChooseExecution })) : null] }));
1104
+ }
1105
+ function CurrentRun({ test, executionId }) {
1106
+ return (_jsx("section", { ...stylex.props(styles.tabSection), children: executionId ? (_jsx(TestExecution, { id: executionId, test: test })) : (_jsx("p", { ...stylex.props(styles.empty), children: "No runs yet. Start this test to see its progress here." })) }));
1107
+ }
1108
+ function RunHistory({ runs, onChoose, }) {
1109
+ return (_jsxs("section", { ...stylex.props(styles.tabSection), children: [_jsx("div", { ...stylex.props(styles.quietHeader), children: _jsxs("span", { ...stylex.props(styles.resourceCount), children: [runs.length, " executions"] }) }), runs.length ? (_jsx("div", { ...stylex.props(styles.historyList), children: runs.map((run) => (_jsx(HistoryItem, { run: run, onChoose: onChoose }, run.id))) })) : (_jsx("p", { ...stylex.props(styles.empty), children: "No saved runs for this test." }))] }));
1110
+ }
1111
+ function HistoryItem({ run, onChoose }) {
1112
+ return (_jsxs("button", { type: "button", "aria-label": `Open ${run.status} execution ${run.id.slice(0, 8)}`, ...stylex.props(styles.buttonReset, styles.historyButton), onClick: () => onChoose(run.id), children: [_jsxs("span", { ...stylex.props(styles.historyIdentity), children: [_jsx("span", { ...stylex.props(styles.historyDate), children: new Date(run.startedAt).toLocaleString() }), _jsx("span", { ...stylex.props(styles.historyId), children: run.id.slice(0, 8) })] }), _jsx("span", { ...stylex.props(styles.status, run.status === "passed" && styles.statusPass, run.status === "failed" && styles.statusFail, run.status === "running" && styles.statusRunning), children: run.status })] }));
1113
+ }
1114
+ function RunTestButton({ test, onStarted }) {
1115
+ const { workers } = useContext(WorkerContext);
1116
+ const client = useQueryClient();
1117
+ const run = useMutation({
1118
+ mutationFn: () => startTest(test.id, workers),
1119
+ onSuccess: ({ executionId }) => {
1120
+ onStarted(executionId);
1121
+ void client.invalidateQueries({ queryKey: ["execution-history"] });
1122
+ },
1123
+ });
1124
+ return (_jsxs("div", { ...stylex.props(styles.heroAction), children: [_jsxs("button", { type: "button", ...stylex.props(styles.buttonReset, styles.button), onClick: () => run.mutate(), disabled: run.isPending, children: [_jsx("span", { "aria-hidden": "true", ...stylex.props(styles.buttonIcon), children: run.isPending ? "●" : "▶" }), run.isPending ? "Starting…" : "Run this test"] }), run.isError ? _jsx("p", { role: "alert", children: run.error.message }) : null] }));
1125
+ }
1126
+ function TestResources({ test }) {
1127
+ const resources = test.resources ?? [];
1128
+ const agents = resources.filter((resource) => resource.kind === "agent");
1129
+ const judges = resources.filter((resource) => resource.kind === "judge");
1130
+ return (_jsxs("section", { "aria-label": "Test setup details", ...stylex.props(styles.contextPanel), children: [_jsx(CriteriaSetup, { test: test }), _jsxs("div", { ...stylex.props(styles.setupBody), children: [_jsx(ResourceSection, { title: "Agents", description: "Task agents this test can start.", resources: agents }), _jsx(ResourceSection, { title: "Judges", description: "Reviewers that evaluate agent output.", resources: judges }), _jsx(WorkspaceSetup, { test: test })] })] }));
1131
+ }
1132
+ function CriteriaSetup({ test }) {
1133
+ const criteria = testCriteria(test);
1134
+ return (_jsxs("section", { "aria-labelledby": "setup-criteria", ...stylex.props(styles.criteriaPanel), children: [_jsx("h3", { id: "setup-criteria", ...stylex.props(styles.contentHeading), children: "Pass criteria" }), criteria.length ? (_jsx("ul", { ...stylex.props(styles.criteriaList), children: criteria.map((criterion) => (_jsxs("li", { ...stylex.props(styles.criterion), children: [_jsx("span", { "aria-hidden": "true", ...stylex.props(styles.criterionIcon), children: "\u2713" }), _jsx("span", { children: criterion })] }, criterion))) })) : (_jsx("p", { ...stylex.props(styles.meta), children: "No explicit pass criteria are declared." }))] }));
1135
+ }
1136
+ function ResourceSection({ title, description, resources, }) {
1137
+ const id = `setup-${title.toLowerCase()}`;
1138
+ const noun = title === "Agents" ? "agent" : "judge";
1139
+ return (_jsxs("section", { "aria-labelledby": id, ...stylex.props(styles.setupSection), children: [_jsxs("header", { ...stylex.props(styles.setupSectionHeader), children: [_jsxs("div", { ...stylex.props(styles.setupSectionCopy), children: [_jsx("h3", { id: id, ...stylex.props(styles.contentHeading), children: title }), _jsx("p", { ...stylex.props(styles.meta), children: description })] }), _jsxs("span", { ...stylex.props(styles.resourceCount), children: [resources.length, " ", pluralize(resources.length, noun)] })] }), resources.length ? (_jsx("div", { ...stylex.props(styles.resourceGrid), children: resources.map((resource) => (_jsx(ResourceCard, { resource: resource }, resource.name))) })) : (_jsx("p", { ...stylex.props(styles.meta), children: "None declared." }))] }));
1140
+ }
1141
+ function ResourceCard({ resource }) {
1142
+ return (_jsxs("article", { ...stylex.props(styles.card, styles.resourceCard), children: [_jsx("div", { ...stylex.props(styles.resourceHeader), children: _jsx("strong", { children: resource.name }) }), _jsx(ResourceContext, { resource: resource })] }));
1143
+ }
1144
+ function WorkspaceSetup({ test }) {
1145
+ return (_jsxs("section", { "aria-labelledby": "setup-workspace", ...stylex.props(styles.setupSection), children: [_jsxs("div", { ...stylex.props(styles.setupSectionCopy), children: [_jsx("h3", { id: "setup-workspace", ...stylex.props(styles.contentHeading), children: "Workspace" }), _jsx("p", { ...stylex.props(styles.meta), children: "Starting files and execution target for this test." })] }), _jsxs("div", { ...stylex.props(styles.workspaceRow), children: [_jsx(ResourceFact, { label: "Source folder", value: test.workspace ?? "Project directory" }), _jsx(ResourceFact, { label: "Project", value: test.project }), _jsx(ResourceFact, { label: "Test file", value: test.file })] })] }));
1146
+ }
1147
+ function testCriteria(test) {
1148
+ if (test.criteria?.length)
1149
+ return test.criteria;
1150
+ return test.description ? [test.description] : [];
1151
+ }
1152
+ function ResourceContext({ resource }) {
1153
+ return (_jsxs("div", { ...stylex.props(styles.resourceBody), children: [resource.description ? (_jsx("p", { ...stylex.props(styles.resourceDescription), children: resource.description })) : null, _jsxs("div", { ...stylex.props(styles.resourceFacts), children: [_jsx(ResourceFact, { label: "Host", value: resource.host ?? "Not configured" }), _jsx(ResourceFact, { label: "Model", value: resource.model ?? "Host default" }), resource.workspace ? _jsx(ResourceFact, { label: "Workspace", value: resource.workspace }) : null, resource.skills.length ? (_jsx(ResourceFact, { label: "Skills", value: resource.skills.join(", ") })) : null, resource.mcpServers.length ? (_jsx(ResourceFact, { label: "MCP", value: resource.mcpServers.join(", ") })) : null] }), resource.prompt ? (_jsxs("div", { ...stylex.props(styles.resourcePrompt), children: [_jsx("span", { ...stylex.props(styles.resourceFactLabel), children: "Prompt" }), _jsx("p", { ...stylex.props(styles.resourceFactValue), children: resource.prompt })] })) : null] }));
1154
+ }
1155
+ function ResourceFact({ label, value }) {
1156
+ return (_jsxs("div", { ...stylex.props(styles.resourceFact), children: [_jsx("span", { ...stylex.props(styles.resourceFactLabel), children: label }), _jsx("span", { ...stylex.props(styles.resourceFactValue), children: value })] }));
1157
+ }
1158
+ function TestExecution({ id, test }) {
1159
+ const detail = useQuery({
1160
+ queryKey: ["execution", id],
1161
+ queryFn: () => fetchExecution(id),
1162
+ });
1163
+ if (detail.isPending)
1164
+ return _jsx("p", { children: "Loading execution\u2026" });
1165
+ if (!detail.data)
1166
+ return _jsx("p", { role: "alert", children: "Execution is unavailable." });
1167
+ const attempts = detail.data.attempts.filter((attempt) => attempt.testId === test.id);
1168
+ if (detail.data.testIds && !detail.data.testIds.includes(test.id))
1169
+ return _jsx("p", { children: "This execution does not contain this test." });
1170
+ return (_jsx(ExecutionDetailView, { execution: { ...detail.data, attempts }, criteria: testCriteria(test) }));
1171
+ }
1172
+ function ExecutionPage() {
1173
+ const { executionId } = executionRoute.useParams();
1174
+ const detail = useQuery({
1175
+ queryKey: ["execution", executionId],
1176
+ queryFn: () => fetchExecution(executionId),
1177
+ });
1178
+ if (detail.isLoading)
1179
+ return _jsx("p", { ...stylex.props(styles.empty), children: "Loading execution\u2026" });
1180
+ if (detail.isError || !detail.data)
1181
+ return _jsx("p", { ...stylex.props(styles.empty), children: "Execution is unavailable." });
1182
+ return _jsx(ExecutionDetailView, { execution: detail.data });
1183
+ }
1184
+ function ExecutionDetailView({ execution, criteria = [], }) {
1185
+ const client = useQueryClient();
1186
+ const cancel = useMutation({
1187
+ mutationFn: () => cancelExecution(execution.id),
1188
+ onSuccess: () => client.invalidateQueries({ queryKey: ["execution", execution.id] }),
1189
+ });
1190
+ const stopping = execution.status === "running" && (cancel.isPending || cancel.isSuccess);
1191
+ const stopLabel = (execution.testIds?.length ?? 0) > 1 ? "Stop suite run" : "Stop this run";
1192
+ return (_jsxs("div", { ...stylex.props(styles.statusPanel), children: [execution.status === "running" ? (_jsx("div", { ...stylex.props(styles.runControls), children: _jsx("button", { type: "button", ...stylex.props(styles.buttonReset, styles.button, styles.secondaryButton), onClick: () => cancel.mutate(), disabled: stopping, children: stopping ? "Stopping…" : stopLabel }) })) : null, cancel.isError ? _jsx("p", { role: "alert", children: "The run could not be stopped." }) : null, _jsxs("section", { ...stylex.props(styles.list), children: [execution.attempts.map((attempt) => (_jsx(AttemptCard, { attempt: attempt, criteria: criteria }, attempt.id))), execution.attempts.length === 0 ? (_jsx("p", { ...stylex.props(styles.empty), children: emptyExecutionMessage(execution, stopping) })) : null] })] }));
1193
+ }
1194
+ function emptyExecutionMessage(execution, stopping) {
1195
+ if (stopping)
1196
+ return "Stopping this run…";
1197
+ if (execution.status === "interrupted")
1198
+ return "Run stopped before the first test started.";
1199
+ if (execution.status === "failed")
1200
+ return "Run failed before the first test started.";
1201
+ if (execution.status === "passed")
1202
+ return "Run completed without starting a test.";
1203
+ const count = execution.testIds?.length ?? 0;
1204
+ return count ? `Starting ${count} ${pluralize(count, "test")}…` : "Starting the test run…";
1205
+ }
1206
+ function ComparePage() {
1207
+ const { left, right } = compareRoute.useParams();
1208
+ const [first, second] = useQueries({
1209
+ queries: [left, right].map((id) => ({
1210
+ queryKey: ["execution", id],
1211
+ queryFn: () => fetchExecution(id),
1212
+ })),
1213
+ });
1214
+ if (first.isLoading || second.isLoading)
1215
+ return _jsx("p", { ...stylex.props(styles.empty), children: "Loading saved runs\u2026" });
1216
+ if (!first.data || !second.data)
1217
+ return _jsx("p", { ...stylex.props(styles.empty), children: "A selected execution is unavailable." });
1218
+ return (_jsxs(_Fragment, { children: [_jsx("div", { ...stylex.props(styles.brand), children: "Saved run comparison" }), _jsx("h2", { ...stylex.props(styles.title), children: "Two execution records" }), _jsxs("section", { ...stylex.props(styles.section), children: [_jsx(ComparisonColumn, { label: "First", execution: first.data }), _jsx(ComparisonColumn, { label: "Second", execution: second.data })] })] }));
1219
+ }
1220
+ function ComparisonColumn({ execution, label }) {
1221
+ return (_jsxs("article", { ...stylex.props(styles.card), children: [_jsxs("strong", { children: [label, ": ", execution.status] }), _jsx("p", { ...stylex.props(styles.meta), children: execution.id.slice(0, 8) }), execution.attempts.map((attempt) => (_jsx(AttemptCard, { attempt: attempt }, attempt.id)))] }));
1222
+ }
1223
+ function AttemptCard({ attempt, criteria = [] }) {
1224
+ const output = [...attempt.output.stdout, ...attempt.output.stderr].join("\n");
1225
+ const result = operationResult(attempt.operations);
1226
+ const title = attempt.title.filter(Boolean).at(-1) ?? "Unnamed test";
1227
+ const [selectedConversationId, setSelectedConversationId] = useState(attempt.operations[0]?.id);
1228
+ const selectedConversation = attempt.operations.find((operation) => operation.id === selectedConversationId) ??
1229
+ attempt.operations[0];
1230
+ return (_jsxs("article", { ...stylex.props(styles.attemptCard), children: [_jsxs("div", { ...stylex.props(styles.row), children: [_jsxs("div", { children: [_jsx("strong", { ...stylex.props(styles.attemptTitle), children: title }), _jsxs("p", { ...stylex.props(styles.meta), children: [attempt.project || "default", " \u00B7 ", attempt.operations.length, " named", " ", pluralize(attempt.operations.length, "operation")] })] }), _jsxs("div", { ...stylex.props(styles.attemptActions), children: [attempt.status === "failed" ? (_jsx(CopyFailureButton, { attempt: attempt, criteria: criteria })) : null, _jsx("span", { ...stylex.props(styles.status, attempt.status === "passed" && styles.statusPass, attempt.status === "failed" && styles.statusFail, attempt.status === "running" && styles.statusRunning), children: attempt.status })] })] }), _jsx(OperationList, { operations: attempt.operations }), _jsx(RunResult, { result: result, status: attempt.status, criteria: criteria, explanations: judgeCriterionExplanations(attempt.operations), errors: attempt.errors, criterionResults: attempt.criterionResults }), attempt.operations.length > 0 ? (_jsx(ConversationTabs, { operations: attempt.operations, selected: selectedConversation, select: setSelectedConversationId, attemptStatus: attempt.status })) : null, _jsx(Conversation, { operation: selectedConversation, operations: attempt.operations, select: setSelectedConversationId, status: attempt.status === "running"
1231
+ ? (selectedConversation?.status ?? attempt.status)
1232
+ : attempt.status }), _jsx(TechnicalDetails, { operations: attempt.operations, output: output })] }));
1233
+ }
1234
+ function CopyFailureButton({ attempt, criteria }) {
1235
+ const [state, setState] = useState("idle");
1236
+ const copy = async () => {
1237
+ try {
1238
+ await navigator.clipboard.writeText(failureDebugText(attempt, criteria));
1239
+ setState("copied");
1240
+ }
1241
+ catch {
1242
+ setState("failed");
1243
+ }
1244
+ };
1245
+ return (_jsx("button", { type: "button", "aria-label": "Copy failure details", ...stylex.props(styles.buttonReset, styles.copyFailureButton), onClick: () => void copy(), children: state === "copied" ? "Copied" : state === "failed" ? "Copy failed" : "Copy details" }));
1246
+ }
1247
+ function failureDebugText(attempt, criteria) {
1248
+ const result = operationResult(attempt.operations);
1249
+ const title = attempt.title.filter(Boolean);
1250
+ const output = [...attempt.output.stdout, ...attempt.output.stderr].join("\n");
1251
+ return [
1252
+ "Fix this agent test failure.",
1253
+ "Use the evidence below. Preserve the test's intent unless its expectation is incorrect.",
1254
+ "",
1255
+ `Test: ${title.at(-1) ?? "Unnamed test"}`,
1256
+ `Title path: ${title.join(" › ")}`,
1257
+ `Attempt: ${attempt.id}`,
1258
+ `Project: ${attempt.project || "default"}`,
1259
+ `Status: ${attempt.status}`,
1260
+ "",
1261
+ "Criteria:",
1262
+ ...failureCriterionLines(attempt, criteria),
1263
+ "",
1264
+ "Errors:",
1265
+ ...(attempt.errors.length
1266
+ ? attempt.errors.map((error) => error.message ?? "Test failed")
1267
+ : ["(none)"]),
1268
+ "",
1269
+ "Conversation and tools:",
1270
+ ...(result.timeline.length ? result.timeline.map(debugTimelineLine) : ["(none recorded)"]),
1271
+ "",
1272
+ "Test process output:",
1273
+ output || "(none)",
1274
+ ].join("\n");
1275
+ }
1276
+ function failureCriterionLines(attempt, criteria) {
1277
+ return criteria.map((criterion, index) => {
1278
+ const outcome = criterionDisplayOutcome({
1279
+ criterion,
1280
+ index,
1281
+ results: attempt.criterionResults,
1282
+ status: attempt.status,
1283
+ errors: attempt.errors,
1284
+ });
1285
+ return `- [${outcome}] ${criterion}`;
1286
+ });
1287
+ }
1288
+ function debugTimelineLine(event) {
1289
+ if (event.kind === "message")
1290
+ return `${event.message.role}: ${event.message.content}`;
1291
+ const args = event.tool.args ? ` ${JSON.stringify(event.tool.args)}` : "";
1292
+ const result = event.tool.result ? `\n result: ${event.tool.result}` : "";
1293
+ return `tool ${event.tool.name}:${args}${result}`;
1294
+ }
1295
+ function TechnicalDetails({ operations, output, }) {
1296
+ return (_jsxs("details", { ...stylex.props(styles.evidence), children: [_jsxs("summary", { ...stylex.props(styles.evidenceSummary), children: [_jsx("span", { ...stylex.props(styles.disclosureIcon), children: "\u203A" }), "Technical details"] }), _jsx("p", { ...stylex.props(styles.meta), children: "Low-level evidence for debugging the test runner, separate from the agent conversation." }), _jsx(EvidencePanel, { label: "Test process logs (stdout / stderr)", value: output, empty: "The test process did not write to stdout or stderr." }), _jsx(EvidencePanel, { label: "Diagnostics", value: JSON.stringify(operations, null, 2), empty: "No diagnostics were captured." })] }));
1297
+ }
1298
+ function EvidencePanel({ label, value, empty }) {
1299
+ return (_jsxs("details", { ...stylex.props(styles.evidence), children: [_jsxs("summary", { ...stylex.props(styles.evidenceSummary), children: [_jsx("span", { ...stylex.props(styles.disclosureIcon), children: "\u203A" }), label] }), value ? (_jsx("pre", { ...stylex.props(styles.pre), children: value })) : (_jsx("p", { ...stylex.props(styles.meta), children: empty }))] }));
1300
+ }
1301
+ function messagesFromOperation(value) {
1302
+ if (!isRecord(value))
1303
+ return [];
1304
+ const trace = isRecord(value.trace)
1305
+ ? value.trace
1306
+ : isRecord(value.conversation)
1307
+ ? value.conversation
1308
+ : undefined;
1309
+ if (!trace || !Array.isArray(trace.messages))
1310
+ return [];
1311
+ return uniqueMessages(trace.messages.flatMap((message) => isRecord(message) && typeof message.role === "string" && typeof message.content === "string"
1312
+ ? [{ role: message.role, content: message.content, seq: optionalNumber(message.seq) }]
1313
+ : []));
1314
+ }
1315
+ function toolCallsFromOperation(value) {
1316
+ if (!isRecord(value))
1317
+ return [];
1318
+ const trace = isRecord(value.trace)
1319
+ ? value.trace
1320
+ : isRecord(value.conversation)
1321
+ ? value.conversation
1322
+ : undefined;
1323
+ if (!trace || !Array.isArray(trace.toolCalls))
1324
+ return [];
1325
+ return trace.toolCalls.flatMap((call) => {
1326
+ if (!isRecord(call) || typeof call.name !== "string")
1327
+ return [];
1328
+ return [
1329
+ {
1330
+ name: call.name,
1331
+ args: isRecord(call.args) ? call.args : undefined,
1332
+ result: optionalString(call.result),
1333
+ succeeded: typeof call.succeeded === "boolean" ? call.succeeded : undefined,
1334
+ exitCode: optionalNumber(call.exitCode),
1335
+ seq: optionalNumber(call.seq),
1336
+ },
1337
+ ];
1338
+ });
1339
+ }
1340
+ function operationResult(operations) {
1341
+ const records = operations.flatMap((operation) => operation.data).filter(isRecord);
1342
+ const completed = [...records].reverse().find((value) => value.output !== undefined);
1343
+ const source = completed ?? records.at(-1);
1344
+ if (!source)
1345
+ return { timeline: [] };
1346
+ const prompt = records.map((record) => optionalString(record.prompt)).find(Boolean);
1347
+ return {
1348
+ prompt,
1349
+ output: conversationOutput(source.output),
1350
+ durationMs: optionalNumber(source.durationMs),
1351
+ totalTokens: nestedNumber(source.usage, "tokens", "total"),
1352
+ toolCallCount: optionalArrayLength(source.toolCalls),
1353
+ changedPathCount: nestedArrayLength(source.workspace, "changedPaths"),
1354
+ timeline: completed
1355
+ ? conversationTimeline(source, prompt)
1356
+ : liveConversationTimeline(records, prompt),
1357
+ };
1358
+ }
1359
+ function conversationOutput(value) {
1360
+ if (typeof value === "string")
1361
+ return value;
1362
+ if (!isRecord(value))
1363
+ return undefined;
1364
+ const reason = optionalString(value.reason);
1365
+ const facts = Object.entries(value)
1366
+ .filter(([key]) => key !== "reason")
1367
+ .map(([key, item]) => `${humanizeKey(key)}: ${formatConversationValue(item)}`);
1368
+ return [reason, ...facts].filter(Boolean).join("\n\n");
1369
+ }
1370
+ function humanizeKey(value) {
1371
+ return value
1372
+ .replace(CAMEL_CASE_BOUNDARY, "$1 $2")
1373
+ .replace(INITIAL_CHARACTER, (letter) => letter.toUpperCase());
1374
+ }
1375
+ function formatConversationValue(value) {
1376
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean")
1377
+ return String(value);
1378
+ return JSON.stringify(value);
1379
+ }
1380
+ function liveConversationTimeline(records, prompt) {
1381
+ const timeline = prompt
1382
+ ? [{ kind: "message", message: { role: "user", content: prompt, seq: -1 } }]
1383
+ : [];
1384
+ for (const [index, record] of records.entries()) {
1385
+ const tool = liveToolEvent(record, index);
1386
+ if (tool)
1387
+ timeline.push(tool);
1388
+ if (record.type === "text" && typeof record.text === "string")
1389
+ appendLiveText(timeline, record.text, index);
1390
+ }
1391
+ return timeline;
1392
+ }
1393
+ function liveToolEvent(record, seq) {
1394
+ if (record.type !== "tool" || typeof record.name !== "string")
1395
+ return undefined;
1396
+ return {
1397
+ kind: "tool",
1398
+ tool: {
1399
+ name: record.name,
1400
+ args: isRecord(record.args) ? record.args : undefined,
1401
+ result: optionalString(record.result),
1402
+ exitCode: optionalNumber(record.exitCode),
1403
+ succeeded: typeof record.succeeded === "boolean" ? record.succeeded : undefined,
1404
+ seq,
1405
+ },
1406
+ };
1407
+ }
1408
+ function appendLiveText(timeline, content, seq) {
1409
+ const last = timeline.at(-1);
1410
+ if (last?.kind === "message" && last.message.role === "assistant") {
1411
+ last.message.content = content;
1412
+ return;
1413
+ }
1414
+ timeline.push({ kind: "message", message: { role: "assistant", content, seq } });
1415
+ }
1416
+ function conversationTimeline(source, prompt) {
1417
+ const tools = toolCallsFromOperation(source);
1418
+ const messages = messagesFromOperation(source).filter((message) => message.role !== "tool" || tools.length === 0);
1419
+ const judgeInput = judgeInputMessages(source.input);
1420
+ if (prompt && !messages.some((message) => message.role === "user" && message.content === prompt))
1421
+ messages.unshift({ role: "user", content: prompt, seq: -1 });
1422
+ const output = conversationOutput(source.output);
1423
+ if (judgeInput.length && output && !messages.some((message) => message.role === "assistant"))
1424
+ messages.push({ role: "assistant", content: output, seq: 1 });
1425
+ return [
1426
+ ...judgeInput.map((message) => ({ kind: "message", message })),
1427
+ ...messages.map((message) => ({ kind: "message", message })),
1428
+ ...tools.map((tool) => ({ kind: "tool", tool })),
1429
+ ].sort((left, right) => eventOrder(left) - eventOrder(right));
1430
+ }
1431
+ function judgeInputMessages(value) {
1432
+ if (!isRecord(value))
1433
+ return [];
1434
+ return Object.entries(value).flatMap(([key, item], index) => {
1435
+ if (typeof item !== "string")
1436
+ return [];
1437
+ return [
1438
+ {
1439
+ role: key === "answer" ? "Agent response" : humanizeKey(key),
1440
+ content: item,
1441
+ seq: index - Object.keys(value).length - 1,
1442
+ },
1443
+ ];
1444
+ });
1445
+ }
1446
+ function eventOrder(event) {
1447
+ const value = event.kind === "message" ? event.message.seq : event.tool.seq;
1448
+ if (value !== undefined)
1449
+ return value;
1450
+ if (event.kind === "tool")
1451
+ return 0;
1452
+ return event.message.role === "user" ? -1 : 1;
1453
+ }
1454
+ function optionalString(value) {
1455
+ return typeof value === "string" ? value : undefined;
1456
+ }
1457
+ function optionalNumber(value) {
1458
+ return typeof value === "number" ? value : undefined;
1459
+ }
1460
+ function optionalArrayLength(value) {
1461
+ return Array.isArray(value) ? value.length : undefined;
1462
+ }
1463
+ function nestedNumber(value, parent, child) {
1464
+ if (!isRecord(value) || !isRecord(value[parent]))
1465
+ return undefined;
1466
+ return optionalNumber(value[parent][child]);
1467
+ }
1468
+ function nestedArrayLength(value, key) {
1469
+ return isRecord(value) ? optionalArrayLength(value[key]) : undefined;
1470
+ }
1471
+ function RunResult({ result, status, criteria, explanations, errors, criterionResults, }) {
1472
+ const presentations = criterionPresentations({
1473
+ criteria,
1474
+ explanations,
1475
+ results: criterionResults,
1476
+ status,
1477
+ errors,
1478
+ });
1479
+ const assignedFailures = new Set(presentations.map((item) => item.failure).filter(Boolean));
1480
+ return (_jsxs("section", { "aria-label": "Result", ...stylex.props(styles.resultPanel), children: [_jsx("h3", { ...stylex.props(styles.contentHeading), children: "Result" }), _jsx(ResultVerdict, { status: status }), _jsx(CriterionResults, { presentations: presentations }), errors
1481
+ .filter((error) => !assignedFailures.has(error.message))
1482
+ .map((error, index) => (_jsx(FailureDetails, { message: error.message ?? "Test failed" }, index))), _jsx(ResultMetrics, { result: result })] }));
1483
+ }
1484
+ function FailureDetails({ message }) {
1485
+ const comparison = assertionComparison(message);
1486
+ if (!comparison)
1487
+ return _jsx("pre", { ...stylex.props(styles.pre, styles.error), children: stripAnsi(message) });
1488
+ return (_jsxs("section", { "aria-label": "Expected vs received", ...stylex.props(styles.assertionCard), children: [_jsx("strong", { ...stylex.props(styles.assertionTitle), children: "Expected vs received" }), _jsxs("dl", { ...stylex.props(styles.assertionValues), children: [_jsx(AssertionValue, { label: "Expected", value: comparison.expected }), _jsx(AssertionValue, { label: "Received", value: comparison.received })] })] }));
1489
+ }
1490
+ function AssertionValue({ label, value }) {
1491
+ return (_jsxs("div", { ...stylex.props(styles.assertionValue), children: [_jsx("dt", { ...stylex.props(styles.assertionLabel), children: label }), _jsx("dd", { ...stylex.props(styles.assertionCode), children: value || "(empty)" })] }));
1492
+ }
1493
+ function ResultVerdict({ status }) {
1494
+ return status === "running" ? (_jsx("p", { ...stylex.props(styles.resultOutput), children: "The test is still running." })) : null;
1495
+ }
1496
+ function criterionPresentations({ criteria, explanations, results, status, errors, }) {
1497
+ const presentations = criteria.map((criterion, index) => ({
1498
+ criterion,
1499
+ explanation: explanations[index],
1500
+ outcome: criterionDisplayOutcome({ criterion, index, results, status, errors }),
1501
+ }));
1502
+ const failed = presentations.filter((item) => item.outcome === "failed");
1503
+ return presentations.map((item) => {
1504
+ const matched = errors.find((error) => criterionMatchesError(item.criterion, error.message));
1505
+ const onlyFailure = failed.length === 1 && errors.length === 1 ? errors[0] : undefined;
1506
+ return {
1507
+ ...item,
1508
+ failure: item.outcome === "failed" ? (matched?.message ?? onlyFailure?.message) : undefined,
1509
+ };
1510
+ });
1511
+ }
1512
+ function CriterionResults({ presentations }) {
1513
+ if (!presentations.length)
1514
+ return null;
1515
+ return (_jsx("section", { "aria-label": "Criterion results", ...stylex.props(styles.criterionResults), children: _jsx("ul", { ...stylex.props(styles.criterionResultList), children: presentations.map((presentation) => (_jsx(CriterionResultRow, { criterion: presentation.criterion, outcome: presentation.outcome, explanation: presentation.explanation, failure: presentation.failure }, presentation.criterion))) }) }));
1516
+ }
1517
+ function criterionDisplayOutcome(input) {
1518
+ const outcome = criterionOutcome(input);
1519
+ if (outcome !== "not-recorded" || input.status !== "failed")
1520
+ return outcome;
1521
+ return input.errors.some((error) => criterionMatchesError(input.criterion, error.message))
1522
+ ? "failed"
1523
+ : outcome;
1524
+ }
1525
+ function criterionMatchesError(criterion, message) {
1526
+ if (!message)
1527
+ return false;
1528
+ const comparison = assertionComparison(message);
1529
+ const expected = comparison?.expected.trim();
1530
+ return Boolean(expected && criterion.includes(expected));
1531
+ }
1532
+ function criterionOutcome({ criterion, index, results, status, }) {
1533
+ const recorded = results.find((result) => result.criterion === criterion) ?? results[index];
1534
+ if (recorded)
1535
+ return recorded.status;
1536
+ if (status === "passed")
1537
+ return "passed";
1538
+ if (status === "running")
1539
+ return "pending";
1540
+ return "not-recorded";
1541
+ }
1542
+ function CriterionResultRow({ criterion, outcome, explanation, failure, }) {
1543
+ const label = outcome === "not-recorded" ? "Not recorded" : capitalize(outcome);
1544
+ return (_jsxs("li", { ...stylex.props(styles.criterionResult), children: [_jsxs("div", { ...stylex.props(styles.criterionResultHeader), children: [_jsx(CriterionOutcomeIcon, { outcome: outcome, label: label }), _jsx("span", { children: criterion })] }), explanation ? _jsx("p", { ...stylex.props(styles.criterionExplanation), children: explanation }) : null, failure ? _jsx(FailureDetails, { message: failure }) : null] }));
1545
+ }
1546
+ function CriterionOutcomeIcon({ outcome, label }) {
1547
+ return (_jsx("span", { role: "img", "aria-label": label, ...stylex.props(styles.criterionOutcome, outcome === "passed" && styles.criterionOutcomePass, outcome === "failed" && styles.criterionOutcomeFail, outcome === "pending" && styles.criterionOutcomePending, outcome === "not-recorded" && styles.criterionOutcomeUnknown), children: criterionSymbol(outcome) }));
1548
+ }
1549
+ function criterionSymbol(outcome) {
1550
+ if (outcome === "passed")
1551
+ return "✓";
1552
+ if (outcome === "failed")
1553
+ return "×";
1554
+ if (outcome === "pending")
1555
+ return "…";
1556
+ return "–";
1557
+ }
1558
+ function capitalize(value) {
1559
+ return `${value.charAt(0).toUpperCase()}${value.slice(1)}`;
1560
+ }
1561
+ function ResultMetrics({ result }) {
1562
+ const metrics = [
1563
+ ["Duration", result.durationMs === undefined ? "—" : formatDuration(result.durationMs)],
1564
+ ["Tokens", result.totalTokens === undefined ? "—" : result.totalTokens.toLocaleString()],
1565
+ ["Tool calls", result.toolCallCount === undefined ? "—" : String(result.toolCallCount)],
1566
+ [
1567
+ "Files changed",
1568
+ result.changedPathCount === undefined ? "—" : String(result.changedPathCount),
1569
+ ],
1570
+ ];
1571
+ return (_jsx("div", { ...stylex.props(styles.metricGrid), children: metrics.map(([label, value]) => (_jsxs("div", { ...stylex.props(styles.metric), children: [_jsx("span", { ...stylex.props(styles.resourceFactLabel), children: label }), _jsx("span", { ...stylex.props(styles.metricValue), children: value })] }, label))) }));
1572
+ }
1573
+ function Conversation({ operation, operations, select, status, }) {
1574
+ const { timeline, judge } = conversationContent(operation, operations);
1575
+ return (_jsxs("section", { "aria-label": "Conversation", ...stylex.props(styles.conversation), children: [_jsxs("header", { ...stylex.props(styles.conversationHeader), children: [_jsx("h3", { ...stylex.props(styles.contentHeading), children: "Conversation" }), _jsx(ConversationRunTabs, { operation: operation, operations: operations, select: select })] }), _jsxs("div", { ...stylex.props(styles.conversationThread), children: [_jsx(ConversationEvents, { timeline: timeline }), _jsx(JudgeResponse, { review: judge })] }), timeline.length === 0 && status !== "running" ? (_jsx("p", { ...stylex.props(styles.meta), children: conversationPlaceholder(status) })) : null, status === "running" ? _jsx(RunningIndicator, {}) : null] }));
1576
+ }
1577
+ function conversationContent(operation, operations) {
1578
+ if (operation?.kind === "evaluation") {
1579
+ const judge = judgeReviewData(operation);
1580
+ return {
1581
+ judge,
1582
+ timeline: judge.question
1583
+ ? [
1584
+ {
1585
+ kind: "message",
1586
+ message: { role: "Judge question", content: judge.question, seq: -1 },
1587
+ },
1588
+ ]
1589
+ : [],
1590
+ };
1591
+ }
1592
+ const result = operationResult(operation ? [operation] : []);
1593
+ return {
1594
+ timeline: [...legacyJudgeInput(operation, operations), ...recordedTimeline(result)],
1595
+ };
1596
+ }
1597
+ function recordedTimeline(result) {
1598
+ if (result.timeline.length)
1599
+ return result.timeline;
1600
+ if (!result.output)
1601
+ return [];
1602
+ return [{ kind: "message", message: { role: "assistant", content: result.output } }];
1603
+ }
1604
+ function ConversationEvents({ timeline }) {
1605
+ return timeline.map((event, index) => event.kind === "tool" ? (_jsx(ToolActivity, { tool: event.tool }, `tool:${event.tool.seq ?? index}:${event.tool.name}`)) : (_jsx(MessageBubble, { message: event.message }, `message:${event.message.seq ?? index}:${event.message.role}`)));
1606
+ }
1607
+ function JudgeResponse({ review }) {
1608
+ if (!review || (!review.outcomes.length && !review.reason))
1609
+ return null;
1610
+ return _jsx(JudgeFindings, { outcomes: review.outcomes, reason: review.reason });
1611
+ }
1612
+ function JudgeFindings({ outcomes, reason, }) {
1613
+ return (_jsxs("section", { "aria-label": "Judge response", ...stylex.props(styles.judgeResponse), children: [_jsx("h4", { ...stylex.props(styles.judgeResponseHeading), children: "Judge response" }), _jsx("div", { ...stylex.props(styles.judgeOutcomeList), children: outcomes.map((outcome) => (_jsxs("div", { ...stylex.props(styles.judgeOutcome), children: [_jsx(CriterionOutcomeIcon, { outcome: outcome.passed ? "passed" : "failed", label: outcome.passed ? "Passed" : "Failed" }), _jsx("span", { ...stylex.props(styles.judgeOutcomeLabel), children: outcome.label }), outcome.explanation ? (_jsx("p", { ...stylex.props(styles.judgeOutcomeExplanation), children: outcome.explanation })) : null] }, outcome.label))) }), reason && !outcomes.length ? (_jsx("p", { ...stylex.props(styles.judgeOutcomeExplanation), children: reason })) : null] }));
1614
+ }
1615
+ function judgeReviewData(operation) {
1616
+ const records = operation.data.filter(isRecord);
1617
+ const record = [...records].reverse().find((item) => item.output !== undefined) ?? records.at(-1);
1618
+ const output = isRecord(record?.output) ? record.output : {};
1619
+ const reason = optionalString(output.reason) ?? conversationOutput(record?.output);
1620
+ return {
1621
+ question: judgeQuestion(record),
1622
+ outcomes: judgeOutcomes(output, reason),
1623
+ reason,
1624
+ };
1625
+ }
1626
+ function judgeQuestion(record) {
1627
+ const evaluation = isRecord(record?.evaluation) ? record.evaluation : undefined;
1628
+ return optionalString(evaluation?.prompt);
1629
+ }
1630
+ function judgeOutcomes(output, fallbackExplanation) {
1631
+ const entries = Object.entries(output).filter((entry) => typeof entry[1] === "boolean");
1632
+ const fallbacks = splitJudgeExplanation(fallbackExplanation, entries.length);
1633
+ return entries.map(([key, passed], index) => ({
1634
+ label: humanizeKey(key),
1635
+ passed,
1636
+ explanation: judgeOutcomeExplanation(output, key) ?? fallbacks[index],
1637
+ }));
1638
+ }
1639
+ function splitJudgeExplanation(value, count) {
1640
+ if (!value || count < 1)
1641
+ return [];
1642
+ const sentences = value.split(SENTENCE_BOUNDARY).filter(Boolean);
1643
+ if (sentences.length < count)
1644
+ return Array.from({ length: count }, () => value);
1645
+ return Array.from({ length: count }, (_, index) => index === count - 1 ? sentences.slice(index).join(" ") : (sentences[index] ?? value));
1646
+ }
1647
+ function judgeOutcomeExplanation(output, key) {
1648
+ const explanations = isRecord(output.explanations) ? output.explanations : {};
1649
+ return (optionalString(explanations[key]) ??
1650
+ optionalString(output[`${key}Explanation`]) ??
1651
+ optionalString(output[`${key}Reason`]));
1652
+ }
1653
+ function judgeCriterionExplanations(operations) {
1654
+ return operations
1655
+ .flatMap((operation) => operation.kind === "evaluation" ? judgeReviewData(operation).outcomes : [])
1656
+ .map((outcome) => outcome.explanation);
1657
+ }
1658
+ function legacyJudgeInput(operation, operations) {
1659
+ if (!operation || operation.kind !== "evaluation")
1660
+ return [];
1661
+ if (operation.data.some((item) => isRecord(item) && isRecord(item.input)))
1662
+ return [];
1663
+ const index = operations.findIndex((item) => item.id === operation.id);
1664
+ const agent = operations
1665
+ .slice(0, index)
1666
+ .reverse()
1667
+ .find((item) => item.kind === "agent");
1668
+ if (!agent)
1669
+ return [];
1670
+ const result = operationResult([agent]);
1671
+ const timeline = [];
1672
+ if (result.prompt)
1673
+ timeline.push({
1674
+ kind: "message",
1675
+ message: { role: "Task", content: result.prompt, seq: -3 },
1676
+ });
1677
+ if (result.output)
1678
+ timeline.push({
1679
+ kind: "message",
1680
+ message: { role: "Agent response", content: result.output, seq: -2 },
1681
+ });
1682
+ return timeline;
1683
+ }
1684
+ function ConversationTabs({ operations, selected, select, attemptStatus, }) {
1685
+ if (!operations.length)
1686
+ return null;
1687
+ const groups = conversationGroups(operations);
1688
+ const representatives = groups.map((group) => group.operations[0]);
1689
+ const selectedGroup = selected ? operationIdentity(selected) : undefined;
1690
+ return (_jsx("div", { role: "tablist", "aria-label": "Conversation participants", ...stylex.props(styles.conversationSwitcher, styles.conversationTabs), children: groups.map((group, index) => (_jsx(ConversationTab, { operation: group.operations[0], active: group.key === selectedGroup, running: attemptStatus === "running" &&
1691
+ group.operations.some((operation) => operation.status === "running"), onSelect: () => select(group.operations[0].id), onKeyDown: (event) => selectConversationWithKeyboard({
1692
+ event,
1693
+ operations: representatives,
1694
+ index,
1695
+ select,
1696
+ }) }, group.key))) }));
1697
+ }
1698
+ function ConversationTab({ operation, active, running, onSelect, onKeyDown, }) {
1699
+ return (_jsxs("button", { type: "button", role: "tab", "aria-label": conversationLabel(operation), "aria-selected": active, ...stylex.props(styles.buttonReset, styles.status, styles.conversationTab, active && styles.conversationTabActive), onClick: onSelect, onKeyDown: onKeyDown, children: [running ? (_jsx("span", { role: "status", "aria-label": `${operation?.name ?? "Agent"} is running`, ...stylex.props(styles.conversationTabDot) })) : null, conversationLabel(operation)] }));
1700
+ }
1701
+ function conversationLabel(operation) {
1702
+ return `${operation?.name ?? "Unnamed"} · ${operation?.kind === "evaluation" ? "Judge" : "Agent"}`;
1703
+ }
1704
+ function conversationGroups(operations) {
1705
+ const groups = new Map();
1706
+ for (const operation of operations) {
1707
+ const key = operationIdentity(operation);
1708
+ const group = groups.get(key);
1709
+ if (group)
1710
+ group.operations.push(operation);
1711
+ else
1712
+ groups.set(key, { key, operations: [operation] });
1713
+ }
1714
+ return [...groups.values()];
1715
+ }
1716
+ function operationIdentity(operation) {
1717
+ return `${operation.name ?? "Unnamed"}\u0000${operation.kind}`;
1718
+ }
1719
+ function ConversationRunTabs({ operation, operations, select, }) {
1720
+ if (!operation)
1721
+ return null;
1722
+ const runs = operations.filter((item) => operationIdentity(item) === operationIdentity(operation));
1723
+ if (runs.length < 2)
1724
+ return null;
1725
+ return (_jsx("div", { role: "tablist", "aria-label": `${operation.name ?? "Agent"} runs`, ...stylex.props(styles.runTabs), children: runs.map((run, index) => (_jsxs("button", { type: "button", role: "tab", "aria-selected": run.id === operation.id, ...stylex.props(styles.buttonReset, styles.runTab, run.id === operation.id && styles.runTabActive), onClick: () => select(run.id), onKeyDown: (event) => selectConversationWithKeyboard({ event, operations: runs, index, select }), children: ["Run ", index + 1] }, run.id))) }));
1726
+ }
1727
+ function selectConversationWithKeyboard(input) {
1728
+ const { event, operations, index, select } = input;
1729
+ if (event.key !== "ArrowLeft" && event.key !== "ArrowRight")
1730
+ return;
1731
+ event.preventDefault();
1732
+ const direction = event.key === "ArrowRight" ? 1 : -1;
1733
+ const next = operations[(index + direction + operations.length) % operations.length];
1734
+ if (!next)
1735
+ return;
1736
+ select(next.id);
1737
+ const tabs = event.currentTarget.parentElement?.querySelectorAll("[role=tab]");
1738
+ tabs?.[(index + direction + operations.length) % operations.length]?.focus();
1739
+ }
1740
+ function RunningIndicator() {
1741
+ return (_jsxs("div", { role: "status", "aria-label": "Agent is running", ...stylex.props(styles.runningIndicator), children: [_jsx("span", { children: "Running" }), _jsxs("span", { "aria-hidden": "true", ...stylex.props(styles.runningDots), children: [_jsx("span", { ...stylex.props(styles.runningDot), children: "\u2022" }), _jsx("span", { ...stylex.props(styles.runningDot, styles.runningDotSecond), children: "\u2022" }), _jsx("span", { ...stylex.props(styles.runningDot, styles.runningDotThird), children: "\u2022" })] })] }));
1742
+ }
1743
+ function ToolActivity({ tool }) {
1744
+ const presentation = toolPresentation(tool);
1745
+ const [outputOpen, setOutputOpen] = useState(false);
1746
+ return (_jsxs("article", { ...stylex.props(styles.toolEvent), children: [_jsx("span", { "aria-hidden": "true", ...stylex.props(styles.toolIcon), children: presentation.icon }), _jsxs("div", { ...stylex.props(styles.toolCopy), children: [_jsx("strong", { ...stylex.props(styles.toolTitle), children: presentation.title }), presentation.detail ? (_jsx("span", { ...stylex.props(styles.toolDetail), children: presentation.detail })) : null] }), _jsxs("div", { role: "group", "aria-label": "Tool controls", ...stylex.props(styles.toolActions), children: [_jsx("span", { ...stylex.props(styles.toolOutcome, presentation.failed && styles.toolOutcomeFail), children: presentation.outcome }), tool.result ? (_jsx("button", { type: "button", ...stylex.props(styles.buttonReset, styles.toolResultSummary), onClick: () => setOutputOpen((open) => !open), children: outputOpen ? "Hide output" : "View output" })) : null] }), tool.result && outputOpen ? (_jsx("pre", { ...stylex.props(styles.toolResultPre), children: tool.result })) : null] }));
1747
+ }
1748
+ function toolPresentation(tool) {
1749
+ const name = tool.name.toLowerCase();
1750
+ const failed = tool.succeeded === false || (tool.exitCode !== undefined && tool.exitCode !== 0);
1751
+ const outcome = tool.exitCode !== undefined ? `Exit ${tool.exitCode}` : failed ? "Failed" : "Completed";
1752
+ if (name === "read" || name.includes("read_file"))
1753
+ return { icon: "↗", title: "Read file", detail: argument(tool, "path"), outcome, failed };
1754
+ if (["shell", "bash", "exec_command"].includes(name))
1755
+ return { icon: ">", title: "Run command", detail: argument(tool, "command"), outcome, failed };
1756
+ if (name.includes("edit") || name.includes("write"))
1757
+ return { icon: "✎", title: "Change file", detail: argument(tool, "path"), outcome, failed };
1758
+ return { icon: "◆", title: tool.name, detail: summarizeArgs(tool.args), outcome, failed };
1759
+ }
1760
+ function argument(tool, key) {
1761
+ const value = tool.args?.[key];
1762
+ return typeof value === "string" ? value : summarizeArgs(tool.args);
1763
+ }
1764
+ function summarizeArgs(args) {
1765
+ if (!args || Object.keys(args).length === 0)
1766
+ return "";
1767
+ const value = JSON.stringify(args);
1768
+ return value.length > 140 ? `${value.slice(0, 137)}…` : value;
1769
+ }
1770
+ function MessageBubble({ message }) {
1771
+ return (_jsxs("div", { ...stylex.props(styles.message, (message.role === "user" || message.role === "Task" || message.role === "Judge question") &&
1772
+ styles.messageUser, (message.role === "assistant" || message.role === "Agent response") &&
1773
+ styles.messageAssistant, message.role === "Judge response" && styles.messageJudge), children: [_jsx("span", { ...stylex.props(styles.messageRole), children: message.role }), _jsx("div", { ...stylex.props(styles.messageContent), children: _jsx("div", { className: "message-markdown", children: _jsx(Markdown, { children: normalizeTranscriptMarkdown(message.content) }) }) })] }));
1774
+ }
1775
+ function normalizeTranscriptMarkdown(content) {
1776
+ return content.replace(LOCAL_PATH_LINK, (_match, label) => `\`${label}\``);
1777
+ }
1778
+ function uniqueMessages(messages) {
1779
+ const seen = new Set();
1780
+ return messages.filter((message) => {
1781
+ const key = `${message.role}\u0000${message.content}`;
1782
+ if (seen.has(key))
1783
+ return false;
1784
+ seen.add(key);
1785
+ return true;
1786
+ });
1787
+ }
1788
+ function formatDuration(durationMs) {
1789
+ return durationMs < 1_000 ? `${durationMs} ms` : `${(durationMs / 1_000).toFixed(1)} s`;
1790
+ }
1791
+ function pluralize(count, noun) {
1792
+ return count === 1 ? noun : `${noun}s`;
1793
+ }
1794
+ function isRecord(value) {
1795
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1796
+ }
1797
+ function OperationList({ operations }) {
1798
+ if (operations.length === 0)
1799
+ return null;
1800
+ const summaries = summarizeOperations(operations);
1801
+ return (_jsx("div", { ...stylex.props(styles.list), children: summaries.map((summary) => (_jsxs("div", { ...stylex.props(styles.meta), children: [summary.name, " \u00B7 ", summary.status, summary.count > 1 ? ` ×${summary.count}` : ""] }, summary.key))) }));
1802
+ }
1803
+ function summarizeOperations(operations) {
1804
+ const summaries = new Map();
1805
+ for (const operation of operations) {
1806
+ const name = operation.name ?? operation.kind;
1807
+ const key = `${operationIdentity(operation)}\u0000${operation.status}`;
1808
+ const existing = summaries.get(key);
1809
+ if (existing)
1810
+ existing.count++;
1811
+ else
1812
+ summaries.set(key, { key, name, status: operation.status, count: 1 });
1813
+ }
1814
+ return [...summaries.values()];
1815
+ }
1816
+ function useExecutionHistory() {
1817
+ return useQuery({
1818
+ queryKey: ["execution-history"],
1819
+ queryFn: fetchExecutionHistory,
1820
+ });
1821
+ }
1822
+ async function fetchTestCatalog() {
1823
+ return viewerApi.getTestCatalog();
1824
+ }
1825
+ async function fetchExecutionHistory() {
1826
+ return (await viewerApi.listExecutions()).executions;
1827
+ }
1828
+ async function fetchExecution(id) {
1829
+ return (await viewerApi.getExecution(id)).execution;
1830
+ }
1831
+ async function startTest(testId, workers) {
1832
+ return viewerApi.startExecution(testId, workers);
1833
+ }
1834
+ async function startSuite(workers) {
1835
+ return viewerApi.startSuiteExecution(workers);
1836
+ }
1837
+ async function startTestGroup(testIds, workers) {
1838
+ return viewerApi.startTestGroup(testIds, workers);
1839
+ }
1840
+ async function cancelExecution(id) {
1841
+ await viewerApi.cancelExecution(id);
1842
+ }
1843
+ function latestTestStatuses(executions) {
1844
+ const statuses = new Map();
1845
+ for (const execution of executions) {
1846
+ for (const testId of execution.testIds ?? []) {
1847
+ if (statuses.has(testId))
1848
+ continue;
1849
+ statuses.set(testId, execution.testStatuses?.[testId] ?? execution.status);
1850
+ }
1851
+ }
1852
+ return statuses;
1853
+ }
1854
+ function groupTests(tests) {
1855
+ const groups = new Map();
1856
+ for (const test of tests) {
1857
+ const name = test.title.slice(0, -1).join(" › ") || test.file;
1858
+ groups.set(name, [...(groups.get(name) ?? []), test]);
1859
+ }
1860
+ return groups;
1861
+ }
1862
+ //# sourceMappingURL=v2-client.js.map