agent-regression-lab 0.1.0 → 0.1.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.
- package/dist/ui/server.js +29 -3
- package/dist/ui-assets/client.css +174 -0
- package/dist/ui-assets/client.js +22105 -0
- package/package.json +4 -2
package/dist/ui/server.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { build } from "esbuild";
|
|
2
2
|
import { createServer } from "node:http";
|
|
3
|
-
import { readFileSync, existsSync } from "node:fs";
|
|
4
|
-
import { extname, resolve } from "node:path";
|
|
3
|
+
import { readFileSync, existsSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { dirname, extname, resolve } from "node:path";
|
|
5
|
+
import { fileURLToPath } from "node:url";
|
|
5
6
|
import { ensureDir } from "../lib/fs.js";
|
|
6
7
|
import { getRunErrorDetail } from "../runOutput.js";
|
|
7
8
|
import { Storage } from "../storage.js";
|
|
8
9
|
const UI_ROOT = resolve("artifacts", "ui");
|
|
9
10
|
const ASSETS_ROOT = resolve(UI_ROOT, "assets");
|
|
11
|
+
const PACKAGED_ASSETS_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..", "ui-assets");
|
|
12
|
+
const SOURCE_UI_ENTRY = resolve("src", "ui", "client.tsx");
|
|
10
13
|
const PORT = 4173;
|
|
11
14
|
export async function startUiServer() {
|
|
12
15
|
await buildUiAssets();
|
|
@@ -91,9 +94,17 @@ function handleApi(url, response) {
|
|
|
91
94
|
}
|
|
92
95
|
}
|
|
93
96
|
async function buildUiAssets() {
|
|
97
|
+
if (existsSync(PACKAGED_ASSETS_ROOT)) {
|
|
98
|
+
ensureDir(ASSETS_ROOT);
|
|
99
|
+
writePackagedAssetCopies();
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (!existsSync(SOURCE_UI_ENTRY)) {
|
|
103
|
+
throw new Error("UI assets are unavailable. Install a package build that includes dist/ui-assets or run from the repo root.");
|
|
104
|
+
}
|
|
94
105
|
ensureDir(ASSETS_ROOT);
|
|
95
106
|
await build({
|
|
96
|
-
entryPoints: [
|
|
107
|
+
entryPoints: [SOURCE_UI_ENTRY],
|
|
97
108
|
outdir: ASSETS_ROOT,
|
|
98
109
|
bundle: true,
|
|
99
110
|
format: "esm",
|
|
@@ -106,6 +117,21 @@ async function buildUiAssets() {
|
|
|
106
117
|
},
|
|
107
118
|
});
|
|
108
119
|
}
|
|
120
|
+
function writePackagedAssetCopies() {
|
|
121
|
+
for (const assetName of ["client.js", "client.css"]) {
|
|
122
|
+
const sourcePath = resolve(PACKAGED_ASSETS_ROOT, assetName);
|
|
123
|
+
const targetPath = resolve(ASSETS_ROOT, assetName);
|
|
124
|
+
if (!existsSync(sourcePath)) {
|
|
125
|
+
throw new Error(`Packaged UI asset '${assetName}' is missing.`);
|
|
126
|
+
}
|
|
127
|
+
responseSafeCopy(sourcePath, targetPath);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function responseSafeCopy(sourcePath, targetPath) {
|
|
131
|
+
ensureDir(dirname(targetPath));
|
|
132
|
+
const contents = readFileSync(sourcePath);
|
|
133
|
+
writeFileSync(targetPath, contents);
|
|
134
|
+
}
|
|
109
135
|
function serveStatic(path, response) {
|
|
110
136
|
if (!existsSync(path)) {
|
|
111
137
|
response.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/* src/ui/styles.css */
|
|
2
|
+
:root {
|
|
3
|
+
color-scheme: light;
|
|
4
|
+
--bg: #f1ede4;
|
|
5
|
+
--panel: #fffdf7;
|
|
6
|
+
--ink: #1c1a16;
|
|
7
|
+
--muted: #665f54;
|
|
8
|
+
--line: #d6ccbc;
|
|
9
|
+
--accent: #9e3d22;
|
|
10
|
+
--pass: #1e6a42;
|
|
11
|
+
--fail: #9a2c1f;
|
|
12
|
+
--error: #5b1e72;
|
|
13
|
+
}
|
|
14
|
+
* {
|
|
15
|
+
box-sizing: border-box;
|
|
16
|
+
}
|
|
17
|
+
body {
|
|
18
|
+
margin: 0;
|
|
19
|
+
background:
|
|
20
|
+
radial-gradient(
|
|
21
|
+
circle at top,
|
|
22
|
+
#f8f3ea 0,
|
|
23
|
+
var(--bg) 45%,
|
|
24
|
+
#e4dccd 100%);
|
|
25
|
+
color: var(--ink);
|
|
26
|
+
font-family:
|
|
27
|
+
"IBM Plex Sans",
|
|
28
|
+
"Helvetica Neue",
|
|
29
|
+
sans-serif;
|
|
30
|
+
}
|
|
31
|
+
a {
|
|
32
|
+
color: var(--accent);
|
|
33
|
+
text-decoration: none;
|
|
34
|
+
}
|
|
35
|
+
pre {
|
|
36
|
+
white-space: pre-wrap;
|
|
37
|
+
word-break: break-word;
|
|
38
|
+
background: #f7f1e6;
|
|
39
|
+
border: 1px solid var(--line);
|
|
40
|
+
padding: 0.8rem;
|
|
41
|
+
border-radius: 10px;
|
|
42
|
+
}
|
|
43
|
+
.shell {
|
|
44
|
+
min-height: 100vh;
|
|
45
|
+
}
|
|
46
|
+
.topbar {
|
|
47
|
+
position: sticky;
|
|
48
|
+
top: 0;
|
|
49
|
+
backdrop-filter: blur(10px);
|
|
50
|
+
background: rgba(241, 237, 228, 0.92);
|
|
51
|
+
border-bottom: 1px solid var(--line);
|
|
52
|
+
padding: 1rem 1.25rem;
|
|
53
|
+
}
|
|
54
|
+
.brand {
|
|
55
|
+
font-family: "IBM Plex Mono", monospace;
|
|
56
|
+
font-size: 0.95rem;
|
|
57
|
+
text-transform: uppercase;
|
|
58
|
+
letter-spacing: 0.08em;
|
|
59
|
+
color: var(--ink);
|
|
60
|
+
}
|
|
61
|
+
.page {
|
|
62
|
+
max-width: 1200px;
|
|
63
|
+
margin: 0 auto;
|
|
64
|
+
padding: 1.25rem;
|
|
65
|
+
}
|
|
66
|
+
.hero {
|
|
67
|
+
margin-bottom: 1rem;
|
|
68
|
+
}
|
|
69
|
+
.hero h1 {
|
|
70
|
+
margin: 0 0 0.35rem;
|
|
71
|
+
font-size: 2rem;
|
|
72
|
+
}
|
|
73
|
+
.hero p,
|
|
74
|
+
.muted {
|
|
75
|
+
color: var(--muted);
|
|
76
|
+
}
|
|
77
|
+
.filters,
|
|
78
|
+
.stats,
|
|
79
|
+
.panel-grid,
|
|
80
|
+
.compare-grid {
|
|
81
|
+
display: grid;
|
|
82
|
+
gap: 1rem;
|
|
83
|
+
}
|
|
84
|
+
.filters {
|
|
85
|
+
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
|
|
86
|
+
margin-bottom: 1rem;
|
|
87
|
+
}
|
|
88
|
+
input,
|
|
89
|
+
select {
|
|
90
|
+
width: 100%;
|
|
91
|
+
padding: 0.75rem 0.85rem;
|
|
92
|
+
border: 1px solid var(--line);
|
|
93
|
+
border-radius: 10px;
|
|
94
|
+
background: var(--panel);
|
|
95
|
+
}
|
|
96
|
+
.stats {
|
|
97
|
+
grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
|
|
98
|
+
margin-bottom: 1rem;
|
|
99
|
+
}
|
|
100
|
+
.stat,
|
|
101
|
+
.panel,
|
|
102
|
+
.empty {
|
|
103
|
+
background: var(--panel);
|
|
104
|
+
border: 1px solid var(--line);
|
|
105
|
+
border-radius: 16px;
|
|
106
|
+
padding: 1rem;
|
|
107
|
+
}
|
|
108
|
+
.stat-value {
|
|
109
|
+
font-size: 1.4rem;
|
|
110
|
+
margin-top: 0.25rem;
|
|
111
|
+
}
|
|
112
|
+
.panel-grid,
|
|
113
|
+
.compare-grid {
|
|
114
|
+
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
|
|
115
|
+
margin-bottom: 1rem;
|
|
116
|
+
}
|
|
117
|
+
.table {
|
|
118
|
+
width: 100%;
|
|
119
|
+
border-collapse: collapse;
|
|
120
|
+
background: var(--panel);
|
|
121
|
+
border: 1px solid var(--line);
|
|
122
|
+
border-radius: 16px;
|
|
123
|
+
overflow: hidden;
|
|
124
|
+
}
|
|
125
|
+
.table th,
|
|
126
|
+
.table td {
|
|
127
|
+
text-align: left;
|
|
128
|
+
padding: 0.85rem;
|
|
129
|
+
border-bottom: 1px solid var(--line);
|
|
130
|
+
vertical-align: top;
|
|
131
|
+
}
|
|
132
|
+
.table th {
|
|
133
|
+
font-family: "IBM Plex Mono", monospace;
|
|
134
|
+
font-size: 0.8rem;
|
|
135
|
+
text-transform: uppercase;
|
|
136
|
+
letter-spacing: 0.04em;
|
|
137
|
+
color: var(--muted);
|
|
138
|
+
}
|
|
139
|
+
.pill {
|
|
140
|
+
display: inline-block;
|
|
141
|
+
padding: 0.2rem 0.55rem;
|
|
142
|
+
border-radius: 999px;
|
|
143
|
+
font-size: 0.8rem;
|
|
144
|
+
font-weight: 700;
|
|
145
|
+
text-transform: uppercase;
|
|
146
|
+
letter-spacing: 0.04em;
|
|
147
|
+
}
|
|
148
|
+
.pill.pass {
|
|
149
|
+
background: rgba(30, 106, 66, 0.12);
|
|
150
|
+
color: var(--pass);
|
|
151
|
+
}
|
|
152
|
+
.pill.fail {
|
|
153
|
+
background: rgba(154, 44, 31, 0.12);
|
|
154
|
+
color: var(--fail);
|
|
155
|
+
}
|
|
156
|
+
.pill.error {
|
|
157
|
+
background: rgba(91, 30, 114, 0.12);
|
|
158
|
+
color: var(--error);
|
|
159
|
+
}
|
|
160
|
+
.stack,
|
|
161
|
+
.timeline {
|
|
162
|
+
display: grid;
|
|
163
|
+
gap: 0.75rem;
|
|
164
|
+
padding-left: 1rem;
|
|
165
|
+
}
|
|
166
|
+
.timeline.compact {
|
|
167
|
+
gap: 0.35rem;
|
|
168
|
+
}
|
|
169
|
+
@media (max-width: 720px) {
|
|
170
|
+
.table {
|
|
171
|
+
display: block;
|
|
172
|
+
overflow-x: auto;
|
|
173
|
+
}
|
|
174
|
+
}
|