@nutteen/conductor-ui 0.1.0
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/README.md +383 -0
- package/bin/conductor-ui.js +17 -0
- package/dist/main/index.js +1608 -0
- package/dist/preload/index.cjs +70 -0
- package/dist/renderer/assets/index-Chkena_6.css +975 -0
- package/dist/renderer/assets/index-DJ8N8Wk7.js +14218 -0
- package/dist/renderer/index.html +22 -0
- package/package.json +54 -0
|
@@ -0,0 +1,975 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* The tracker's own design tokens, so the control room and the web app read as one
|
|
3
|
+
* product. Values mirror `apps/web/src/styles.css`; this file is standalone because
|
|
4
|
+
* the two apps share no build, and copying ~30 custom properties is cheaper than
|
|
5
|
+
* making a viewer depend on the web workspace.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
:root {
|
|
9
|
+
--color-brand: #a100ff;
|
|
10
|
+
--color-brand-soft: #e1b6ff;
|
|
11
|
+
--color-on-brand: #f9e8ff;
|
|
12
|
+
--color-shell: #0d0e11;
|
|
13
|
+
--color-bg: #121316;
|
|
14
|
+
--color-surface-low: #1a1b1f;
|
|
15
|
+
--color-surface: #1e2023;
|
|
16
|
+
--color-surface-high: #292a2d;
|
|
17
|
+
--color-surface-highest: #343538;
|
|
18
|
+
--color-border: #4e4256;
|
|
19
|
+
--color-border-soft: #27242c;
|
|
20
|
+
--color-text: #e3e2e6;
|
|
21
|
+
--color-muted: #d1c1d8;
|
|
22
|
+
--color-danger: #ffb4ab;
|
|
23
|
+
--color-success: #8fe3b0;
|
|
24
|
+
/* Promoting a colour this file already used twice, not inventing one: it was the
|
|
25
|
+
literal behind `.logrow--tracker_write_refused`. Used for the states that are
|
|
26
|
+
neither running nor off — stale, and the transitional ones. */
|
|
27
|
+
--color-warning: #ffcf9a;
|
|
28
|
+
--color-focus: rgba(225, 182, 255, 0.46);
|
|
29
|
+
|
|
30
|
+
/*
|
|
31
|
+
* Graph-only colours, because a node-link diagram is the one place in this app
|
|
32
|
+
* where the boxes and lines ARE the content.
|
|
33
|
+
*
|
|
34
|
+
* The shared palette draws borders at about 2:1 against their background, which
|
|
35
|
+
* is right for tables and panels — the text carries the meaning and a loud rule
|
|
36
|
+
* would only shout. In the graph it measured 1.05:1 for a node box against the
|
|
37
|
+
* canvas and 1.79:1 for an edge, i.e. structure you could not see. These hit the
|
|
38
|
+
* 3:1 WCAG 1.4.11 floor for graphical objects (3.5:1 and 4.6:1 on `--graph-bg`)
|
|
39
|
+
* without touching the tokens the rest of the Control Room shares with the web
|
|
40
|
+
* app.
|
|
41
|
+
*/
|
|
42
|
+
--graph-bg: var(--color-shell);
|
|
43
|
+
--graph-line: #6f6478;
|
|
44
|
+
--graph-line-strong: #8d8296;
|
|
45
|
+
--graph-fill: var(--color-surface);
|
|
46
|
+
--graph-fill-high: var(--color-surface-high);
|
|
47
|
+
|
|
48
|
+
/*
|
|
49
|
+
* Status tints. Named rather than inlined because a low-alpha wash of a
|
|
50
|
+
* light-on-dark colour is invisible over a light surface: `rgba(143,227,176,.16)`
|
|
51
|
+
* is a badge in dark mode and nothing at all in light.
|
|
52
|
+
*/
|
|
53
|
+
--tint-brand: rgba(161, 0, 255, 0.1);
|
|
54
|
+
--tint-brand-strong: rgba(161, 0, 255, 0.22);
|
|
55
|
+
--tint-accent: rgba(225, 182, 255, 0.11);
|
|
56
|
+
--tint-success: rgba(143, 227, 176, 0.16);
|
|
57
|
+
--tint-warning: rgba(255, 207, 154, 0.16);
|
|
58
|
+
--tint-danger: rgba(255, 180, 171, 0.16);
|
|
59
|
+
--tint-danger-weak: rgba(255, 180, 171, 0.1);
|
|
60
|
+
|
|
61
|
+
color-scheme: dark;
|
|
62
|
+
|
|
63
|
+
--space-1: 4px;
|
|
64
|
+
--space-2: 8px;
|
|
65
|
+
--space-3: 12px;
|
|
66
|
+
--space-4: 16px;
|
|
67
|
+
--space-5: 20px;
|
|
68
|
+
--space-6: 24px;
|
|
69
|
+
--space-8: 32px;
|
|
70
|
+
|
|
71
|
+
--radius-sm: 2px;
|
|
72
|
+
--radius-md: 4px;
|
|
73
|
+
--radius-lg: 8px;
|
|
74
|
+
|
|
75
|
+
--sidebar-width: 300px;
|
|
76
|
+
--topbar-height: 48px;
|
|
77
|
+
|
|
78
|
+
--font-sans: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
79
|
+
--font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/*
|
|
83
|
+
* Light mode. The shared values mirror `apps/web`'s own `html[data-theme="light"]`
|
|
84
|
+
* block, for the same reason this file copies the dark ones: the two apps share no
|
|
85
|
+
* build, and duplicating tokens is cheaper than making a viewer depend on the web
|
|
86
|
+
* workspace. Everything below that line is Control Room only.
|
|
87
|
+
*/
|
|
88
|
+
html[data-theme="light"] {
|
|
89
|
+
color-scheme: light;
|
|
90
|
+
--color-brand: #7b00cc;
|
|
91
|
+
--color-brand-soft: #7b00cc;
|
|
92
|
+
--color-on-brand: #ffffff;
|
|
93
|
+
--color-shell: #f0f0f3;
|
|
94
|
+
--color-bg: #f5f5f8;
|
|
95
|
+
--color-surface-low: #ebebee;
|
|
96
|
+
--color-surface: #e4e4e7;
|
|
97
|
+
--color-surface-high: #d8d8db;
|
|
98
|
+
--color-surface-highest: #ccccce;
|
|
99
|
+
--color-border: #b0a0bc;
|
|
100
|
+
--color-border-soft: #d4ceda;
|
|
101
|
+
--color-text: #1a1a1e;
|
|
102
|
+
--color-muted: #4a3d52;
|
|
103
|
+
--color-danger: #b3261e;
|
|
104
|
+
--color-success: #1e6e3f;
|
|
105
|
+
--color-focus: rgba(123, 0, 204, 0.3);
|
|
106
|
+
|
|
107
|
+
/* No counterpart in the web app: `--color-warning` was promoted here for the
|
|
108
|
+
states that are neither running nor off. Darkened to carry on a light surface. */
|
|
109
|
+
--color-warning: #8a5a00;
|
|
110
|
+
|
|
111
|
+
/* `--graph-bg` and the fills follow the surface tokens above on their own, being
|
|
112
|
+
`var()` references. Only the strokes need their own value: the dark ones are
|
|
113
|
+
lightened *away* from a dark canvas, which is the wrong direction here. 5.2:1
|
|
114
|
+
and 8.6:1 against `--graph-bg`. */
|
|
115
|
+
--graph-line: #6d5f78;
|
|
116
|
+
--graph-line-strong: #4b3f55;
|
|
117
|
+
|
|
118
|
+
--tint-brand: rgba(123, 0, 204, 0.1);
|
|
119
|
+
--tint-brand-strong: rgba(123, 0, 204, 0.18);
|
|
120
|
+
--tint-accent: rgba(123, 0, 204, 0.1);
|
|
121
|
+
--tint-success: rgba(30, 110, 63, 0.14);
|
|
122
|
+
--tint-warning: rgba(138, 90, 0, 0.16);
|
|
123
|
+
--tint-danger: rgba(179, 38, 30, 0.12);
|
|
124
|
+
--tint-danger-weak: rgba(179, 38, 30, 0.08);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
* {
|
|
128
|
+
box-sizing: border-box;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
html,
|
|
132
|
+
body,
|
|
133
|
+
#root {
|
|
134
|
+
height: 100%;
|
|
135
|
+
margin: 0;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
body {
|
|
139
|
+
background: var(--color-shell);
|
|
140
|
+
color: var(--color-text);
|
|
141
|
+
font-family: var(--font-sans);
|
|
142
|
+
font-size: 14px;
|
|
143
|
+
line-height: 1.5;
|
|
144
|
+
-webkit-font-smoothing: antialiased;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
button {
|
|
148
|
+
font: inherit;
|
|
149
|
+
color: inherit;
|
|
150
|
+
background: none;
|
|
151
|
+
border: none;
|
|
152
|
+
cursor: pointer;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
::-webkit-scrollbar {
|
|
156
|
+
width: 10px;
|
|
157
|
+
height: 10px;
|
|
158
|
+
}
|
|
159
|
+
::-webkit-scrollbar-thumb {
|
|
160
|
+
background: var(--color-surface-highest);
|
|
161
|
+
border-radius: var(--radius-lg);
|
|
162
|
+
}
|
|
163
|
+
::-webkit-scrollbar-track {
|
|
164
|
+
background: transparent;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
.mono {
|
|
168
|
+
font-family: var(--font-mono);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/* --- shell ------------------------------------------------------------- */
|
|
172
|
+
|
|
173
|
+
.app {
|
|
174
|
+
display: grid;
|
|
175
|
+
grid-template-columns: var(--sidebar-width) 1fr;
|
|
176
|
+
grid-template-rows: var(--topbar-height) 1fr;
|
|
177
|
+
height: 100%;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.topbar {
|
|
181
|
+
grid-column: 1 / -1;
|
|
182
|
+
display: flex;
|
|
183
|
+
align-items: center;
|
|
184
|
+
gap: var(--space-4);
|
|
185
|
+
padding: 0 var(--space-4);
|
|
186
|
+
background: var(--color-surface-low);
|
|
187
|
+
border-bottom: 1px solid var(--color-border-soft);
|
|
188
|
+
/* Leaves room for the traffic lights under `titleBarStyle: hiddenInset`. */
|
|
189
|
+
padding-left: 88px;
|
|
190
|
+
-webkit-app-region: drag;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.topbar > * {
|
|
194
|
+
-webkit-app-region: no-drag;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
.topbar__title {
|
|
198
|
+
font-weight: 600;
|
|
199
|
+
letter-spacing: 0.01em;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.topbar__spacer {
|
|
203
|
+
flex: 1;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.select,
|
|
207
|
+
.button {
|
|
208
|
+
background: var(--color-surface);
|
|
209
|
+
border: 1px solid var(--color-border-soft);
|
|
210
|
+
border-radius: var(--radius-md);
|
|
211
|
+
color: var(--color-text);
|
|
212
|
+
padding: var(--space-1) var(--space-3);
|
|
213
|
+
font-size: 13px;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.button:hover:not(:disabled) {
|
|
217
|
+
background: var(--color-surface-high);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.button:disabled {
|
|
221
|
+
opacity: 0.5;
|
|
222
|
+
cursor: default;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.button--primary {
|
|
226
|
+
background: var(--color-brand);
|
|
227
|
+
color: var(--color-on-brand);
|
|
228
|
+
border-color: transparent;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
:focus-visible {
|
|
232
|
+
outline: 2px solid var(--color-focus);
|
|
233
|
+
outline-offset: 1px;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/* --- liveness ---------------------------------------------------------- */
|
|
237
|
+
|
|
238
|
+
.liveness {
|
|
239
|
+
display: inline-flex;
|
|
240
|
+
align-items: center;
|
|
241
|
+
gap: var(--space-2);
|
|
242
|
+
font-family: var(--font-mono);
|
|
243
|
+
font-size: 12px;
|
|
244
|
+
color: var(--color-muted);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
.liveness__dot {
|
|
248
|
+
width: 8px;
|
|
249
|
+
height: 8px;
|
|
250
|
+
border-radius: 50%;
|
|
251
|
+
background: var(--color-surface-highest);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
.liveness__dot--running {
|
|
255
|
+
background: var(--color-success);
|
|
256
|
+
box-shadow: 0 0 0 3px rgba(143, 227, 176, 0.18);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/* Neither running nor off. `--color-brand-soft` is `.badge--running` and would read
|
|
260
|
+
as "running"; `--color-muted` reads as "off". */
|
|
261
|
+
.liveness__dot--stale,
|
|
262
|
+
.liveness__dot--draining,
|
|
263
|
+
.liveness__dot--starting,
|
|
264
|
+
.liveness__dot--stopping,
|
|
265
|
+
.liveness__dot--restarting {
|
|
266
|
+
background: var(--color-warning);
|
|
267
|
+
box-shadow: 0 0 0 3px rgba(255, 207, 154, 0.18);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.liveness__dot--starting,
|
|
271
|
+
.liveness__dot--stopping,
|
|
272
|
+
.liveness__dot--restarting {
|
|
273
|
+
animation: liveness-pulse 1.4s ease-in-out infinite;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
@keyframes liveness-pulse {
|
|
277
|
+
50% {
|
|
278
|
+
opacity: 0.35;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/*
|
|
283
|
+
* Both selectors, because `-webkit-app-region` does not inherit: `.topbar > *` gives
|
|
284
|
+
* this wrapper `no-drag`, but its children would fall back to the topbar's `drag` and
|
|
285
|
+
* swallow their own clicks.
|
|
286
|
+
*/
|
|
287
|
+
.topbar__lifecycle,
|
|
288
|
+
.topbar__lifecycle > * {
|
|
289
|
+
-webkit-app-region: no-drag;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.topbar__lifecycle {
|
|
293
|
+
display: inline-flex;
|
|
294
|
+
align-items: center;
|
|
295
|
+
gap: var(--space-2);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/* --- lifecycle output --------------------------------------------------- */
|
|
299
|
+
|
|
300
|
+
.lifecycle__argv,
|
|
301
|
+
.lifecycle__stderr {
|
|
302
|
+
font-size: 12px;
|
|
303
|
+
color: var(--color-muted);
|
|
304
|
+
white-space: pre-wrap;
|
|
305
|
+
word-break: break-word;
|
|
306
|
+
margin: var(--space-2) 0 0;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/* --- modal -------------------------------------------------------------- */
|
|
310
|
+
|
|
311
|
+
.modal {
|
|
312
|
+
position: fixed;
|
|
313
|
+
inset: 0;
|
|
314
|
+
display: grid;
|
|
315
|
+
place-items: center;
|
|
316
|
+
z-index: 20;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.modal__backdrop {
|
|
320
|
+
position: absolute;
|
|
321
|
+
inset: 0;
|
|
322
|
+
background: rgba(13, 14, 17, 0.72);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
.modal__panel {
|
|
326
|
+
position: relative;
|
|
327
|
+
width: min(760px, calc(100vw - var(--space-8)));
|
|
328
|
+
max-height: calc(100vh - var(--space-8));
|
|
329
|
+
overflow-y: auto;
|
|
330
|
+
background: var(--color-surface);
|
|
331
|
+
border: 1px solid var(--color-border);
|
|
332
|
+
border-radius: var(--radius-lg);
|
|
333
|
+
padding: var(--space-5);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
.modal__title {
|
|
337
|
+
margin: 0 0 var(--space-3);
|
|
338
|
+
font-size: 16px;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
.modal__lede {
|
|
342
|
+
margin: 0 0 var(--space-3);
|
|
343
|
+
color: var(--color-muted);
|
|
344
|
+
font-size: 13px;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
.modal__section {
|
|
348
|
+
margin-top: var(--space-4);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.modal__checks {
|
|
352
|
+
margin-top: var(--space-2);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.modal__detail {
|
|
356
|
+
font-size: 12px;
|
|
357
|
+
color: var(--color-muted);
|
|
358
|
+
white-space: pre-wrap;
|
|
359
|
+
word-break: break-word;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
.modal__actions {
|
|
363
|
+
display: flex;
|
|
364
|
+
justify-content: flex-end;
|
|
365
|
+
gap: var(--space-2);
|
|
366
|
+
margin-top: var(--space-5);
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
/* --- config panel ------------------------------------------------------- */
|
|
370
|
+
|
|
371
|
+
.flows {
|
|
372
|
+
display: flex;
|
|
373
|
+
flex-direction: column;
|
|
374
|
+
gap: var(--space-4);
|
|
375
|
+
padding: var(--space-4);
|
|
376
|
+
overflow-y: auto;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
.flows__header {
|
|
380
|
+
display: flex;
|
|
381
|
+
align-items: flex-start;
|
|
382
|
+
justify-content: space-between;
|
|
383
|
+
gap: var(--space-4);
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
.flows__path {
|
|
387
|
+
font-size: 12px;
|
|
388
|
+
word-break: break-all;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
.flows__note {
|
|
392
|
+
font-size: 12px;
|
|
393
|
+
color: var(--color-warning);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
.flows__flow {
|
|
397
|
+
border: 1px solid var(--color-border-soft);
|
|
398
|
+
border-radius: var(--radius-md);
|
|
399
|
+
padding: var(--space-3) var(--space-4);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
.flows__flow-header {
|
|
403
|
+
display: flex;
|
|
404
|
+
align-items: baseline;
|
|
405
|
+
gap: var(--space-3);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
.flows__input {
|
|
409
|
+
width: 100%;
|
|
410
|
+
font-family: var(--font-mono);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
.flows__resolved,
|
|
414
|
+
.flows__comment {
|
|
415
|
+
font-size: 12px;
|
|
416
|
+
color: var(--color-muted);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
.flows__comment {
|
|
420
|
+
white-space: pre-wrap;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
.flows__preview {
|
|
424
|
+
border: 1px solid var(--color-border);
|
|
425
|
+
border-radius: var(--radius-md);
|
|
426
|
+
padding: var(--space-3) var(--space-4);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
.flows__diff {
|
|
430
|
+
background: var(--color-surface-low);
|
|
431
|
+
border-radius: var(--radius-md);
|
|
432
|
+
padding: var(--space-3);
|
|
433
|
+
font-size: 12px;
|
|
434
|
+
overflow-x: auto;
|
|
435
|
+
white-space: pre;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/* --- sidebar ----------------------------------------------------------- */
|
|
439
|
+
|
|
440
|
+
.sidebar {
|
|
441
|
+
background: var(--color-surface-low);
|
|
442
|
+
border-right: 1px solid var(--color-border-soft);
|
|
443
|
+
overflow-y: auto;
|
|
444
|
+
display: flex;
|
|
445
|
+
flex-direction: column;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
.sidebar__section {
|
|
449
|
+
padding: var(--space-3) var(--space-4);
|
|
450
|
+
border-bottom: 1px solid var(--color-border-soft);
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.sidebar__label {
|
|
454
|
+
font-family: var(--font-mono);
|
|
455
|
+
font-size: 11px;
|
|
456
|
+
text-transform: uppercase;
|
|
457
|
+
letter-spacing: 0.08em;
|
|
458
|
+
color: var(--color-muted);
|
|
459
|
+
margin-bottom: var(--space-2);
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
.ticket {
|
|
463
|
+
display: block;
|
|
464
|
+
width: 100%;
|
|
465
|
+
text-align: left;
|
|
466
|
+
padding: var(--space-3) var(--space-4);
|
|
467
|
+
border-bottom: 1px solid var(--color-border-soft);
|
|
468
|
+
border-left: 2px solid transparent;
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
.ticket:hover {
|
|
472
|
+
background: var(--color-surface-high);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
.ticket--selected {
|
|
476
|
+
background: var(--color-surface);
|
|
477
|
+
border-left-color: var(--color-brand-soft);
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
.ticket__head {
|
|
481
|
+
display: flex;
|
|
482
|
+
align-items: baseline;
|
|
483
|
+
gap: var(--space-2);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
.ticket__key {
|
|
487
|
+
font-family: var(--font-mono);
|
|
488
|
+
font-size: 12px;
|
|
489
|
+
color: var(--color-brand-soft);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
.ticket__title {
|
|
493
|
+
font-size: 13px;
|
|
494
|
+
overflow: hidden;
|
|
495
|
+
text-overflow: ellipsis;
|
|
496
|
+
white-space: nowrap;
|
|
497
|
+
color: var(--color-text);
|
|
498
|
+
margin-top: 2px;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
.ticket__meta {
|
|
502
|
+
display: flex;
|
|
503
|
+
flex-wrap: wrap;
|
|
504
|
+
gap: var(--space-2);
|
|
505
|
+
margin-top: var(--space-2);
|
|
506
|
+
font-family: var(--font-mono);
|
|
507
|
+
font-size: 11px;
|
|
508
|
+
color: var(--color-muted);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
/* --- badges ------------------------------------------------------------ */
|
|
512
|
+
|
|
513
|
+
.badge {
|
|
514
|
+
display: inline-block;
|
|
515
|
+
padding: 1px var(--space-2);
|
|
516
|
+
border-radius: var(--radius-sm);
|
|
517
|
+
font-family: var(--font-mono);
|
|
518
|
+
font-size: 11px;
|
|
519
|
+
background: var(--color-surface-high);
|
|
520
|
+
color: var(--color-muted);
|
|
521
|
+
white-space: nowrap;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
.badge--running {
|
|
525
|
+
background: var(--tint-brand-strong);
|
|
526
|
+
color: var(--color-brand-soft);
|
|
527
|
+
}
|
|
528
|
+
.badge--completed {
|
|
529
|
+
background: var(--tint-success);
|
|
530
|
+
color: var(--color-success);
|
|
531
|
+
}
|
|
532
|
+
.badge--failed,
|
|
533
|
+
.badge--escalated {
|
|
534
|
+
background: var(--tint-danger);
|
|
535
|
+
color: var(--color-danger);
|
|
536
|
+
}
|
|
537
|
+
.badge--stale,
|
|
538
|
+
.badge--waiting {
|
|
539
|
+
background: var(--tint-accent);
|
|
540
|
+
color: var(--color-brand-soft);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
/* A ticket dispatched at or past `agent.max_attempts`' default. Warning, not danger:
|
|
544
|
+
the third dispatch may be legitimate rework — it is worth a glance, not an alarm. */
|
|
545
|
+
.badge--runaway {
|
|
546
|
+
background: var(--tint-warning);
|
|
547
|
+
color: var(--color-warning);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/* Preflight rows. After `.badge` so the base `color` does not win on equal
|
|
551
|
+
specificity. */
|
|
552
|
+
.badge--pass {
|
|
553
|
+
background: var(--tint-success);
|
|
554
|
+
color: var(--color-success);
|
|
555
|
+
}
|
|
556
|
+
.badge--warn {
|
|
557
|
+
background: var(--tint-warning);
|
|
558
|
+
color: var(--color-warning);
|
|
559
|
+
}
|
|
560
|
+
.badge--fail {
|
|
561
|
+
background: var(--tint-danger);
|
|
562
|
+
color: var(--color-danger);
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
/* --- main -------------------------------------------------------------- */
|
|
566
|
+
|
|
567
|
+
.main {
|
|
568
|
+
display: flex;
|
|
569
|
+
flex-direction: column;
|
|
570
|
+
overflow: hidden;
|
|
571
|
+
background: var(--color-bg);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
.tabs {
|
|
575
|
+
display: flex;
|
|
576
|
+
gap: var(--space-1);
|
|
577
|
+
padding: 0 var(--space-4);
|
|
578
|
+
background: var(--color-surface-low);
|
|
579
|
+
border-bottom: 1px solid var(--color-border-soft);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
.tab {
|
|
583
|
+
padding: var(--space-3) var(--space-4);
|
|
584
|
+
font-size: 13px;
|
|
585
|
+
color: var(--color-muted);
|
|
586
|
+
border-bottom: 2px solid transparent;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
.tab--active {
|
|
590
|
+
color: var(--color-text);
|
|
591
|
+
border-bottom-color: var(--color-brand-soft);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
.panel {
|
|
595
|
+
flex: 1;
|
|
596
|
+
overflow: auto;
|
|
597
|
+
padding: var(--space-5);
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
.empty {
|
|
601
|
+
color: var(--color-muted);
|
|
602
|
+
padding: var(--space-8);
|
|
603
|
+
text-align: center;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/* --- diagnostics ------------------------------------------------------- */
|
|
607
|
+
|
|
608
|
+
.diagnostics {
|
|
609
|
+
margin-bottom: var(--space-4);
|
|
610
|
+
display: flex;
|
|
611
|
+
flex-direction: column;
|
|
612
|
+
gap: var(--space-2);
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
.diagnostic {
|
|
616
|
+
border-radius: var(--radius-md);
|
|
617
|
+
padding: var(--space-3);
|
|
618
|
+
font-family: var(--font-mono);
|
|
619
|
+
font-size: 12px;
|
|
620
|
+
white-space: pre-wrap;
|
|
621
|
+
border-left: 3px solid var(--color-danger);
|
|
622
|
+
background: var(--tint-danger-weak);
|
|
623
|
+
color: var(--color-danger);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
.diagnostic--warning {
|
|
627
|
+
border-left-color: var(--color-brand-soft);
|
|
628
|
+
background: var(--tint-accent);
|
|
629
|
+
color: var(--color-brand-soft);
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/* --- graph ------------------------------------------------------------- */
|
|
633
|
+
|
|
634
|
+
.graph {
|
|
635
|
+
position: relative;
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
/*
|
|
639
|
+
* A 9-stage pipeline at readable type is wider than the panel. Scrolling beats
|
|
640
|
+
* shrinking node text to ~5px, which is where fitting the canvas into ~1130px lands.
|
|
641
|
+
* Scoped to the canvas: `.graph` also holds the toolbar, the legend and the run
|
|
642
|
+
* inspector, and none of those should move when the cursor is scrolled into view.
|
|
643
|
+
*/
|
|
644
|
+
.graph__viewport {
|
|
645
|
+
overflow-x: auto;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
.graph__toolbar {
|
|
649
|
+
display: flex;
|
|
650
|
+
align-items: center;
|
|
651
|
+
gap: var(--space-3);
|
|
652
|
+
margin-bottom: var(--space-3);
|
|
653
|
+
font-family: var(--font-mono);
|
|
654
|
+
font-size: 12px;
|
|
655
|
+
color: var(--color-muted);
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
.graph__canvas {
|
|
659
|
+
background: var(--graph-bg);
|
|
660
|
+
border: 1px solid var(--color-border-soft);
|
|
661
|
+
border-radius: var(--radius-lg);
|
|
662
|
+
display: block;
|
|
663
|
+
/* Fit to the panel, with a floor. `max-width` and `min-width` come from the
|
|
664
|
+
layout as inline style, so this stays pure CSS: no ResizeObserver, no
|
|
665
|
+
measurement state, no new component lifecycle. */
|
|
666
|
+
width: 100%;
|
|
667
|
+
height: auto;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/*
|
|
671
|
+
* Kind is carried by the dash pattern and the fill, not by stroke *strength* — a
|
|
672
|
+
* node you cannot see the outline of is not a subtler node, it is a missing one.
|
|
673
|
+
*/
|
|
674
|
+
.gnode__box {
|
|
675
|
+
fill: var(--graph-fill);
|
|
676
|
+
stroke: var(--graph-line);
|
|
677
|
+
stroke-width: 1.25;
|
|
678
|
+
rx: 6;
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
.gnode--agent .gnode__box {
|
|
682
|
+
stroke: var(--graph-line-strong);
|
|
683
|
+
}
|
|
684
|
+
.gnode--shell .gnode__box {
|
|
685
|
+
stroke-dasharray: 4 3;
|
|
686
|
+
}
|
|
687
|
+
.gnode--builtin .gnode__box {
|
|
688
|
+
fill: var(--graph-fill-high);
|
|
689
|
+
stroke: var(--graph-line-strong);
|
|
690
|
+
}
|
|
691
|
+
.gnode--sentinel .gnode__box {
|
|
692
|
+
fill: transparent;
|
|
693
|
+
stroke-dasharray: 2 4;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
.gnode--visited .gnode__box {
|
|
697
|
+
stroke: var(--color-brand-soft);
|
|
698
|
+
fill: var(--tint-brand);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
.gnode--current .gnode__box {
|
|
702
|
+
stroke: var(--color-brand-soft);
|
|
703
|
+
stroke-width: 2.5;
|
|
704
|
+
fill: var(--tint-brand-strong);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
.gnode--failed .gnode__box {
|
|
708
|
+
stroke: var(--color-danger);
|
|
709
|
+
stroke-width: 2;
|
|
710
|
+
fill: var(--tint-danger-weak);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
.gnode--flagged .gnode__box {
|
|
714
|
+
stroke: var(--color-danger);
|
|
715
|
+
stroke-width: 2;
|
|
716
|
+
stroke-dasharray: 5 3;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
.gnode--selected .gnode__box {
|
|
720
|
+
stroke: var(--color-brand-soft);
|
|
721
|
+
stroke-width: 2;
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
.gnode__name {
|
|
725
|
+
fill: var(--color-text);
|
|
726
|
+
font-family: var(--font-mono);
|
|
727
|
+
font-size: 12px;
|
|
728
|
+
font-weight: 500;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
.gnode__sub {
|
|
732
|
+
fill: var(--color-muted);
|
|
733
|
+
font-family: var(--font-mono);
|
|
734
|
+
font-size: 10px;
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
.gnode__visits {
|
|
738
|
+
fill: var(--color-brand-soft);
|
|
739
|
+
font-family: var(--font-mono);
|
|
740
|
+
font-size: 10px;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
/**
|
|
744
|
+
* How many walkers are inside this one declared node right now.
|
|
745
|
+
*
|
|
746
|
+
* Without it a 3-way `map_over` is pixel-identical to a 1-way one: the declared graph
|
|
747
|
+
* is drawn once and branches are counts and classes ON it, never new boxes.
|
|
748
|
+
*/
|
|
749
|
+
.gnode__branches {
|
|
750
|
+
fill: var(--color-brand-soft);
|
|
751
|
+
font-family: var(--font-mono);
|
|
752
|
+
font-size: 10px;
|
|
753
|
+
font-weight: 600;
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
/* A fan-out origin and its join, marked on the declared graph so the region reads as
|
|
757
|
+
one shape rather than as unrelated parallel boxes. */
|
|
758
|
+
.gnode--fanout .gnode__box,
|
|
759
|
+
.gnode--join .gnode__box {
|
|
760
|
+
stroke-dasharray: 2 2;
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
.gnode {
|
|
764
|
+
cursor: pointer;
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
.gedge__line {
|
|
768
|
+
fill: none;
|
|
769
|
+
stroke: var(--graph-line);
|
|
770
|
+
stroke-width: 1.4;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
.gedge--back .gedge__line {
|
|
774
|
+
stroke-dasharray: 5 4;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
/* A spoke of a fan-out edge: one authored routing decision drawn as N lines, so it
|
|
778
|
+
reads as a fork rather than as N independent conditions. */
|
|
779
|
+
.gedge--fanout .gedge__line {
|
|
780
|
+
stroke-dasharray: 1 3;
|
|
781
|
+
stroke-width: 1.8;
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
.gedge--error .gedge__line {
|
|
785
|
+
stroke: var(--color-danger);
|
|
786
|
+
opacity: 0.8;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
.gedge--taken .gedge__line {
|
|
790
|
+
stroke: var(--color-brand-soft);
|
|
791
|
+
stroke-width: 2.25;
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
.gedge--exhausted .gedge__line {
|
|
795
|
+
stroke: var(--color-danger);
|
|
796
|
+
stroke-width: 2.25;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
/* A terminal stub is marked by its length and its end bar, not by being faint —
|
|
800
|
+
fading it was the one place this file made the legibility problem worse. */
|
|
801
|
+
.gedge--stub .gedge__line {
|
|
802
|
+
stroke-dasharray: none;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
.gedge__label {
|
|
806
|
+
fill: var(--color-muted);
|
|
807
|
+
font-family: var(--font-mono);
|
|
808
|
+
font-size: 10px;
|
|
809
|
+
}
|
|
810
|
+
|
|
811
|
+
.gedge--taken .gedge__label {
|
|
812
|
+
fill: var(--color-brand-soft);
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
.gedge__label-bg {
|
|
816
|
+
fill: var(--graph-bg);
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
.graph__legend {
|
|
820
|
+
display: flex;
|
|
821
|
+
flex-wrap: wrap;
|
|
822
|
+
gap: var(--space-4);
|
|
823
|
+
margin-top: var(--space-3);
|
|
824
|
+
font-family: var(--font-mono);
|
|
825
|
+
font-size: 11px;
|
|
826
|
+
color: var(--color-muted);
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
/* --- inspector / tables ------------------------------------------------ */
|
|
830
|
+
|
|
831
|
+
.inspector {
|
|
832
|
+
margin-top: var(--space-4);
|
|
833
|
+
background: var(--color-surface);
|
|
834
|
+
border: 1px solid var(--color-border-soft);
|
|
835
|
+
border-radius: var(--radius-lg);
|
|
836
|
+
padding: var(--space-4);
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
.table {
|
|
840
|
+
width: 100%;
|
|
841
|
+
border-collapse: collapse;
|
|
842
|
+
font-size: 13px;
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
.table th {
|
|
846
|
+
text-align: left;
|
|
847
|
+
font-family: var(--font-mono);
|
|
848
|
+
font-size: 11px;
|
|
849
|
+
text-transform: uppercase;
|
|
850
|
+
letter-spacing: 0.06em;
|
|
851
|
+
color: var(--color-muted);
|
|
852
|
+
font-weight: 500;
|
|
853
|
+
padding: var(--space-2) var(--space-3);
|
|
854
|
+
border-bottom: 1px solid var(--color-border-soft);
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
.table td {
|
|
858
|
+
padding: var(--space-2) var(--space-3);
|
|
859
|
+
border-bottom: 1px solid var(--color-border-soft);
|
|
860
|
+
vertical-align: top;
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
.table tr:last-child td {
|
|
864
|
+
border-bottom: none;
|
|
865
|
+
}
|
|
866
|
+
|
|
867
|
+
.value {
|
|
868
|
+
font-family: var(--font-mono);
|
|
869
|
+
font-size: 12px;
|
|
870
|
+
white-space: pre-wrap;
|
|
871
|
+
word-break: break-word;
|
|
872
|
+
margin: 0;
|
|
873
|
+
}
|
|
874
|
+
|
|
875
|
+
.value--unset {
|
|
876
|
+
color: var(--color-muted);
|
|
877
|
+
opacity: 0.7;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
.note {
|
|
881
|
+
color: var(--color-muted);
|
|
882
|
+
font-size: 12px;
|
|
883
|
+
margin: 0 0 var(--space-3);
|
|
884
|
+
}
|
|
885
|
+
|
|
886
|
+
.section-title {
|
|
887
|
+
font-family: var(--font-mono);
|
|
888
|
+
font-size: 11px;
|
|
889
|
+
text-transform: uppercase;
|
|
890
|
+
letter-spacing: 0.08em;
|
|
891
|
+
color: var(--color-muted);
|
|
892
|
+
margin: var(--space-5) 0 var(--space-2);
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
.section-title:first-child {
|
|
896
|
+
margin-top: 0;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
/* --- audit log --------------------------------------------------------- */
|
|
900
|
+
|
|
901
|
+
.filters {
|
|
902
|
+
display: flex;
|
|
903
|
+
flex-wrap: wrap;
|
|
904
|
+
gap: var(--space-2);
|
|
905
|
+
margin-bottom: var(--space-3);
|
|
906
|
+
align-items: center;
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
.log {
|
|
910
|
+
display: flex;
|
|
911
|
+
flex-direction: column;
|
|
912
|
+
gap: 1px;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
.logrow {
|
|
916
|
+
display: grid;
|
|
917
|
+
grid-template-columns: 92px 148px 110px 1fr;
|
|
918
|
+
gap: var(--space-3);
|
|
919
|
+
padding: var(--space-2) var(--space-3);
|
|
920
|
+
background: var(--color-surface);
|
|
921
|
+
font-family: var(--font-mono);
|
|
922
|
+
font-size: 12px;
|
|
923
|
+
align-items: baseline;
|
|
924
|
+
border-left: 2px solid transparent;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
.logrow:hover {
|
|
928
|
+
background: var(--color-surface-high);
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
.logrow--edge_taken {
|
|
932
|
+
border-left-color: var(--color-brand-soft);
|
|
933
|
+
}
|
|
934
|
+
.logrow--node_failed,
|
|
935
|
+
.logrow--worker_exited_abnormal,
|
|
936
|
+
.logrow--turn_failed {
|
|
937
|
+
border-left-color: var(--color-danger);
|
|
938
|
+
}
|
|
939
|
+
.logrow--tracker_write_refused {
|
|
940
|
+
border-left-color: var(--color-warning);
|
|
941
|
+
}
|
|
942
|
+
.logrow--turn_completed {
|
|
943
|
+
border-left-color: var(--color-surface-highest);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
.logrow__time {
|
|
947
|
+
color: var(--color-muted);
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
.logrow__kind {
|
|
951
|
+
color: var(--color-brand-soft);
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
.logrow__node {
|
|
955
|
+
color: var(--color-muted);
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
.logrow__detail {
|
|
959
|
+
color: var(--color-text);
|
|
960
|
+
word-break: break-word;
|
|
961
|
+
}
|
|
962
|
+
|
|
963
|
+
.logrow__detail em {
|
|
964
|
+
color: var(--color-muted);
|
|
965
|
+
font-style: normal;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
.logrow--node_failed .logrow__detail,
|
|
969
|
+
.logrow--worker_exited_abnormal .logrow__detail {
|
|
970
|
+
color: var(--color-danger);
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
.logrow--tracker_write_refused .logrow__detail {
|
|
974
|
+
color: var(--color-warning);
|
|
975
|
+
}
|