@post-print/agent-test 1.1.9 → 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 (300) hide show
  1. package/README.md +18 -66
  2. package/dist/cli.d.ts +2 -64
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +26 -691
  5. package/dist/cli.js.map +1 -1
  6. package/dist/host-login.d.ts +1 -26
  7. package/dist/host-login.d.ts.map +1 -1
  8. package/dist/host-login.js +1 -92
  9. package/dist/host-login.js.map +1 -1
  10. package/dist/index.d.ts +6 -28
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +4 -26
  13. package/dist/index.js.map +1 -1
  14. package/dist/sdk/cli.d.ts +3 -0
  15. package/dist/sdk/cli.d.ts.map +1 -0
  16. package/dist/sdk/cli.js +55 -0
  17. package/dist/sdk/cli.js.map +1 -0
  18. package/dist/sdk/definitions.d.ts +22 -0
  19. package/dist/sdk/definitions.d.ts.map +1 -0
  20. package/dist/sdk/definitions.js +58 -0
  21. package/dist/sdk/definitions.js.map +1 -0
  22. package/dist/sdk/execution-reporter.d.ts +18 -0
  23. package/dist/sdk/execution-reporter.d.ts.map +1 -0
  24. package/dist/sdk/execution-reporter.js +171 -0
  25. package/dist/sdk/execution-reporter.js.map +1 -0
  26. package/dist/sdk/execution-runner.d.ts +14 -0
  27. package/dist/sdk/execution-runner.d.ts.map +1 -0
  28. package/dist/sdk/execution-runner.js +80 -0
  29. package/dist/sdk/execution-runner.js.map +1 -0
  30. package/dist/sdk/execution-store.d.ts +92 -0
  31. package/dist/sdk/execution-store.d.ts.map +1 -0
  32. package/dist/sdk/execution-store.js +357 -0
  33. package/dist/sdk/execution-store.js.map +1 -0
  34. package/dist/sdk/expect.d.ts +31 -0
  35. package/dist/sdk/expect.d.ts.map +1 -0
  36. package/dist/sdk/expect.js +96 -0
  37. package/dist/sdk/expect.js.map +1 -0
  38. package/dist/sdk/judge.d.ts +16 -0
  39. package/dist/sdk/judge.d.ts.map +1 -0
  40. package/dist/sdk/judge.js +82 -0
  41. package/dist/sdk/judge.js.map +1 -0
  42. package/dist/sdk/metrics.d.ts +3 -0
  43. package/dist/sdk/metrics.d.ts.map +1 -0
  44. package/dist/sdk/metrics.js +24 -0
  45. package/dist/sdk/metrics.js.map +1 -0
  46. package/dist/sdk/playwright-cli.d.ts +2 -0
  47. package/dist/sdk/playwright-cli.d.ts.map +1 -0
  48. package/dist/sdk/playwright-cli.js +6 -0
  49. package/dist/sdk/playwright-cli.js.map +1 -0
  50. package/dist/sdk/reporter.d.ts +12 -0
  51. package/dist/sdk/reporter.d.ts.map +1 -0
  52. package/dist/sdk/reporter.js +98 -0
  53. package/dist/sdk/reporter.js.map +1 -0
  54. package/dist/sdk/runtime.d.ts +33 -0
  55. package/dist/sdk/runtime.d.ts.map +1 -0
  56. package/dist/sdk/runtime.js +197 -0
  57. package/dist/sdk/runtime.js.map +1 -0
  58. package/dist/sdk/test.d.ts +36 -0
  59. package/dist/sdk/test.d.ts.map +1 -0
  60. package/dist/sdk/test.js +133 -0
  61. package/dist/sdk/test.js.map +1 -0
  62. package/dist/sdk/types.d.ts +76 -0
  63. package/dist/sdk/types.d.ts.map +1 -0
  64. package/dist/sdk/types.js.map +1 -0
  65. package/dist/sdk/usage.d.ts +10 -0
  66. package/dist/sdk/usage.d.ts.map +1 -0
  67. package/dist/sdk/usage.js +13 -0
  68. package/dist/sdk/usage.js.map +1 -0
  69. package/dist/sdk/viewer.d.ts +5 -0
  70. package/dist/sdk/viewer.d.ts.map +1 -0
  71. package/dist/sdk/viewer.js +74 -0
  72. package/dist/sdk/viewer.js.map +1 -0
  73. package/dist/sdk/workspace.d.ts +33 -0
  74. package/dist/sdk/workspace.d.ts.map +1 -0
  75. package/dist/sdk/workspace.js +100 -0
  76. package/dist/sdk/workspace.js.map +1 -0
  77. package/dist/viewer/bootstrap.d.ts +10 -0
  78. package/dist/viewer/bootstrap.d.ts.map +1 -0
  79. package/dist/viewer/bootstrap.js +2 -0
  80. package/dist/viewer/bootstrap.js.map +1 -0
  81. package/dist/viewer/client-entry.d.ts +2 -0
  82. package/dist/viewer/client-entry.d.ts.map +1 -0
  83. package/dist/viewer/client-entry.js +31 -0
  84. package/dist/viewer/client-entry.js.map +1 -0
  85. package/dist/viewer/generated-api.d.ts +15 -0
  86. package/dist/viewer/generated-api.d.ts.map +1 -0
  87. package/dist/viewer/generated-api.js +42 -0
  88. package/dist/viewer/generated-api.js.map +1 -0
  89. package/dist/viewer/generated-contracts.d.ts +13 -0
  90. package/dist/viewer/generated-contracts.d.ts.map +1 -0
  91. package/dist/viewer/generated-contracts.js +12 -0
  92. package/dist/viewer/generated-contracts.js.map +1 -0
  93. package/dist/viewer/main.js +64 -3
  94. package/dist/viewer/main.js.map +1 -1
  95. package/dist/viewer/page.d.ts +2 -4
  96. package/dist/viewer/page.d.ts.map +1 -1
  97. package/dist/viewer/page.js +18 -194
  98. package/dist/viewer/page.js.map +1 -1
  99. package/dist/viewer/presentation.d.ts +8 -0
  100. package/dist/viewer/presentation.d.ts.map +1 -0
  101. package/dist/viewer/presentation.js +45 -0
  102. package/dist/viewer/presentation.js.map +1 -0
  103. package/dist/viewer/protocol.d.ts +21 -0
  104. package/dist/viewer/protocol.d.ts.map +1 -0
  105. package/dist/viewer/protocol.js +6 -0
  106. package/dist/viewer/protocol.js.map +1 -0
  107. package/dist/viewer/server.d.ts +7 -11
  108. package/dist/viewer/server.d.ts.map +1 -1
  109. package/dist/viewer/server.js +314 -175
  110. package/dist/viewer/server.js.map +1 -1
  111. package/dist/viewer/styles.d.ts +2 -0
  112. package/dist/viewer/styles.d.ts.map +1 -0
  113. package/dist/viewer/styles.js +97 -0
  114. package/dist/viewer/styles.js.map +1 -0
  115. package/dist/viewer/stylex.css +1322 -0
  116. package/dist/viewer/test-catalog.d.ts +43 -0
  117. package/dist/viewer/test-catalog.d.ts.map +1 -0
  118. package/dist/viewer/test-catalog.js +27 -0
  119. package/dist/viewer/test-catalog.js.map +1 -0
  120. package/dist/viewer/v2-client.d.ts +7 -0
  121. package/dist/viewer/v2-client.d.ts.map +1 -0
  122. package/dist/viewer/v2-client.js +1862 -0
  123. package/dist/viewer/v2-client.js.map +1 -0
  124. package/package.json +19 -9
  125. package/dist/check.d.ts +0 -38
  126. package/dist/check.d.ts.map +0 -1
  127. package/dist/check.js +0 -169
  128. package/dist/check.js.map +0 -1
  129. package/dist/command-allowlist.d.ts +0 -9
  130. package/dist/command-allowlist.d.ts.map +0 -1
  131. package/dist/command-allowlist.js +0 -29
  132. package/dist/command-allowlist.js.map +0 -1
  133. package/dist/compare-scenario.d.ts +0 -65
  134. package/dist/compare-scenario.d.ts.map +0 -1
  135. package/dist/compare-scenario.js +0 -328
  136. package/dist/compare-scenario.js.map +0 -1
  137. package/dist/debug-bundle.d.ts +0 -81
  138. package/dist/debug-bundle.d.ts.map +0 -1
  139. package/dist/debug-bundle.js +0 -392
  140. package/dist/debug-bundle.js.map +0 -1
  141. package/dist/discover-suites.d.ts +0 -2
  142. package/dist/discover-suites.d.ts.map +0 -1
  143. package/dist/discover-suites.js +0 -19
  144. package/dist/discover-suites.js.map +0 -1
  145. package/dist/doctor.d.ts +0 -24
  146. package/dist/doctor.d.ts.map +0 -1
  147. package/dist/doctor.js +0 -272
  148. package/dist/doctor.js.map +0 -1
  149. package/dist/expect.d.ts +0 -59
  150. package/dist/expect.d.ts.map +0 -1
  151. package/dist/expect.js +0 -518
  152. package/dist/expect.js.map +0 -1
  153. package/dist/failures.d.ts +0 -4
  154. package/dist/failures.d.ts.map +0 -1
  155. package/dist/failures.js +0 -7
  156. package/dist/failures.js.map +0 -1
  157. package/dist/host-log.d.ts +0 -17
  158. package/dist/host-log.d.ts.map +0 -1
  159. package/dist/host-log.js +0 -154
  160. package/dist/host-log.js.map +0 -1
  161. package/dist/hosts.d.ts +0 -22
  162. package/dist/hosts.d.ts.map +0 -1
  163. package/dist/hosts.js +0 -84
  164. package/dist/hosts.js.map +0 -1
  165. package/dist/html-report.d.ts +0 -18
  166. package/dist/html-report.d.ts.map +0 -1
  167. package/dist/html-report.js +0 -1276
  168. package/dist/html-report.js.map +0 -1
  169. package/dist/live-isolation.d.ts +0 -82
  170. package/dist/live-isolation.d.ts.map +0 -1
  171. package/dist/live-isolation.js +0 -399
  172. package/dist/live-isolation.js.map +0 -1
  173. package/dist/live-timeout.d.ts +0 -11
  174. package/dist/live-timeout.d.ts.map +0 -1
  175. package/dist/live-timeout.js +0 -29
  176. package/dist/live-timeout.js.map +0 -1
  177. package/dist/load-adapters.d.ts +0 -13
  178. package/dist/load-adapters.d.ts.map +0 -1
  179. package/dist/load-adapters.js +0 -76
  180. package/dist/load-adapters.js.map +0 -1
  181. package/dist/load-suite.d.ts +0 -22
  182. package/dist/load-suite.d.ts.map +0 -1
  183. package/dist/load-suite.js +0 -154
  184. package/dist/load-suite.js.map +0 -1
  185. package/dist/mcp-config.d.ts +0 -13
  186. package/dist/mcp-config.d.ts.map +0 -1
  187. package/dist/mcp-config.js +0 -121
  188. package/dist/mcp-config.js.map +0 -1
  189. package/dist/preflight.d.ts +0 -3
  190. package/dist/preflight.d.ts.map +0 -1
  191. package/dist/preflight.js +0 -17
  192. package/dist/preflight.js.map +0 -1
  193. package/dist/progress.d.ts +0 -24
  194. package/dist/progress.d.ts.map +0 -1
  195. package/dist/progress.js +0 -111
  196. package/dist/progress.js.map +0 -1
  197. package/dist/record-trace.d.ts +0 -64
  198. package/dist/record-trace.d.ts.map +0 -1
  199. package/dist/record-trace.js +0 -124
  200. package/dist/record-trace.js.map +0 -1
  201. package/dist/report-preview-server.d.ts +0 -2
  202. package/dist/report-preview-server.d.ts.map +0 -1
  203. package/dist/report-preview-server.js +0 -24
  204. package/dist/report-preview-server.js.map +0 -1
  205. package/dist/report-preview.d.ts +0 -35
  206. package/dist/report-preview.d.ts.map +0 -1
  207. package/dist/report-preview.js +0 -205
  208. package/dist/report-preview.js.map +0 -1
  209. package/dist/run-suite.d.ts +0 -139
  210. package/dist/run-suite.d.ts.map +0 -1
  211. package/dist/run-suite.js +0 -1688
  212. package/dist/run-suite.js.map +0 -1
  213. package/dist/scenario-finalizer.d.ts +0 -27
  214. package/dist/scenario-finalizer.d.ts.map +0 -1
  215. package/dist/scenario-finalizer.js +0 -39
  216. package/dist/scenario-finalizer.js.map +0 -1
  217. package/dist/scenario-retry.d.ts +0 -15
  218. package/dist/scenario-retry.d.ts.map +0 -1
  219. package/dist/scenario-retry.js +0 -52
  220. package/dist/scenario-retry.js.map +0 -1
  221. package/dist/scenario-seed.d.ts +0 -13
  222. package/dist/scenario-seed.d.ts.map +0 -1
  223. package/dist/scenario-seed.js +0 -72
  224. package/dist/scenario-seed.js.map +0 -1
  225. package/dist/scenario-story.d.ts +0 -41
  226. package/dist/scenario-story.d.ts.map +0 -1
  227. package/dist/scenario-story.js +0 -459
  228. package/dist/scenario-story.js.map +0 -1
  229. package/dist/scenario-usage.d.ts +0 -15
  230. package/dist/scenario-usage.d.ts.map +0 -1
  231. package/dist/scenario-usage.js +0 -18
  232. package/dist/scenario-usage.js.map +0 -1
  233. package/dist/suite-summary.d.ts +0 -16
  234. package/dist/suite-summary.d.ts.map +0 -1
  235. package/dist/suite-summary.js +0 -218
  236. package/dist/suite-summary.js.map +0 -1
  237. package/dist/theme.d.ts +0 -96
  238. package/dist/theme.d.ts.map +0 -1
  239. package/dist/theme.js +0 -446
  240. package/dist/theme.js.map +0 -1
  241. package/dist/types.d.ts +0 -364
  242. package/dist/types.d.ts.map +0 -1
  243. package/dist/types.js.map +0 -1
  244. package/dist/validate-seeds.d.ts +0 -20
  245. package/dist/validate-seeds.d.ts.map +0 -1
  246. package/dist/validate-seeds.js +0 -72
  247. package/dist/validate-seeds.js.map +0 -1
  248. package/dist/validate-suite.d.ts +0 -24
  249. package/dist/validate-suite.d.ts.map +0 -1
  250. package/dist/validate-suite.js +0 -542
  251. package/dist/validate-suite.js.map +0 -1
  252. package/dist/viewer/catalog.d.ts +0 -72
  253. package/dist/viewer/catalog.d.ts.map +0 -1
  254. package/dist/viewer/catalog.js +0 -154
  255. package/dist/viewer/catalog.js.map +0 -1
  256. package/dist/viewer/cli.d.ts +0 -17
  257. package/dist/viewer/cli.d.ts.map +0 -1
  258. package/dist/viewer/cli.js +0 -38
  259. package/dist/viewer/cli.js.map +0 -1
  260. package/dist/viewer/client.d.ts +0 -7
  261. package/dist/viewer/client.d.ts.map +0 -1
  262. package/dist/viewer/client.js +0 -14
  263. package/dist/viewer/client.js.map +0 -1
  264. package/dist/viewer/compare-metrics.d.ts +0 -30
  265. package/dist/viewer/compare-metrics.d.ts.map +0 -1
  266. package/dist/viewer/compare-metrics.js +0 -101
  267. package/dist/viewer/compare-metrics.js.map +0 -1
  268. package/dist/viewer/context-files.d.ts +0 -8
  269. package/dist/viewer/context-files.d.ts.map +0 -1
  270. package/dist/viewer/context-files.js +0 -57
  271. package/dist/viewer/context-files.js.map +0 -1
  272. package/dist/viewer/emit.d.ts +0 -7
  273. package/dist/viewer/emit.d.ts.map +0 -1
  274. package/dist/viewer/emit.js +0 -25
  275. package/dist/viewer/emit.js.map +0 -1
  276. package/dist/viewer/events.d.ts +0 -118
  277. package/dist/viewer/events.d.ts.map +0 -1
  278. package/dist/viewer/events.js +0 -51
  279. package/dist/viewer/events.js.map +0 -1
  280. package/dist/viewer/live-runner.d.ts +0 -27
  281. package/dist/viewer/live-runner.d.ts.map +0 -1
  282. package/dist/viewer/live-runner.js +0 -166
  283. package/dist/viewer/live-runner.js.map +0 -1
  284. package/dist/viewer/run-controller.d.ts +0 -41
  285. package/dist/viewer/run-controller.d.ts.map +0 -1
  286. package/dist/viewer/run-controller.js +0 -426
  287. package/dist/viewer/run-controller.js.map +0 -1
  288. package/dist/viewer/session-server.d.ts +0 -2
  289. package/dist/viewer/session-server.d.ts.map +0 -1
  290. package/dist/viewer/session-server.js +0 -71
  291. package/dist/viewer/session-server.js.map +0 -1
  292. package/dist/warnings.d.ts +0 -3
  293. package/dist/warnings.d.ts.map +0 -1
  294. package/dist/warnings.js +0 -13
  295. package/dist/warnings.js.map +0 -1
  296. package/dist/worker-pool.d.ts +0 -8
  297. package/dist/worker-pool.d.ts.map +0 -1
  298. package/dist/worker-pool.js +0 -26
  299. package/dist/worker-pool.js.map +0 -1
  300. /package/dist/{types.js → sdk/types.js} +0 -0
@@ -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