nexus-agentd 0.2.5 → 0.3.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.
Files changed (61) hide show
  1. package/README.md +359 -250
  2. package/dist/a2a/runtime.d.ts +7 -1
  3. package/dist/a2a/runtime.js +290 -17
  4. package/dist/acp/runtime.d.ts +5 -1
  5. package/dist/acp/runtime.js +88 -39
  6. package/dist/artifact-store.d.ts +162 -0
  7. package/dist/artifact-store.js +1081 -0
  8. package/dist/cli.js +13 -14
  9. package/dist/completion-contract.js +1 -1
  10. package/dist/config.js +45 -5
  11. package/dist/control-plane-validation.d.ts +54 -0
  12. package/dist/control-plane-validation.js +152 -0
  13. package/dist/control-plane.d.ts +9 -32
  14. package/dist/control-plane.js +52 -158
  15. package/dist/drivers/index.js +12 -0
  16. package/dist/drivers/pi.js +1 -1
  17. package/dist/drivers/stdio.d.ts +4 -1
  18. package/dist/drivers/stdio.js +135 -19
  19. package/dist/events.d.ts +9 -0
  20. package/dist/events.js +17 -4
  21. package/dist/index.d.ts +1 -1
  22. package/dist/index.js +33 -6
  23. package/dist/process-tree.js +15 -6
  24. package/dist/run-store.d.ts +57 -7
  25. package/dist/run-store.js +188 -23
  26. package/dist/server/auth-policy.d.ts +27 -0
  27. package/dist/server/auth-policy.js +143 -0
  28. package/dist/server/connection.d.ts +8 -0
  29. package/dist/server/connection.js +67 -0
  30. package/dist/server/diagnostics.d.ts +40 -0
  31. package/dist/server/diagnostics.js +130 -0
  32. package/dist/server/metrics.d.ts +51 -0
  33. package/dist/server/metrics.js +56 -0
  34. package/dist/server/quota.d.ts +59 -0
  35. package/dist/server/quota.js +176 -0
  36. package/dist/server/validation.d.ts +29 -0
  37. package/dist/server/validation.js +221 -0
  38. package/dist/server.d.ts +3 -0
  39. package/dist/server.js +682 -418
  40. package/dist/session/admin-runs.d.ts +73 -0
  41. package/dist/session/admin-runs.js +297 -0
  42. package/dist/session/admission.d.ts +32 -0
  43. package/dist/session/admission.js +62 -0
  44. package/dist/session/readiness.d.ts +33 -0
  45. package/dist/session/readiness.js +174 -0
  46. package/dist/session-contract.d.ts +1 -0
  47. package/dist/session.d.ts +64 -7
  48. package/dist/session.js +321 -159
  49. package/dist/sse-writer.d.ts +7 -0
  50. package/dist/sse-writer.js +60 -0
  51. package/dist/types.d.ts +44 -2
  52. package/dist/types.js +1 -0
  53. package/dist/webui/app/sources.js +18 -10
  54. package/dist/webui/index.js +11 -11
  55. package/dist/webui/markup.js +69 -66
  56. package/dist/webui/styles.js +791 -616
  57. package/dist/workspace.d.ts +30 -0
  58. package/dist/workspace.js +67 -2
  59. package/examples/client.mjs +102 -0
  60. package/nexus-agentd.example.json +21 -2
  61. package/package.json +6 -3
@@ -1,617 +1,792 @@
1
- export const styles = String.raw `
2
- /* 全局设计约定:间距用 --sp-*、字号用 --fs-*,扩展时不要引入散落的像素值。 */
3
-
4
- :root {
5
- color-scheme: light;
6
- --background: 0 0% 100%;
7
- --foreground: 0 0% 3.9%;
8
- --card: 0 0% 100%;
9
- --card-foreground: 0 0% 3.9%;
10
- --popover: 0 0% 100%;
11
- --popover-foreground: 0 0% 3.9%;
12
- --primary: 0 0% 9%;
13
- --primary-foreground: 0 0% 98%;
14
- --secondary: 0 0% 96.1%;
15
- --secondary-foreground: 0 0% 9%;
16
- --muted: 0 0% 96.1%;
17
- --muted-foreground: 0 0% 45.1%;
18
- --accent: 0 0% 96.1%;
19
- --accent-foreground: 0 0% 9%;
20
- --destructive: 0 84.2% 60.2%;
21
- --destructive-foreground: 0 0% 98%;
22
- --success: 142 76% 36%;
23
- --warning: 32 95% 44%;
24
- --info: 217 91% 60%;
25
- --border: 0 0% 89.8%;
26
- --input: 0 0% 89.8%;
27
- --ring: 0 0% 63.9%;
28
-
29
- --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px;
30
- --sp-5: 20px; --sp-6: 24px; --sp-8: 32px;
31
-
32
- /* 字号阶梯,全站只用这六级:
33
- 2xs 大写微标签(表头 / badge)· xs 辅助说明 · sm 正文与表格
34
- md 面板与 drawer 标题 · lg 页面标题 · stat 统计数字 */
35
- --fs-2xs: 11px; --fs-xs: 12px; --fs-sm: 13px;
36
- --fs-md: 14px; --fs-lg: 16px; --fs-stat: 28px;
37
-
38
- --radius: 6px;
39
- --sidebar-width: 232px;
40
- --gutter: clamp(var(--sp-6), 4vw, 48px);
41
- }
42
-
43
- html[data-theme="dark"] {
44
- color-scheme: dark;
45
- --background: 0 0% 3.9%;
46
- --foreground: 0 0% 98%;
47
- --card: 0 0% 3.9%;
48
- --card-foreground: 0 0% 98%;
49
- --popover: 0 0% 3.9%;
50
- --popover-foreground: 0 0% 98%;
51
- --primary: 0 0% 98%;
52
- --primary-foreground: 0 0% 9%;
53
- --secondary: 0 0% 14.9%;
54
- --secondary-foreground: 0 0% 98%;
55
- --muted: 0 0% 14.9%;
56
- --muted-foreground: 0 0% 63.9%;
57
- --accent: 0 0% 14.9%;
58
- --accent-foreground: 0 0% 98%;
59
- --destructive: 0 62.8% 30.6%;
60
- --destructive-foreground: 0 0% 98%;
61
- --success: 142 71% 45%;
62
- --warning: 38 92% 50%;
63
- --info: 217 91% 65%;
64
- --border: 0 0% 14.9%;
65
- --input: 0 0% 14.9%;
66
- --ring: 0 0% 83.1%;
67
- }
68
-
69
- /* ── Base ─────────────────────────────────────────────────────────── */
70
- *, *::before, *::after { box-sizing: border-box; }
71
- html, body { height: 100%; }
72
- html { scrollbar-gutter: stable; }
73
- body {
74
- margin: 0;
75
- background: hsl(var(--background));
76
- color: hsl(var(--foreground));
77
- font: var(--fs-sm)/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans",
78
- "PingFang SC", "Microsoft YaHei", Helvetica, Arial, sans-serif;
79
- -webkit-font-smoothing: antialiased;
80
- text-rendering: optimizeLegibility;
81
- }
82
- h1, h2, h3, p { margin: 0; }
83
- button, input, select, textarea { font: inherit; color: inherit; }
84
- button { background: none; border: 0; cursor: pointer; padding: 0; }
85
- code, .mono { font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace; }
86
- .hidden { display: none !important; }
87
- .muted { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); }
88
-
89
- :focus-visible {
90
- outline: 2px solid hsl(var(--ring));
91
- outline-offset: 1px;
92
- border-radius: 2px;
93
- }
94
-
95
- ::selection { background: hsl(var(--accent)); color: hsl(var(--accent-foreground)); }
96
-
97
- /* Thin scrollbars */
98
- ::-webkit-scrollbar { width: 10px; height: 10px; }
99
- ::-webkit-scrollbar-thumb { background: hsl(var(--muted-foreground) / .35); border-radius: 8px; border: 3px solid transparent; background-clip: content-box; }
100
- ::-webkit-scrollbar-thumb:hover { background-color: hsl(var(--muted-foreground) / .55); }
101
- ::-webkit-scrollbar-track { background: transparent; }
102
-
103
- /* ── Brand ────────────────────────────────────────────────────────── */
104
- .brand-mark {
105
- width: 28px; height: 28px;
106
- display: grid; place-items: center;
107
- background: hsl(var(--primary)); color: hsl(var(--primary-foreground));
108
- border-radius: var(--radius);
109
- font-weight: 700; font-size: var(--fs-sm); letter-spacing: -.02em;
110
- flex-shrink: 0;
111
- }
112
-
113
- /* ── Auth screens ─────────────────────────────────────────────────── */
114
- .auth-screen {
115
- min-height: 100vh;
116
- display: grid; place-items: center;
117
- padding: var(--sp-6);
118
- background: hsl(var(--muted) / .4);
119
- }
120
- .auth-card {
121
- width: min(400px, 100%);
122
- padding: var(--sp-6);
123
- background: hsl(var(--card));
124
- border: 1px solid hsl(var(--border));
125
- border-radius: calc(var(--radius) + 2px);
126
- box-shadow: 0 1px 2px rgb(0 0 0 / .05), 0 8px 24px -8px rgb(0 0 0 / .1);
127
- }
128
- .auth-card header { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-5); }
129
- .auth-card h1 { font-size: var(--fs-lg); font-weight: 600; letter-spacing: -.01em; }
130
- .auth-card > p { color: hsl(var(--muted-foreground)); font-size: var(--fs-sm); margin-bottom: var(--sp-5); }
131
- .auth-submit { width: 100%; height: 36px; }
132
- .avatar {
133
- width: 26px; height: 26px; flex-shrink: 0;
134
- display: grid; place-items: center;
135
- background: hsl(var(--secondary)); color: hsl(var(--secondary-foreground));
136
- border-radius: 50%;
137
- font-size: var(--fs-2xs); font-weight: 700;
138
- }
139
-
140
- /* ── Forms ────────────────────────────────────────────────────────── */
141
- .field { display: grid; gap: var(--sp-2); margin-bottom: var(--sp-4); font-size: var(--fs-sm); font-weight: 500; }
142
- .field > small, .field-help { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); font-weight: 400; line-height: 1.5; }
143
- .field-row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--sp-4); align-items: start; }
144
-
145
- input, select, textarea {
146
- width: 100%; height: 32px;
147
- padding: 0 var(--sp-3);
148
- background: transparent;
149
- border: 1px solid hsl(var(--input));
150
- border-radius: var(--radius);
151
- font-size: var(--fs-sm);
152
- transition: border-color .12s ease, box-shadow .12s ease;
153
- }
154
- textarea { height: auto; min-height: 72px; padding: var(--sp-2) var(--sp-3); resize: vertical; line-height: 1.5; }
155
- input:hover, select:hover, textarea:hover { border-color: hsl(var(--muted-foreground) / .6); }
156
- input:focus, select:focus, textarea:focus { outline: none; border-color: hsl(var(--ring)); box-shadow: 0 0 0 2px hsl(var(--ring) / .2); }
157
- input:disabled, select:disabled, textarea:disabled { opacity: .5; cursor: not-allowed; }
158
- input[type="checkbox"] { width: 14px; height: 14px; padding: 0; accent-color: hsl(var(--primary)); }
159
-
160
- .checkbox { display: flex; align-items: center; gap: var(--sp-2); height: 32px; font-weight: 500; cursor: pointer; }
161
- .checkbox input { flex-shrink: 0; }
162
-
163
- .form-error { min-height: 18px; margin-top: var(--sp-2); color: hsl(var(--destructive)); font-size: var(--fs-xs); font-weight: 500; }
164
- .confirm-text { color: hsl(var(--muted-foreground)); font-size: var(--fs-sm); line-height: 1.6; }
165
-
166
- /* ── Buttons ──────────────────────────────────────────────────────── */
167
- .button {
168
- display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
169
- height: 32px; padding: 0 var(--sp-3);
170
- border: 1px solid hsl(var(--input));
171
- border-radius: var(--radius);
172
- background: hsl(var(--card));
173
- font-size: var(--fs-sm); font-weight: 500; white-space: nowrap;
174
- box-shadow: 0 1px 2px rgb(0 0 0 / .04);
175
- transition: background-color .12s ease, border-color .12s ease;
176
- }
177
- .button:hover:not(:disabled) { background: hsl(var(--accent)); color: hsl(var(--accent-foreground)); }
178
- .button:disabled { opacity: .5; cursor: not-allowed; }
179
- .button.primary { background: hsl(var(--primary)); border-color: hsl(var(--primary)); color: hsl(var(--primary-foreground)); }
180
- .button.primary:hover:not(:disabled) { background: hsl(var(--primary) / .88); color: hsl(var(--primary-foreground)); }
181
- .button.danger { border-color: hsl(var(--destructive) / .5); color: hsl(var(--destructive)); }
182
- .button.danger:hover:not(:disabled) { background: hsl(var(--destructive) / .08); }
183
- .button.solid-danger { background: hsl(var(--destructive)); border-color: hsl(var(--destructive)); color: hsl(var(--destructive-foreground)); }
184
- .button.solid-danger:hover:not(:disabled) { background: hsl(var(--destructive) / .9); color: hsl(var(--destructive-foreground)); }
185
- .button.small { height: 26px; padding: 0 var(--sp-2); font-size: var(--fs-xs); }
186
- .button svg, .menu-button svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; }
187
-
188
- .icon-button {
189
- display: inline-flex; align-items: center; justify-content: center;
190
- width: 32px; height: 32px; flex-shrink: 0;
191
- border-radius: var(--radius);
192
- color: hsl(var(--muted-foreground));
193
- transition: background-color .12s ease, color .12s ease;
194
- }
195
- .icon-button:hover { background: hsl(var(--accent)); color: hsl(var(--accent-foreground)); }
196
- .icon-button svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
197
-
198
- /* ── App shell ────────────────────────────────────────────────────── */
199
- .app-shell { min-height: 100vh; display: flex; }
200
-
201
- .sidebar {
202
- position: fixed; inset: 0 auto 0 0;
203
- width: var(--sidebar-width);
204
- padding: var(--sp-3) var(--sp-2);
205
- display: flex; flex-direction: column; gap: var(--sp-2);
206
- background: hsl(var(--card));
207
- border-right: 1px solid hsl(var(--border));
208
- z-index: 10;
209
- }
210
- .brand {
211
- display: flex; align-items: center; gap: var(--sp-2);
212
- height: 40px; padding: 0 var(--sp-2);
213
- font-weight: 600; font-size: var(--fs-sm); letter-spacing: -.01em;
214
- }
215
- nav { display: flex; flex-direction: column; gap: 2px; }
216
- .nav-item {
217
- width: 100%; height: 32px;
218
- display: flex; align-items: center; gap: var(--sp-2);
219
- padding: 0 var(--sp-2);
220
- border-radius: var(--radius);
221
- color: hsl(var(--muted-foreground));
222
- font-size: var(--fs-sm); font-weight: 500; text-align: left;
223
- transition: background-color .12s ease, color .12s ease;
224
- }
225
- .nav-item:hover { background: hsl(var(--accent)); color: hsl(var(--accent-foreground)); }
226
- .nav-item.active { background: hsl(var(--secondary)); color: hsl(var(--secondary-foreground)); font-weight: 600; }
227
- .nav-item svg { width: 15px; height: 15px; flex-shrink: 0; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
228
-
229
- .admin-menu-wrap { position: relative; margin-top: auto; }
230
- .admin-button {
231
- width: 100%; display: flex; align-items: center; gap: var(--sp-2);
232
- padding: var(--sp-2);
233
- border-radius: var(--radius);
234
- text-align: left;
235
- transition: background-color .12s ease;
236
- }
237
- .admin-button:hover { background: hsl(var(--accent)); }
238
- .admin-button > svg { width: 15px; height: 15px; flex-shrink: 0; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
239
- .admin-meta { display: grid; min-width: 0; }
240
- .admin-button strong { font-size: var(--fs-sm); font-weight: 600; }
241
- .admin-popover {
242
- position: absolute; inset: auto 0 calc(100% + var(--sp-2));
243
- padding: var(--sp-2);
244
- background: hsl(var(--popover));
245
- border: 1px solid hsl(var(--border));
246
- border-radius: calc(var(--radius) + 2px);
247
- box-shadow: 0 8px 24px -4px rgb(0 0 0 / .12), 0 2px 8px -2px rgb(0 0 0 / .08);
248
- z-index: 20;
249
- }
250
- .admin-popover .field { margin-bottom: var(--sp-2); font-size: var(--fs-xs); }
251
- .menu-button {
252
- width: 100%; height: 30px;
253
- display: flex; align-items: center;
254
- padding: 0 var(--sp-2);
255
- border-radius: var(--radius);
256
- font-size: var(--fs-sm); font-weight: 500; text-align: left;
257
- transition: background-color .12s ease;
258
- }
259
- .menu-button:hover { background: hsl(var(--accent)); }
260
- .danger-text { color: hsl(var(--destructive)); }
261
-
262
- /* ── Main / page chrome ───────────────────────────────────────────── */
263
- .main {
264
- flex: 1; min-width: 0;
265
- margin-left: var(--sidebar-width);
266
- min-height: 100vh;
267
- display: flex; flex-direction: column;
268
- }
269
- .topbar {
270
- position: sticky; top: 0; z-index: 5;
271
- height: 56px;
272
- display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
273
- padding: 0 var(--gutter);
274
- background: hsl(var(--background));
275
- border-bottom: 1px solid hsl(var(--border));
276
- }
277
- .topbar h1 { font-size: var(--fs-lg); font-weight: 600; letter-spacing: -.01em; }
278
- .page-actions { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
279
-
280
- .page-content {
281
- flex: 1; width: 100%;
282
- padding: var(--sp-5) var(--gutter) var(--sp-6);
283
- display: flex; flex-direction: column; gap: var(--sp-4);
284
- }
285
-
286
- /* ── Cards / panels ───────────────────────────────────────────────── */
287
- .panel {
288
- background: hsl(var(--card));
289
- border: 1px solid hsl(var(--border));
290
- border-radius: calc(var(--radius) + 2px);
291
- }
292
- .panel-header {
293
- min-height: 44px;
294
- padding: 0 var(--sp-4);
295
- display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
296
- border-bottom: 1px solid hsl(var(--border));
297
- }
298
- .panel-header h2 { font-size: var(--fs-md); font-weight: 600; }
299
- .panel-body { padding: var(--sp-4); }
300
- .empty { padding: var(--sp-8) var(--sp-4); color: hsl(var(--muted-foreground)); text-align: center; font-size: var(--fs-sm); }
301
- .empty-state { display: grid; justify-items: center; gap: var(--sp-1); padding: var(--sp-8) var(--sp-4); text-align: center; }
302
- .empty-state > svg { width: 28px; height: 28px; margin-bottom: var(--sp-2); color: hsl(var(--muted-foreground)); fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
303
- .empty-state strong { font-size: var(--fs-md); font-weight: 600; color: hsl(var(--foreground)); }
304
- .empty-state span { font-size: var(--fs-xs); color: hsl(var(--muted-foreground)); }
305
- .empty-state .button { margin-top: var(--sp-3); }
306
-
307
- /* Stats */
308
- .stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-4); }
309
- .stat {
310
- padding: var(--sp-4) var(--sp-5);
311
- background: hsl(var(--card));
312
- border: 1px solid hsl(var(--border));
313
- border-radius: calc(var(--radius) + 2px);
314
- display: grid; gap: var(--sp-1);
315
- }
316
- .stat span { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); font-weight: 500; }
317
- .stat strong { font-size: var(--fs-stat); font-weight: 600; letter-spacing: -.02em; line-height: 1.2; font-variant-numeric: tabular-nums; }
318
-
319
- /* ── Toolbar ──────────────────────────────────────────────────────── */
320
- .toolbar { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
321
- .toolbar select { width: auto; min-width: 128px; }
322
- .search-box { position: relative; flex: 1; min-width: 160px; max-width: 280px; }
323
- .search-box svg { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); width: 14px; height: 14px; color: hsl(var(--muted-foreground)); fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; pointer-events: none; }
324
- .search-box input { width: 100%; padding-left: 30px; }
325
-
326
- /* ── Tables ───────────────────────────────────────────────────────── */
327
- .table-wrap {
328
- overflow-x: auto;
329
- background: hsl(var(--card));
330
- border: 1px solid hsl(var(--border));
331
- border-radius: calc(var(--radius) + 2px);
332
- }
333
- table { width: 100%; border-collapse: collapse; min-width: 720px; }
334
- th, td { padding: 0 var(--sp-4); height: 40px; border-bottom: 1px solid hsl(var(--border)); text-align: left; vertical-align: middle; }
335
- th { height: 36px; color: hsl(var(--muted-foreground)); font-size: var(--fs-2xs); font-weight: 600; letter-spacing: .05em; text-transform: uppercase; white-space: nowrap; }
336
- tbody tr:last-child td { border-bottom: 0; }
337
- tbody tr:hover { background: hsl(var(--muted) / .5); }
338
- tr[data-run-detail] { cursor: pointer; }
339
-
340
- .agent-name { display: grid; gap: 2px; min-width: 0; }
341
- .agent-name strong { font-size: var(--fs-sm); font-weight: 600; overflow: hidden; text-overflow: ellipsis; }
342
- .agent-name small { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
343
- .error-detail { color: hsl(var(--destructive)); font-size: var(--fs-sm); overflow-wrap: anywhere; line-height: 1.4; }
344
- .row-actions { display: flex; justify-content: flex-end; gap: var(--sp-2); }
345
-
346
- /* ── Badges & status ──────────────────────────────────────────────── */
347
- .badge {
348
- display: inline-flex; align-items: center;
349
- height: 20px; padding: 0 var(--sp-2);
350
- border: 1px solid hsl(var(--border));
351
- border-radius: 4px;
352
- background: hsl(var(--secondary));
353
- color: hsl(var(--secondary-foreground));
354
- font-size: var(--fs-2xs); font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
355
- }
356
- .status {
357
- display: inline-flex; align-items: center; gap: var(--sp-2);
358
- height: 22px; padding: 0 var(--sp-2);
359
- border-radius: 9999px;
360
- background: hsl(var(--secondary));
361
- color: hsl(var(--muted-foreground));
362
- font-size: var(--fs-xs); font-weight: 500; white-space: nowrap;
363
- }
364
- .status::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: hsl(var(--muted-foreground) / .5); flex-shrink: 0; }
365
- .status.ready, .status.completed { color: hsl(var(--success)); background: hsl(var(--success) / .1); }
366
- .status.ready::before, .status.completed::before { background: hsl(var(--success)); }
367
- .status.failed { color: hsl(var(--destructive)); background: hsl(var(--destructive) / .1); }
368
- .status.failed::before { background: hsl(var(--destructive)); }
369
- .status.running { color: hsl(var(--info)); background: hsl(var(--info) / .1); }
370
- .status.running::before { background: hsl(var(--info)); animation: pulse 2s cubic-bezier(.4, 0, .6, 1) infinite; }
371
- .status.waiting { color: hsl(var(--warning)); background: hsl(var(--warning) / .12); }
372
- .status.waiting::before { background: hsl(var(--warning)); animation: pulse 2s cubic-bezier(.4, 0, .6, 1) infinite; }
373
- .status.checking::before { animation: pulse 2s cubic-bezier(.4, 0, .6, 1) infinite; }
374
- @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .4; } }
375
-
376
- /* ── Runs page ────────────────────────────────────────────────────── */
377
- .run-summary { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-4); }
378
- .run-section { display: flex; flex-direction: column; gap: var(--sp-3); }
379
- .run-section-title { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-4); }
380
- .run-section-title h2 { font-size: var(--fs-md); font-weight: 600; }
381
- .run-section-title span { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); }
382
-
383
- .run-live-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: var(--sp-3); }
384
- .run-card {
385
- position: relative;
386
- display: flex; flex-direction: column; gap: var(--sp-2);
387
- padding: var(--sp-3) var(--sp-4);
388
- background: hsl(var(--card));
389
- border: 1px solid hsl(var(--border));
390
- border-left: 3px solid hsl(var(--info));
391
- border-radius: calc(var(--radius) + 2px);
392
- cursor: pointer;
393
- transition: border-color .12s ease, box-shadow .12s ease;
394
- }
395
- .run-card:hover { border-color: hsl(var(--muted-foreground) / .4); box-shadow: 0 2px 8px -2px rgb(0 0 0 / .08); }
396
- .run-card.waiting { border-left-color: hsl(var(--warning)); }
397
- .run-card-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
398
- .run-card-agent { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
399
- .run-card-agent strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-sm); font-weight: 600; }
400
- .run-task {
401
- display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
402
- overflow: hidden;
403
- color: hsl(var(--foreground));
404
- font-size: var(--fs-sm); line-height: 1.5;
405
- white-space: pre-wrap;
406
- }
407
- .run-progress { display: grid; gap: 2px; }
408
- .run-progress strong { font-size: var(--fs-xs); font-weight: 600; }
409
- .run-progress small { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
410
- .run-meta {
411
- display: flex; align-items: center; justify-content: space-between;
412
- color: hsl(var(--muted-foreground));
413
- font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
414
- font-size: var(--fs-2xs); line-height: 1.4;
415
- font-variant-numeric: tabular-nums;
416
- }
417
- .run-table { min-width: 880px; }
418
- .run-table .run-task-cell { max-width: 360px; }
419
- .run-table th.num, .run-table td.num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
420
- .run-task-cell strong { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; font-size: var(--fs-sm); }
421
- .run-task-cell small { display: block; margin-top: 2px; color: hsl(var(--muted-foreground)); font-size: var(--fs-2xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
422
-
423
- /* Run detail (drawer) */
424
- .run-detail-grid {
425
- display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
426
- margin-bottom: var(--sp-4);
427
- border: 1px solid hsl(var(--border));
428
- border-radius: calc(var(--radius) + 2px);
429
- overflow: hidden;
430
- background: hsl(var(--border));
431
- }
432
- .run-detail-item { padding: var(--sp-3); background: hsl(var(--card)); display: grid; gap: var(--sp-1); align-content: start; }
433
- .run-detail-item span { color: hsl(var(--muted-foreground)); font-size: var(--fs-2xs); font-weight: 600; letter-spacing: .05em; text-transform: uppercase; }
434
- .run-detail-item strong { font-size: var(--fs-sm); font-weight: 500; overflow-wrap: anywhere; }
435
- .run-detail-block { margin-bottom: var(--sp-4); }
436
- .run-detail-block h3 { margin: 0 0 var(--sp-2); color: hsl(var(--muted-foreground)); font-size: var(--fs-2xs); font-weight: 600; letter-spacing: .05em; text-transform: uppercase; }
437
- .run-detail-code {
438
- margin: 0; padding: var(--sp-3);
439
- max-height: 320px; overflow: auto;
440
- border: 1px solid hsl(var(--border));
441
- border-radius: var(--radius);
442
- background: hsl(var(--muted) / .4);
443
- font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
444
- font-size: var(--fs-xs); line-height: 1.6;
445
- overflow-wrap: anywhere; white-space: pre-wrap;
446
- }
447
- .run-id { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
448
-
449
- /* ── Lists (workspaces, overview, artifacts) ──────────────────────── */
450
- .workspace-list, .overview-list { display: grid; gap: var(--sp-2); }
451
- .list-row {
452
- min-height: 48px;
453
- display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
454
- padding: var(--sp-3) var(--sp-4);
455
- background: hsl(var(--card));
456
- border: 1px solid hsl(var(--border));
457
- border-radius: calc(var(--radius) + 2px);
458
- transition: border-color .12s ease;
459
- }
460
- .list-row:hover { border-color: hsl(var(--muted-foreground) / .4); }
461
- .list-row-main { display: grid; gap: 2px; min-width: 0; }
462
- .list-row-main strong, .path { font-size: var(--fs-sm); font-weight: 600; overflow-wrap: anywhere; }
463
- .list-row-main small { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); }
464
- .panel-body > .workspace-list, .panel-body > .overview-list { gap: var(--sp-2); }
465
- .panel-body .list-row { border-radius: var(--radius); }
466
-
467
- /* ── API keys ─────────────────────────────────────────────────────── */
468
- .key-table { min-width: 0; width: 100%; table-layout: fixed; }
469
- .key-table th:nth-child(1) { width: 21%; }
470
- .key-table th:nth-child(2) { width: 15%; }
471
- .key-table th:nth-child(3) { width: 20%; }
472
- .key-table th:nth-child(4) { width: 15%; }
473
- .key-table th:nth-child(5) { width: 15%; }
474
- .key-table th:nth-child(6) { width: 14%; }
475
- .key-table th, .key-table td { padding-left: 10px; padding-right: 10px; }
476
- .key-table-wrap { overflow-x: hidden; }
477
- .key-table th:last-child, .key-table td:last-child { text-align: right; }
478
- .key-secret-cell { display: flex; align-items: center; gap: var(--sp-2); white-space: nowrap; }
479
- .key-secret-cell code { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); letter-spacing: .02em; }
480
- .key-copy-button, .key-icon-button {
481
- display: inline-flex; align-items: center; justify-content: center;
482
- width: 28px; height: 28px;
483
- border-radius: var(--radius);
484
- color: hsl(var(--muted-foreground));
485
- cursor: pointer;
486
- transition: background-color .12s ease, color .12s ease, box-shadow .12s ease;
487
- }
488
- .key-copy-button:hover, .key-icon-button:hover { background: hsl(var(--accent)); color: hsl(var(--accent-foreground)); }
489
- .key-icon-button[aria-expanded="true"] {
490
- background: hsl(var(--accent)); color: hsl(var(--accent-foreground));
491
- box-shadow: 0 0 0 2px hsl(var(--ring) / .35);
492
- }
493
- .key-copy-button svg, .key-icon-button svg, .key-action-menu svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
494
- .key-icon-button.danger-action { color: hsl(var(--destructive)); }
495
- .key-icon-button.danger-action:hover { background: hsl(var(--destructive) / .08); }
496
- .key-scope, .key-last-used { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); }
497
- .key-actions { display: inline-flex; align-items: center; justify-content: flex-end; gap: 2px; }
498
-
499
- .key-action-menu {
500
- position: fixed; z-index: 50;
501
- width: 188px; padding: var(--sp-1);
502
- background: hsl(var(--popover));
503
- border: 1px solid hsl(var(--border));
504
- border-radius: calc(var(--radius) + 2px);
505
- box-shadow: 0 8px 24px -4px rgb(0 0 0 / .12), 0 2px 8px -2px rgb(0 0 0 / .08);
506
- }
507
- .key-action-menu button {
508
- width: 100%; height: 30px;
509
- display: flex; align-items: center; gap: var(--sp-2);
510
- padding: 0 var(--sp-2);
511
- border-radius: var(--radius);
512
- font-size: var(--fs-sm); font-weight: 500; text-align: left;
513
- transition: background-color .12s ease;
514
- }
515
- .key-action-menu button:hover { background: hsl(var(--accent)); }
516
- .key-action-menu button.danger-text { margin-top: var(--sp-1); border-top: 1px solid hsl(var(--border)); border-radius: 0 0 var(--radius) var(--radius); height: 34px; }
517
- .key-action-menu button.danger-text:hover { background: hsl(var(--destructive) / .08); }
518
-
519
- .agent-scope {
520
- max-height: 168px; overflow: auto;
521
- display: grid; gap: 2px;
522
- padding: var(--sp-2);
523
- margin-bottom: var(--sp-4);
524
- border: 1px solid hsl(var(--border));
525
- border-radius: var(--radius);
526
- background: hsl(var(--muted) / .4);
527
- }
528
- .agent-scope .checkbox { height: 28px; padding: 0 var(--sp-2); border-radius: var(--radius); }
529
- .agent-scope .checkbox:hover { background: hsl(var(--accent)); }
530
- .secret-box { display: grid; gap: var(--sp-3); }
531
- .secret-value {
532
- display: block; padding: var(--sp-3);
533
- background: hsl(var(--muted) / .5);
534
- border: 1px solid hsl(var(--border));
535
- border-radius: var(--radius);
536
- overflow-wrap: anywhere;
537
- font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
538
- font-size: var(--fs-xs);
539
- }
540
-
541
- /* ── Drawer ───────────────────────────────────────────────────────── */
542
- .drawer-backdrop { position: fixed; inset: 0; background: rgb(0 0 0 / .4); z-index: 40; animation: fadeIn .18s ease-out; }
543
- .drawer {
544
- position: fixed; inset: 0 0 0 auto;
545
- width: min(480px, 100vw);
546
- display: flex; flex-direction: column;
547
- background: hsl(var(--card));
548
- border-left: 1px solid hsl(var(--border));
549
- box-shadow: -8px 0 32px -8px rgb(0 0 0 / .15);
550
- z-index: 41;
551
- animation: slideInRight .22s cubic-bezier(.32, .72, 0, 1);
552
- overflow: hidden;
553
- }
554
- .drawer-header {
555
- height: 52px; flex-shrink: 0;
556
- display: flex; align-items: center; justify-content: space-between;
557
- padding: 0 var(--sp-4);
558
- border-bottom: 1px solid hsl(var(--border));
559
- }
560
- .drawer-header h2 { font-size: var(--fs-md); font-weight: 600; }
561
- .drawer-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: var(--sp-4); }
562
- .drawer-footer {
563
- flex: 0 0 auto;
564
- display: flex; justify-content: flex-end; gap: var(--sp-2);
565
- padding: var(--sp-3) var(--sp-4) var(--sp-4);
566
- border-top: 1px solid hsl(var(--border));
567
- background: hsl(var(--card));
568
- }
569
- @keyframes fadeIn { from { opacity: 0; } }
570
- @keyframes slideInRight { from { transform: translateX(16px); opacity: 0; } }
571
-
572
- /* ── Settings ─────────────────────────────────────────────────────── */
573
- .settings-layout { width: 100%; max-width: 680px; }
574
- .settings-form .panel-header { min-height: 0; padding: var(--sp-4); }
575
- .settings-fields { display: grid; padding: var(--sp-4); }
576
- .settings-fields .field:last-child { margin-bottom: 0; }
577
- .settings-fields .field input { max-width: 240px; }
578
- .settings-actions { display: flex; justify-content: flex-end; padding: var(--sp-4); }
579
-
580
- /* ── Toast ────────────────────────────────────────────────────────── */
581
- .toast-region {
582
- position: fixed; right: var(--sp-6); bottom: var(--sp-6);
583
- z-index: 60;
584
- display: grid; gap: var(--sp-2);
585
- max-width: 360px;
586
- }
587
- .toast {
588
- padding: var(--sp-3) var(--sp-4);
589
- background: hsl(var(--primary)); color: hsl(var(--primary-foreground));
590
- border-radius: var(--radius);
591
- box-shadow: 0 8px 24px -4px rgb(0 0 0 / .18);
592
- font-size: var(--fs-sm); font-weight: 500; line-height: 1.5;
593
- animation: slideInUp .2s ease;
594
- }
595
- .toast.error { background: hsl(var(--destructive)); color: hsl(var(--destructive-foreground)); }
596
- @keyframes slideInUp { from { opacity: 0; transform: translateY(8px); } }
597
-
598
- /* ── Responsive ───────────────────────────────────────────────────── */
599
- @media (max-width: 860px) {
600
- :root { --sidebar-width: 56px; --gutter: var(--sp-4); }
601
- .brand span:last-child, .nav-item span, .admin-meta { display: none; }
602
- .brand, .nav-item, .admin-button { justify-content: center; }
603
- .admin-popover { left: 0; right: auto; width: 200px; }
604
- }
605
- @media (max-width: 640px) {
606
- .page-content { padding: var(--sp-4) var(--gutter) var(--sp-4); }
607
- .search-box { max-width: none; }
608
- .stats { grid-template-columns: 1fr; }
609
- .run-summary { grid-template-columns: repeat(2, 1fr); }
610
- .run-live-grid { grid-template-columns: 1fr; }
611
- .toolbar input[type="search"], .toolbar select { max-width: none; width: 100%; }
612
- .field-row { grid-template-columns: 1fr; }
613
- .drawer { width: 100vw; }
614
- .run-detail-grid { grid-template-columns: 1fr; }
615
- .toast-region { right: var(--sp-4); bottom: var(--sp-4); left: var(--sp-4); max-width: none; }
616
- }
1
+ // This file is generated by scripts/generate-webui-sources.mjs — do not edit by hand.
2
+ // Edit src/webui/styles.css instead.
3
+ export const styles = String.raw `
4
+ /* 全局设计约定:间距用 --sp-*、字号用 --fs-*、投影用 --shadow-*、层级用 --z-*、
5
+ 动效用 --duration-* / --ease-*,扩展时不要引入散落的像素值或字面量。 */
6
+
7
+ :root {
8
+ color-scheme: light;
9
+ --background: 0 0% 100%;
10
+ --foreground: 0 0% 3.9%;
11
+ --card: 0 0% 100%;
12
+ --card-foreground: 0 0% 3.9%;
13
+ --popover: 0 0% 100%;
14
+ --popover-foreground: 0 0% 3.9%;
15
+ --primary: 0 0% 9%;
16
+ --primary-foreground: 0 0% 98%;
17
+ --secondary: 0 0% 96.1%;
18
+ --secondary-foreground: 0 0% 9%;
19
+ --muted: 0 0% 96.1%;
20
+ --muted-foreground: 0 0% 45.1%;
21
+ --accent: 0 0% 96.1%;
22
+ --accent-foreground: 0 0% 9%;
23
+ /* 状态色既作文字也作自己的 10% 染色底,取值按两种情况都过 AA 4.5:1 反解。
24
+ 下面是浏览器实测值(元素真实计算色 + alpha 合成后的背景),不是手算:
25
+ status failed 4.58 · ready 4.79 · waiting 4.63 · running 4.62 · solid-danger 白字 5.21
26
+ · form-error / danger-text / error-detail / button.danger 5.43。
27
+ --border 是装饰性分隔(WCAG 1.4.11 豁免,不动);--input 是识别输入框与按钮的唯一
28
+ 线索,需 ≥3:1,实测 3.15;--ring 焦点环需 ≥3:1,实测 3.15。调亮前先重测。 */
29
+ --destructive: 0 84.2% 45%;
30
+ --destructive-text: 0 84.2% 45%;
31
+ --destructive-foreground: 0 0% 98%;
32
+ --success: 142 76% 27%;
33
+ --warning: 32 95% 32%;
34
+ --info: 217 91% 48.5%;
35
+ --border: 0 0% 89.8%;
36
+ --input: 0 0% 57%;
37
+ --ring: 0 0% 56%;
38
+
39
+ --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px;
40
+ --sp-5: 20px; --sp-6: 24px; --sp-8: 32px;
41
+
42
+ /* 字号阶梯,全站只用这六级:
43
+ 2xs 大写微标签(表头 / badge)· xs 辅助说明 · sm 正文与表格
44
+ md 面板与 drawer 标题 · lg 页面标题 · stat 统计数字 */
45
+ --fs-2xs: 11px; --fs-xs: 12px; --fs-sm: 13px;
46
+ --fs-md: 14px; --fs-lg: 16px; --fs-stat: 28px;
47
+
48
+ --radius: 6px;
49
+ --radius-lg: calc(var(--radius) + 2px);
50
+ --sidebar-width: 232px;
51
+ --gutter: clamp(var(--sp-6), 4vw, 48px);
52
+
53
+ /* 投影。--shadow-ring-* 是焦点环(用 ring 色描边),不是投影,不要与 elevation 混用。 */
54
+ --shadow-xs: 0 1px 2px rgb(0 0 0 / .04);
55
+ --shadow-sm: 0 2px 8px -2px rgb(0 0 0 / .08);
56
+ --shadow-md: 0 8px 24px -4px rgb(0 0 0 / .12), 0 2px 8px -2px rgb(0 0 0 / .08);
57
+ --shadow-card: 0 1px 2px rgb(0 0 0 / .05), 0 8px 24px -8px rgb(0 0 0 / .1);
58
+ --shadow-drawer: -8px 0 32px -8px rgb(0 0 0 / .15);
59
+ --shadow-toast: 0 8px 24px -4px rgb(0 0 0 / .18);
60
+ --shadow-ring-focus: 0 0 0 2px hsl(var(--ring) / .2);
61
+ --shadow-ring-selected: 0 0 0 2px hsl(var(--ring) / .35);
62
+
63
+ /* 层级。drawer 必须压在 backdrop 之上,menu 与 toast 再往上。 */
64
+ --z-topbar: 5;
65
+ --z-sidebar: 10;
66
+ --z-backdrop: 40;
67
+ --z-drawer: 41;
68
+ --z-menu: 50;
69
+ --z-toast: 60;
70
+
71
+ --duration-fast: .12s;
72
+ --duration-fade: .18s;
73
+ --duration-toast: .2s;
74
+ --duration-slide: .22s;
75
+ --duration-pulse: 2s;
76
+ --ease-standard: ease;
77
+ --ease-out: ease-out;
78
+ --ease-drawer: cubic-bezier(.32, .72, 0, 1);
79
+ --ease-pulse: cubic-bezier(.4, 0, .6, 1);
80
+ }
81
+
82
+ html[data-theme="dark"] {
83
+ color-scheme: dark;
84
+ --background: 0 0% 3.9%;
85
+ --foreground: 0 0% 98%;
86
+ --card: 0 0% 3.9%;
87
+ --card-foreground: 0 0% 98%;
88
+ --popover: 0 0% 3.9%;
89
+ --popover-foreground: 0 0% 98%;
90
+ --primary: 0 0% 98%;
91
+ --primary-foreground: 0 0% 9%;
92
+ --secondary: 0 0% 14.9%;
93
+ --secondary-foreground: 0 0% 98%;
94
+ --muted: 0 0% 14.9%;
95
+ --muted-foreground: 0 0% 63.9%;
96
+ --accent: 0 0% 14.9%;
97
+ --accent-foreground: 0 0% 98%;
98
+ /* destructive 是唯一「作按钮底要暗、作文字要亮」的颜色,所以暗色必须拆两个令牌:
99
+ 基色 30.6% 配白字 9.59,文字色 58% 在自己的染色底上 4.52;把基色提到 58% 会让
100
+ 实心危险按钮掉到 3.88。其余状态色在暗色染色底上已有 7.60 / 7.86 / 5.85,无需拆分。 */
101
+ --destructive: 0 62.8% 30.6%;
102
+ --destructive-text: 0 62.8% 58%;
103
+ --destructive-foreground: 0 0% 98%;
104
+ --success: 142 71% 45%;
105
+ --warning: 38 92% 50%;
106
+ --info: 217 91% 65%;
107
+ --border: 0 0% 14.9%;
108
+ --input: 0 0% 40%;
109
+ --ring: 0 0% 83.1%;
110
+ }
111
+
112
+ /* ── Base ─────────────────────────────────────────────────────────── */
113
+ *, *::before, *::after { box-sizing: border-box; }
114
+ html, body { height: 100%; }
115
+ html { scrollbar-gutter: stable; }
116
+ body {
117
+ margin: 0;
118
+ background: hsl(var(--background));
119
+ color: hsl(var(--foreground));
120
+ font: var(--fs-sm)/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans",
121
+ "PingFang SC", "Microsoft YaHei", Helvetica, Arial, sans-serif;
122
+ -webkit-font-smoothing: antialiased;
123
+ text-rendering: optimizeLegibility;
124
+ }
125
+ h1, h2, h3, p { margin: 0; }
126
+ button, input, select, textarea { font: inherit; color: inherit; }
127
+ button { background: none; border: 0; cursor: pointer; padding: 0; }
128
+ code, .mono { font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace; }
129
+ .hidden, [hidden] { display: none !important; }
130
+ .muted { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); }
131
+
132
+ :focus-visible {
133
+ outline: 2px solid hsl(var(--ring));
134
+ outline-offset: 1px;
135
+ }
136
+
137
+ ::selection { background: hsl(var(--accent)); color: hsl(var(--accent-foreground)); }
138
+
139
+ /* Thin scrollbars */
140
+ ::-webkit-scrollbar { width: 10px; height: 10px; }
141
+ ::-webkit-scrollbar-thumb { background: hsl(var(--muted-foreground) / .35); border-radius: 8px; border: 3px solid transparent; background-clip: content-box; }
142
+ ::-webkit-scrollbar-thumb:hover { background-color: hsl(var(--muted-foreground) / .55); }
143
+ ::-webkit-scrollbar-track { background: transparent; }
144
+
145
+ /* ── Brand ────────────────────────────────────────────────────────── */
146
+ .brand-mark {
147
+ width: 28px; height: 28px;
148
+ display: grid; place-items: center;
149
+ background: hsl(var(--primary)); color: hsl(var(--primary-foreground));
150
+ border-radius: var(--radius);
151
+ font-weight: 700; font-size: var(--fs-sm); letter-spacing: -.02em;
152
+ flex-shrink: 0;
153
+ }
154
+
155
+ /* ── Auth screens ─────────────────────────────────────────────────── */
156
+ .auth-screen {
157
+ min-height: 100vh;
158
+ display: grid; place-items: center;
159
+ padding: var(--sp-6);
160
+ background: hsl(var(--muted) / .4);
161
+ }
162
+ .auth-card {
163
+ width: min(400px, 100%);
164
+ padding: var(--sp-6);
165
+ background: hsl(var(--card));
166
+ border: 1px solid hsl(var(--border));
167
+ border-radius: var(--radius-lg);
168
+ box-shadow: var(--shadow-card);
169
+ }
170
+ .auth-card header { display: flex; align-items: center; gap: var(--sp-3); margin-bottom: var(--sp-5); }
171
+ .auth-card h1 { font-size: var(--fs-lg); font-weight: 600; letter-spacing: -.01em; }
172
+ .auth-card > p { color: hsl(var(--muted-foreground)); font-size: var(--fs-sm); margin-bottom: var(--sp-5); }
173
+ .auth-submit { width: 100%; height: 36px; }
174
+
175
+ /* ── Forms ────────────────────────────────────────────────────────── */
176
+ .field { display: grid; gap: var(--sp-2); margin-bottom: var(--sp-4); font-size: var(--fs-sm); font-weight: 500; }
177
+ .field > small, .field-help { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); font-weight: 400; line-height: 1.5; }
178
+ .field-row { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--sp-4); align-items: start; margin-bottom: var(--sp-4); }
179
+ .field-row > .field { margin-bottom: 0; }
180
+
181
+ input, select, textarea {
182
+ width: 100%; height: 32px;
183
+ padding: 0 var(--sp-3);
184
+ background: transparent;
185
+ border: 1px solid hsl(var(--input));
186
+ border-radius: var(--radius);
187
+ font-size: var(--fs-sm);
188
+ transition: border-color var(--duration-fast) var(--ease-standard), box-shadow var(--duration-fast) var(--ease-standard);
189
+ }
190
+ textarea { height: auto; min-height: 72px; padding: var(--sp-2) var(--sp-3); resize: vertical; line-height: 1.5; }
191
+ input:hover, select:hover, textarea:hover { border-color: hsl(var(--muted-foreground) / .6); }
192
+ input:focus, select:focus, textarea:focus { outline: none; border-color: hsl(var(--ring)); box-shadow: var(--shadow-ring-focus); }
193
+ input:disabled, select:disabled, textarea:disabled { opacity: .5; cursor: not-allowed; }
194
+ input[type="checkbox"] { width: 14px; height: 14px; padding: 0; accent-color: hsl(var(--primary)); }
195
+
196
+ .checkbox { display: flex; align-items: center; gap: var(--sp-2); height: 32px; font-weight: 500; cursor: pointer; }
197
+ .checkbox input { flex-shrink: 0; }
198
+
199
+ .form-error { min-height: 18px; margin-top: var(--sp-2); color: hsl(var(--destructive-text)); font-size: var(--fs-xs); font-weight: 500; }
200
+ .confirm-text { color: hsl(var(--muted-foreground)); font-size: var(--fs-sm); line-height: 1.6; }
201
+
202
+ /* ── Buttons ──────────────────────────────────────────────────────── */
203
+ .button {
204
+ display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
205
+ height: 32px; padding: 0 var(--sp-3);
206
+ border: 1px solid hsl(var(--input));
207
+ border-radius: var(--radius);
208
+ background: hsl(var(--card));
209
+ font-size: var(--fs-sm); font-weight: 500; white-space: nowrap;
210
+ box-shadow: var(--shadow-xs);
211
+ transition: background-color var(--duration-fast) var(--ease-standard), border-color var(--duration-fast) var(--ease-standard);
212
+ }
213
+ .button:hover:not(:disabled) { background: hsl(var(--accent)); color: hsl(var(--accent-foreground)); }
214
+ .button:disabled { opacity: .5; cursor: not-allowed; }
215
+ .button.primary { background: hsl(var(--primary)); border-color: hsl(var(--primary)); color: hsl(var(--primary-foreground)); }
216
+ .button.primary:hover:not(:disabled) { background: hsl(var(--primary) / .88); color: hsl(var(--primary-foreground)); }
217
+ .button.danger { color: hsl(var(--destructive-text)); }
218
+ .button.danger:hover:not(:disabled) { background: hsl(var(--destructive) / .08); }
219
+ .button.solid-danger { background: hsl(var(--destructive)); border-color: hsl(var(--destructive)); color: hsl(var(--destructive-foreground)); }
220
+ .button.solid-danger:hover:not(:disabled) { background: hsl(var(--destructive) / .9); color: hsl(var(--destructive-foreground)); }
221
+ .button.small { height: 26px; padding: 0 var(--sp-2); font-size: var(--fs-xs); }
222
+ .button svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; flex-shrink: 0; }
223
+
224
+ .icon-button {
225
+ display: inline-flex; align-items: center; justify-content: center;
226
+ width: 32px; height: 32px; flex-shrink: 0;
227
+ border-radius: var(--radius);
228
+ color: hsl(var(--muted-foreground));
229
+ transition: background-color var(--duration-fast) var(--ease-standard), color var(--duration-fast) var(--ease-standard);
230
+ }
231
+ .icon-button:hover { background: hsl(var(--accent)); color: hsl(var(--accent-foreground)); }
232
+ .icon-button svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
233
+
234
+ /* ── App shell ────────────────────────────────────────────────────── */
235
+ .app-shell { min-height: 100vh; display: flex; }
236
+
237
+ .sidebar {
238
+ position: fixed; inset: 0 auto 0 0;
239
+ width: var(--sidebar-width);
240
+ padding: var(--sp-3) var(--sp-2);
241
+ display: flex; flex-direction: column; gap: var(--sp-2);
242
+ background: hsl(var(--card));
243
+ border-right: 1px solid hsl(var(--border));
244
+ z-index: var(--z-sidebar);
245
+ }
246
+ .brand {
247
+ display: flex; align-items: center; gap: var(--sp-2);
248
+ height: 40px; padding: 0 var(--sp-2);
249
+ font-weight: 600; font-size: var(--fs-sm); letter-spacing: -.01em;
250
+ }
251
+ nav { flex: 1; min-height: 0; display: flex; flex-direction: column; gap: var(--sp-4); }
252
+ .nav-group { display: flex; flex-direction: column; gap: 2px; }
253
+ .nav-group-label {
254
+ padding: 0 var(--sp-2);
255
+ color: hsl(var(--muted-foreground));
256
+ font-size: var(--fs-2xs); font-weight: 600; letter-spacing: .05em; text-transform: uppercase;
257
+ }
258
+ .nav-group-footer { margin-top: auto; }
259
+ .nav-item {
260
+ width: 100%; height: 32px;
261
+ display: flex; align-items: center; gap: var(--sp-2);
262
+ padding: 0 var(--sp-2);
263
+ border-radius: var(--radius);
264
+ color: hsl(var(--muted-foreground));
265
+ font-size: var(--fs-sm); font-weight: 500; text-align: left;
266
+ transition: background-color var(--duration-fast) var(--ease-standard), color var(--duration-fast) var(--ease-standard);
267
+ }
268
+ .nav-item:hover { background: hsl(var(--accent)); color: hsl(var(--accent-foreground)); }
269
+ .nav-item.active { background: hsl(var(--secondary)); color: hsl(var(--secondary-foreground)); font-weight: 600; }
270
+ .nav-item-danger { color: hsl(var(--destructive-text)); }
271
+ .nav-item-danger:hover { background: hsl(var(--destructive) / .08); color: hsl(var(--destructive-text)); }
272
+ .nav-item svg { width: 15px; height: 15px; flex-shrink: 0; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
273
+
274
+ .danger-text { color: hsl(var(--destructive-text)); }
275
+
276
+ /* ── Main / page chrome ───────────────────────────────────────────── */
277
+ .main {
278
+ flex: 1; min-width: 0;
279
+ margin-left: var(--sidebar-width);
280
+ min-height: 100vh;
281
+ display: flex; flex-direction: column;
282
+ }
283
+ .topbar {
284
+ position: sticky; top: 0; z-index: var(--z-topbar);
285
+ height: 56px;
286
+ display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
287
+ padding: 0 var(--gutter);
288
+ background: hsl(var(--background));
289
+ border-bottom: 1px solid hsl(var(--border));
290
+ }
291
+ .topbar h1 { font-size: var(--fs-lg); font-weight: 600; letter-spacing: -.01em; }
292
+ .page-actions { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
293
+
294
+ #page-results { display: flex; flex-direction: column; gap: var(--sp-4); }
295
+ .page-content > :empty { display: none; }
296
+ .visually-hidden { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; }
297
+
298
+ button[aria-busy="true"] { cursor: progress; }
299
+ button[aria-busy="true"]::after { content: '…'; margin-left: var(--sp-1); }
300
+
301
+ .page-content {
302
+ flex: 1; width: 100%;
303
+ padding: var(--sp-5) var(--gutter) var(--sp-6);
304
+ display: flex; flex-direction: column; gap: var(--sp-4);
305
+ }
306
+
307
+ /* ── Cards / panels ───────────────────────────────────────────────── */
308
+ .panel {
309
+ background: hsl(var(--card));
310
+ border: 1px solid hsl(var(--border));
311
+ border-radius: var(--radius-lg);
312
+ }
313
+ .panel-header {
314
+ min-height: 44px;
315
+ padding: 0 var(--sp-4);
316
+ display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
317
+ border-bottom: 1px solid hsl(var(--border));
318
+ }
319
+ .panel-header h2 { font-size: var(--fs-md); font-weight: 600; }
320
+ .panel-body { padding: var(--sp-4); }
321
+ .panel-note { padding: var(--sp-4); color: hsl(var(--muted-foreground)); font-size: var(--fs-sm); }
322
+ .empty { padding: var(--sp-8) var(--sp-4); color: hsl(var(--muted-foreground)); text-align: center; font-size: var(--fs-sm); }
323
+ .empty-state { display: grid; justify-items: center; gap: var(--sp-1); padding: var(--sp-8) var(--sp-4); text-align: center; }
324
+ .empty-state > svg { width: 28px; height: 28px; margin-bottom: var(--sp-2); color: hsl(var(--muted-foreground)); fill: none; stroke: currentColor; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
325
+ .empty-state strong { font-size: var(--fs-md); font-weight: 600; color: hsl(var(--foreground)); }
326
+ .empty-state span { font-size: var(--fs-xs); color: hsl(var(--muted-foreground)); }
327
+ .empty-state .button { margin-top: var(--sp-3); }
328
+
329
+ /* Stats */
330
+ .stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-4); }
331
+ .stat {
332
+ padding: var(--sp-4) var(--sp-5);
333
+ background: hsl(var(--card));
334
+ border: 1px solid hsl(var(--border));
335
+ border-radius: var(--radius-lg);
336
+ display: grid; gap: var(--sp-1);
337
+ }
338
+ .stat span { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); font-weight: 500; }
339
+ .stat strong { font-size: var(--fs-stat); font-weight: 600; letter-spacing: -.02em; line-height: 1.2; font-variant-numeric: tabular-nums; }
340
+
341
+ /* ── Toolbar ──────────────────────────────────────────────────────── */
342
+ .toolbar { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
343
+ .toolbar select { width: auto; min-width: 128px; }
344
+ .search-box { position: relative; flex: 1; min-width: 160px; max-width: 280px; }
345
+ .search-box svg { position: absolute; left: 10px; top: 50%; transform: translateY(-50%); width: 14px; height: 14px; color: hsl(var(--muted-foreground)); fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; pointer-events: none; }
346
+ .search-box input { width: 100%; padding-left: 30px; }
347
+
348
+ /* ── Tables ───────────────────────────────────────────────────────── */
349
+ .table-wrap {
350
+ overflow-x: auto;
351
+ background: hsl(var(--card));
352
+ border: 1px solid hsl(var(--border));
353
+ border-radius: var(--radius-lg);
354
+ }
355
+ table { width: 100%; border-collapse: collapse; min-width: 720px; }
356
+ th, td { padding: 0 var(--sp-4); height: 40px; border-bottom: 1px solid hsl(var(--border)); text-align: left; vertical-align: middle; }
357
+ th { height: 36px; color: hsl(var(--muted-foreground)); font-size: var(--fs-2xs); font-weight: 600; letter-spacing: .05em; text-transform: uppercase; white-space: nowrap; }
358
+ tbody tr:last-child td { border-bottom: 0; }
359
+ tbody tr:hover { background: hsl(var(--muted) / .5); }
360
+ tr[data-run-detail] { cursor: pointer; }
361
+
362
+ .agent-name { display: grid; gap: 2px; min-width: 0; }
363
+ .agent-name strong { font-size: var(--fs-sm); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
364
+ .agent-name small { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
365
+ .error-detail { color: hsl(var(--destructive-text)); font-size: var(--fs-sm); overflow-wrap: anywhere; line-height: 1.4; }
366
+ .row-actions { display: flex; justify-content: flex-end; gap: var(--sp-2); }
367
+ .agent-table { min-width: 1050px; table-layout: fixed; }
368
+ .connection-status { padding: var(--sp-3) var(--sp-4); border: 1px solid currentColor; border-radius: var(--radius-lg); color: hsl(var(--destructive-text)); margin-bottom: var(--sp-4); overflow-wrap: anywhere; }
369
+ .run-pagination { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px; margin-bottom: 16px; }
370
+ .agent-table th:nth-child(1) { width: 22%; }
371
+ .agent-table th:nth-child(2) { width: 8%; }
372
+ .agent-table th:nth-child(3), .agent-table th:nth-child(4), .agent-table th:nth-child(6) { width: 10%; }
373
+ .agent-table th:nth-child(5) { width: 26%; }
374
+ .agent-table th:nth-child(7) { width: 14%; }
375
+ .agent-table td, .agent-table .agent-name small { overflow-wrap: anywhere; }
376
+
377
+ /* ── Badges & status ──────────────────────────────────────────────── */
378
+ .badge {
379
+ display: inline-flex; align-items: center;
380
+ height: 20px; padding: 0 var(--sp-2);
381
+ border: 1px solid hsl(var(--border));
382
+ border-radius: 4px;
383
+ background: hsl(var(--secondary));
384
+ color: hsl(var(--secondary-foreground));
385
+ font-size: var(--fs-2xs); font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
386
+ }
387
+ .status {
388
+ display: inline-flex; align-items: center; gap: var(--sp-2);
389
+ height: 22px; padding: 0 var(--sp-2);
390
+ border-radius: 9999px;
391
+ background: hsl(var(--secondary));
392
+ color: hsl(var(--muted-foreground));
393
+ font-size: var(--fs-xs); font-weight: 500; white-space: nowrap;
394
+ }
395
+ .status::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: hsl(var(--muted-foreground) / .5); flex-shrink: 0; }
396
+ .status.ready, .status.completed { color: hsl(var(--success)); background: hsl(var(--success) / .1); }
397
+ .status.ready::before, .status.completed::before { background: hsl(var(--success)); }
398
+ .status.failed { color: hsl(var(--destructive-text)); background: hsl(var(--destructive) / .1); }
399
+ .status.failed::before { background: hsl(var(--destructive)); }
400
+ .status.running { color: hsl(var(--info)); background: hsl(var(--info) / .1); }
401
+ .status.running::before { background: hsl(var(--info)); animation: pulse var(--duration-pulse) var(--ease-pulse) infinite; }
402
+ .status.waiting { color: hsl(var(--warning)); background: hsl(var(--warning) / .12); }
403
+ .status.waiting::before { background: hsl(var(--warning)); animation: pulse var(--duration-pulse) var(--ease-pulse) infinite; }
404
+ .status.checking::before { animation: pulse var(--duration-pulse) var(--ease-pulse) infinite; }
405
+ @keyframes pulse { 0%, 100% { opacity: 1; } 50% { opacity: .4; } }
406
+
407
+ /* ── Runs page ────────────────────────────────────────────────────── */
408
+ .run-summary { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--sp-4); }
409
+ .run-section { display: flex; flex-direction: column; gap: var(--sp-3); }
410
+ .run-section-title { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-4); }
411
+ .run-section-title h2 { font-size: var(--fs-md); font-weight: 600; }
412
+ .run-section-title span { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); }
413
+
414
+ .run-live-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: var(--sp-3); }
415
+ .run-card {
416
+ position: relative;
417
+ min-width: 0;
418
+ display: flex; flex-direction: column; gap: var(--sp-2);
419
+ padding: var(--sp-3) var(--sp-4);
420
+ background: hsl(var(--card));
421
+ border: 1px solid hsl(var(--border));
422
+ border-left: 3px solid hsl(var(--info));
423
+ border-radius: var(--radius-lg);
424
+ transition: border-color var(--duration-fast) var(--ease-standard), box-shadow var(--duration-fast) var(--ease-standard);
425
+ }
426
+ .run-card:hover { border-color: hsl(var(--muted-foreground) / .4); box-shadow: var(--shadow-sm); }
427
+ .run-card.waiting { border-left-color: hsl(var(--warning)); }
428
+ .run-card-head { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
429
+ .run-card-agent { display: flex; align-items: center; gap: var(--sp-2); min-width: 0; }
430
+ .run-card-head > .status, .run-card-agent > .badge { flex-shrink: 0; }
431
+ .run-card-agent strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-sm); font-weight: 600; }
432
+ .run-task {
433
+ display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
434
+ overflow: hidden;
435
+ color: hsl(var(--foreground));
436
+ font-size: var(--fs-sm); line-height: 1.5;
437
+ white-space: pre-wrap;
438
+ overflow-wrap: anywhere;
439
+ }
440
+ .run-progress { display: grid; gap: 2px; }
441
+ .run-progress strong { font-size: var(--fs-xs); font-weight: 600; }
442
+ .run-progress small { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
443
+ .run-meta {
444
+ display: flex; align-items: center; justify-content: space-between;
445
+ color: hsl(var(--muted-foreground));
446
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
447
+ font-size: var(--fs-2xs); line-height: 1.4;
448
+ font-variant-numeric: tabular-nums;
449
+ }
450
+ .run-table { min-width: 1040px; table-layout: fixed; }
451
+ .run-table th:nth-child(1), .run-table th:nth-child(5) { width: 160px; }
452
+ .run-table th:nth-child(4) { width: 100px; }
453
+ .run-table th:nth-child(6) { width: 90px; }
454
+ .run-table th:nth-child(7) { width: 110px; }
455
+ .run-table .run-task-cell { max-width: 360px; }
456
+ .run-table th.num, .run-table td.num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
457
+ .run-task-cell strong { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-weight: 500; font-size: var(--fs-sm); }
458
+ .run-task-cell small { display: block; margin-top: 2px; color: hsl(var(--muted-foreground)); font-size: var(--fs-2xs); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
459
+
460
+ /* Run detail (drawer) */
461
+ .run-detail-actions { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-3); }
462
+ .run-output-heading { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-2); }
463
+ .run-output-heading h3 { margin: 0; }
464
+ .run-pending { padding: var(--sp-3); margin-bottom: var(--sp-4); border: 1px solid hsl(var(--border)); border-radius: var(--radius); }
465
+ .run-pending-prompt { white-space: pre-wrap; overflow-wrap: anywhere; }
466
+ .run-pending h3 { font-size: var(--fs-md); }
467
+ .run-pending .row-actions { flex-wrap: wrap; }
468
+ .run-detail-grid {
469
+ display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
470
+ margin-bottom: var(--sp-4);
471
+ border: 1px solid hsl(var(--border));
472
+ border-radius: var(--radius-lg);
473
+ overflow: hidden;
474
+ background: hsl(var(--border));
475
+ }
476
+ .run-detail-item { padding: var(--sp-3); background: hsl(var(--card)); display: grid; gap: var(--sp-1); align-content: start; }
477
+ .run-detail-item span { color: hsl(var(--muted-foreground)); font-size: var(--fs-2xs); font-weight: 600; letter-spacing: .05em; text-transform: uppercase; }
478
+ .run-detail-item strong { font-size: var(--fs-sm); font-weight: 500; overflow-wrap: anywhere; }
479
+ .run-detail-block { margin-bottom: var(--sp-4); }
480
+ .run-detail-block h3 { margin: 0 0 var(--sp-2); color: hsl(var(--muted-foreground)); font-size: var(--fs-2xs); font-weight: 600; letter-spacing: .05em; text-transform: uppercase; }
481
+ .run-detail-code {
482
+ margin: 0; padding: var(--sp-3);
483
+ max-height: 320px; overflow: auto;
484
+ border: 1px solid hsl(var(--border));
485
+ border-radius: var(--radius);
486
+ background: hsl(var(--muted) / .4);
487
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
488
+ font-size: var(--fs-xs); line-height: 1.6;
489
+ overflow-wrap: anywhere; white-space: pre-wrap;
490
+ }
491
+ .run-id { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
492
+
493
+ /* ── Lists (workspaces, overview, artifacts) ──────────────────────── */
494
+ .workspace-list, .overview-list { display: grid; gap: var(--sp-2); }
495
+ .list-row {
496
+ min-width: 0; min-height: 48px;
497
+ display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
498
+ padding: var(--sp-3) var(--sp-4);
499
+ background: hsl(var(--card));
500
+ border: 1px solid hsl(var(--border));
501
+ border-radius: var(--radius-lg);
502
+ transition: border-color var(--duration-fast) var(--ease-standard);
503
+ }
504
+ .list-row:hover { border-color: hsl(var(--muted-foreground) / .4); }
505
+ .list-row-main { display: grid; gap: 2px; min-width: 0; }
506
+ .list-row-main > * { min-width: 0; }
507
+ .list-row-main strong, .path { font-size: var(--fs-sm); font-weight: 600; overflow-wrap: anywhere; }
508
+ .list-row-main small { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); overflow-wrap: anywhere; }
509
+ .panel-body > .workspace-list, .panel-body > .overview-list { gap: var(--sp-2); }
510
+ .panel-body .list-row { border-radius: var(--radius); }
511
+
512
+ /* ── API keys ─────────────────────────────────────────────────────── */
513
+ .key-table { min-width: 760px; width: 100%; table-layout: fixed; }
514
+ .key-table th:nth-child(1) { width: 21%; }
515
+ .key-table th:nth-child(2) { width: 15%; }
516
+ .key-table th:nth-child(3) { width: 20%; }
517
+ .key-table th:nth-child(4) { width: 15%; }
518
+ .key-table th:nth-child(5) { width: 15%; }
519
+ .key-table th:nth-child(6) { width: 14%; }
520
+ .key-table th, .key-table td { padding-left: 10px; padding-right: 10px; }
521
+ .key-table-wrap { overflow-x: auto; }
522
+ .key-table th:last-child, .key-table td:last-child { text-align: right; }
523
+ .key-secret-cell { display: flex; align-items: center; gap: var(--sp-2); white-space: nowrap; }
524
+ .key-secret-cell code { color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); letter-spacing: .02em; }
525
+ .key-copy-button, .key-icon-button {
526
+ display: inline-flex; align-items: center; justify-content: center;
527
+ width: 28px; height: 28px;
528
+ border-radius: var(--radius);
529
+ color: hsl(var(--muted-foreground));
530
+ cursor: pointer;
531
+ transition: background-color var(--duration-fast) var(--ease-standard), color var(--duration-fast) var(--ease-standard), box-shadow var(--duration-fast) var(--ease-standard);
532
+ }
533
+ .key-copy-button:hover, .key-icon-button:hover { background: hsl(var(--accent)); color: hsl(var(--accent-foreground)); }
534
+ .key-icon-button[aria-expanded="true"] {
535
+ background: hsl(var(--accent)); color: hsl(var(--accent-foreground));
536
+ box-shadow: var(--shadow-ring-selected);
537
+ }
538
+ .key-copy-button svg, .key-icon-button svg, .key-action-menu svg { width: 14px; height: 14px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
539
+ .key-icon-button.danger-action { color: hsl(var(--destructive-text)); }
540
+ .key-icon-button.danger-action:hover { background: hsl(var(--destructive) / .08); }
541
+ .key-scope, .key-last-used { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: hsl(var(--muted-foreground)); font-size: var(--fs-xs); }
542
+ .key-actions { display: inline-flex; align-items: center; justify-content: flex-end; gap: 2px; }
543
+
544
+ .key-action-menu {
545
+ position: fixed; z-index: var(--z-menu);
546
+ width: 188px; padding: var(--sp-1);
547
+ background: hsl(var(--popover));
548
+ border: 1px solid hsl(var(--border));
549
+ border-radius: var(--radius-lg);
550
+ box-shadow: var(--shadow-md);
551
+ }
552
+ .key-action-menu button {
553
+ width: 100%; height: 30px;
554
+ display: flex; align-items: center; gap: var(--sp-2);
555
+ padding: 0 var(--sp-2);
556
+ border-radius: var(--radius);
557
+ font-size: var(--fs-sm); font-weight: 500; text-align: left;
558
+ transition: background-color var(--duration-fast) var(--ease-standard);
559
+ }
560
+ .key-action-menu button:hover { background: hsl(var(--accent)); }
561
+ .key-action-menu button.danger-text { margin-top: var(--sp-1); border-top: 1px solid hsl(var(--border)); border-radius: 0 0 var(--radius) var(--radius); height: 34px; }
562
+ .key-action-menu button.danger-text:hover { background: hsl(var(--destructive) / .08); }
563
+
564
+ .agent-scope {
565
+ max-height: 168px; overflow: auto;
566
+ display: grid; gap: 2px;
567
+ padding: var(--sp-2);
568
+ margin-bottom: var(--sp-4);
569
+ border: 1px solid hsl(var(--border));
570
+ border-radius: var(--radius);
571
+ background: hsl(var(--muted) / .4);
572
+ }
573
+ .agent-scope .checkbox {
574
+ display: grid; grid-template-columns: 14px minmax(0, 1fr) auto;
575
+ align-items: start; height: auto; min-height: 32px;
576
+ padding: 6px var(--sp-2); border-radius: var(--radius);
577
+ }
578
+ .agent-scope .checkbox input { margin-top: 3px; }
579
+ .scope-name { overflow-wrap: anywhere; }
580
+ .agent-scope .checkbox:hover { background: hsl(var(--accent)); }
581
+ .secret-box { display: grid; gap: var(--sp-3); }
582
+ .secret-value {
583
+ display: block; padding: var(--sp-3);
584
+ background: hsl(var(--muted) / .5);
585
+ border: 1px solid hsl(var(--border));
586
+ border-radius: var(--radius);
587
+ overflow-wrap: anywhere;
588
+ font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
589
+ font-size: var(--fs-xs);
590
+ }
591
+
592
+ /* ── Drawer ───────────────────────────────────────────────────────── */
593
+ .drawer-backdrop { position: fixed; inset: 0; background: rgb(0 0 0 / .4); z-index: var(--z-backdrop); animation: fadeIn var(--duration-fade) var(--ease-out); }
594
+ .drawer {
595
+ position: fixed; inset: 0 0 0 auto;
596
+ width: min(480px, 100%);
597
+ display: flex; flex-direction: column;
598
+ background: hsl(var(--card));
599
+ border-left: 1px solid hsl(var(--border));
600
+ box-shadow: var(--shadow-drawer);
601
+ z-index: var(--z-drawer);
602
+ animation: slideInRight var(--duration-slide) var(--ease-drawer);
603
+ overflow: hidden;
604
+ }
605
+ .drawer-header {
606
+ height: 52px; flex-shrink: 0;
607
+ display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3);
608
+ padding: 0 var(--sp-4);
609
+ border-bottom: 1px solid hsl(var(--border));
610
+ }
611
+ .drawer-header h2 { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: var(--fs-md); font-weight: 600; }
612
+ .drawer-body { flex: 1 1 auto; min-height: 0; overflow-y: auto; padding: var(--sp-4); }
613
+ .drawer-footer {
614
+ flex: 0 0 auto;
615
+ display: flex; justify-content: flex-end; gap: var(--sp-2);
616
+ padding: var(--sp-3) var(--sp-4) var(--sp-4);
617
+ border-top: 1px solid hsl(var(--border));
618
+ background: hsl(var(--card));
619
+ }
620
+ @keyframes fadeIn { from { opacity: 0; } }
621
+ @keyframes slideInRight { from { transform: translateX(16px); opacity: 0; } }
622
+
623
+ /* ── Settings ─────────────────────────────────────────────────────── */
624
+ .main.settings-page .topbar { padding-inline: 0; justify-content: flex-start; gap: 0; }
625
+ .main.settings-page .topbar h1 {
626
+ width: min(calc(100% - 2 * var(--gutter)), 820px);
627
+ margin-inline: auto;
628
+ padding-right: 100px;
629
+ }
630
+ .main.settings-page .page-actions { position: absolute; right: max(var(--gutter), calc((100% - 820px) / 2)); }
631
+ .main.settings-page .page-content { padding-top: var(--sp-8); }
632
+ .settings-layout { width: min(100%, 820px); margin-inline: auto; }
633
+ .settings-section { width: 100%; }
634
+ .settings-section + .settings-section {
635
+ margin-top: 48px;
636
+ padding-top: 48px;
637
+ border-top: 1px solid hsl(var(--border));
638
+ }
639
+ .settings-section-heading { display: grid; gap: var(--sp-2); margin-bottom: 28px; }
640
+ .settings-section-heading h2 { font-size: var(--fs-lg); font-weight: 600; letter-spacing: -.01em; }
641
+ /* 节说明写的是生效范围——这是界面自身无法表达的信息,不要当复述删掉 */
642
+ .settings-note { color: hsl(var(--muted-foreground)); font-size: var(--fs-sm); }
643
+ .settings-fields { display: grid; gap: 24px; width: min(100%, 520px); }
644
+ .settings-fields .field { margin-bottom: 0; }
645
+ .settings-fields .field input, .settings-fields .field select { max-width: none; }
646
+ .settings-actions { display: flex; justify-content: flex-end; gap: var(--sp-2); margin-top: 28px; }
647
+ .settings-form-error { width: min(100%, 520px); margin-top: 32px; }
648
+ .settings-account-row {
649
+ display: grid;
650
+ grid-template-columns: minmax(160px, 200px) minmax(0, 1fr);
651
+ align-items: start;
652
+ gap: 32px;
653
+ }
654
+ .settings-account-copy { display: grid; gap: var(--sp-1); }
655
+ .settings-account-copy strong { font-size: var(--fs-sm); font-weight: 600; }
656
+ .settings-account-copy p { color: hsl(var(--muted-foreground)); font-size: var(--fs-sm); }
657
+ .settings-account-fields { display: grid; gap: 24px; width: min(100%, 520px); }
658
+
659
+ /* ── Toast ────────────────────────────────────────────────────────── */
660
+ .toast-region {
661
+ position: fixed; right: var(--sp-6); bottom: var(--sp-6);
662
+ z-index: var(--z-toast);
663
+ display: grid; gap: var(--sp-2);
664
+ max-width: 360px;
665
+ }
666
+ .toast {
667
+ padding: var(--sp-3) var(--sp-4);
668
+ background: hsl(var(--primary)); color: hsl(var(--primary-foreground));
669
+ border-radius: var(--radius);
670
+ box-shadow: var(--shadow-toast);
671
+ font-size: var(--fs-sm); font-weight: 500; line-height: 1.5;
672
+ animation: slideInUp var(--duration-toast) var(--ease-standard);
673
+ }
674
+ .toast-region > div { display: grid; gap: var(--sp-2); }
675
+ .toast-region > :empty { display: none; }
676
+ .drawer .toast-region { position: static; flex: 0 0 auto; max-width: none; max-height: min(30vh, 180px); overflow-y: auto; margin: 0 var(--sp-4); }
677
+ .drawer .toast { margin-bottom: var(--sp-3); }
678
+ .run-card .run-detail-button { align-self: flex-end; }
679
+ .agent-name > .badge { width: fit-content; }
680
+ .toast.error { background: hsl(var(--destructive)); color: hsl(var(--destructive-foreground)); }
681
+ @keyframes slideInUp { from { opacity: 0; transform: translateY(8px); } }
682
+
683
+ /* ── Responsive ───────────────────────────────────────────────────── */
684
+ @media (max-width: 1100px) {
685
+ /* Keep every key action visible when six columns no longer fit. The real
686
+ table headings stay in the accessibility tree while rows stack. */
687
+ .key-table { min-width: 0; }
688
+ .key-table thead {
689
+ position: absolute; width: 1px; height: 1px;
690
+ margin: -1px; padding: 0; overflow: hidden;
691
+ clip-path: inset(50%); white-space: nowrap;
692
+ }
693
+ .key-table tbody { display: grid; }
694
+ .key-table tbody tr {
695
+ display: grid; grid-template-columns: minmax(0, 1fr) auto;
696
+ gap: var(--sp-2) var(--sp-3); padding: var(--sp-4);
697
+ border-bottom: 1px solid hsl(var(--border));
698
+ }
699
+ .key-table tbody tr:last-child { border-bottom: 0; }
700
+ .key-table td { min-width: 0; height: auto; padding: 0; border: 0; }
701
+ .key-table td:nth-child(1) { grid-area: 1 / 1; }
702
+ .key-table td:nth-child(2) { grid-area: 2 / 1; }
703
+ .key-table td:nth-child(6) { grid-area: 1 / 2 / 3 / 3; }
704
+ .key-table td[data-label] { grid-column: 1 / -1; display: flex; align-items: baseline; gap: var(--sp-3); }
705
+ .key-table td[data-label]::before {
706
+ content: attr(data-label); flex: 0 0 60px;
707
+ color: hsl(var(--muted-foreground)); font-size: var(--fs-xs);
708
+ }
709
+ .key-table .agent-name strong {
710
+ display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
711
+ overflow-wrap: anywhere; white-space: normal;
712
+ }
713
+ .key-secret-cell { align-items: center; }
714
+ .key-scope, .key-last-used { min-width: 0; white-space: normal; overflow-wrap: anywhere; }
715
+ }
716
+ @media (max-width: 860px) {
717
+ :root { --sidebar-width: 56px; --gutter: var(--sp-4); }
718
+ /* 视觉隐藏而不是 display:none:图标栏里按钮的可访问名来自 span,
719
+ display:none 会让 6 个导航按钮在无障碍树上变成无名按钮。 */
720
+ .brand span:last-child, .nav-item span, .nav-group-label {
721
+ position: absolute; width: 1px; height: 1px;
722
+ margin: -1px; padding: 0; overflow: hidden;
723
+ clip-path: inset(50%); white-space: nowrap;
724
+ }
725
+ .brand, .nav-item { justify-content: center; }
726
+ .nav-group + .nav-group { padding-top: var(--sp-2); border-top: 1px solid hsl(var(--border)); }
727
+ }
728
+ @media (max-width: 640px) {
729
+ .page-content { padding: var(--sp-4) var(--gutter) var(--sp-4); }
730
+ .main.settings-page .page-content { padding-top: var(--sp-6); }
731
+ .settings-section + .settings-section { margin-top: 40px; padding-top: 40px; }
732
+ .settings-section-heading { margin-bottom: 24px; }
733
+ .settings-account-row { grid-template-columns: 1fr; gap: var(--sp-4); }
734
+ .search-box { max-width: none; }
735
+ .stats { grid-template-columns: 1fr; }
736
+ .run-summary { grid-template-columns: repeat(2, 1fr); }
737
+ .run-live-grid { grid-template-columns: minmax(0, 1fr); }
738
+ .toolbar input[type="search"], .toolbar select { max-width: none; width: 100%; }
739
+ .field-row { grid-template-columns: 1fr; }
740
+ .field-spacer { display: none; }
741
+ .drawer { width: 100%; }
742
+ .run-detail-grid { grid-template-columns: 1fr; }
743
+ .toast-region { right: var(--sp-4); bottom: var(--sp-4); left: var(--sp-4); max-width: none; }
744
+ }
745
+
746
+ /* Keep row actions and task context in the viewport on laptops and phones. */
747
+ @media (max-width: 1400px) {
748
+ .agent-table, .run-table { min-width: 0; }
749
+ .agent-table thead, .run-table thead {
750
+ position: absolute; width: 1px; height: 1px; padding: 0;
751
+ overflow: hidden; clip-path: inset(50%); white-space: nowrap;
752
+ }
753
+ .agent-table tbody, .run-table tbody { display: grid; }
754
+ .agent-table tbody tr, .run-table tbody tr {
755
+ display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
756
+ gap: var(--sp-3) var(--sp-6); padding: var(--sp-4); border-bottom: 1px solid hsl(var(--border));
757
+ }
758
+ .agent-table td, .run-table td {
759
+ min-width: 0; max-width: none !important; padding: 0; height: auto;
760
+ border: 0; white-space: normal !important; overflow-wrap: anywhere; text-align: left !important;
761
+ }
762
+ .agent-table td::before, .run-table td::before { display: block; font-size: var(--fs-xs); color: hsl(var(--muted-foreground)); margin-bottom: var(--sp-1); }
763
+ .agent-table td:nth-child(2)::before { content: '协议'; }
764
+ .agent-table td:nth-child(3)::before { content: '驱动'; }
765
+ .agent-table td:nth-child(4)::before { content: '探测状态'; }
766
+ .agent-table td:nth-child(5)::before { content: '默认工作区'; }
767
+ .agent-table td:nth-child(6)::before { content: '权限策略'; }
768
+ .run-table td:nth-child(2)::before { content: '任务'; }
769
+ .run-table td:nth-child(3)::before { content: '结果'; }
770
+ .run-table td:nth-child(4)::before { content: '状态'; }
771
+ .run-table td:nth-child(5)::before { content: '开始时间'; }
772
+ .run-table td:nth-child(6)::before { content: '耗时'; }
773
+ .agent-table td:last-child, .run-table td:last-child, td[colspan] { grid-column: 1 / -1; }
774
+ .agent-table .row-actions { justify-content: flex-start; }
775
+ .agent-table .button.small, .run-table .button.small { min-height: 36px; }
776
+ }
777
+ @media (max-width: 560px) {
778
+ .agent-table tbody tr, .run-table tbody tr { grid-template-columns: minmax(0, 1fr); }
779
+ .run-pagination { align-items: flex-start; }
780
+ }
781
+
782
+ /* ── Reduced motion ───────────────────────────────────────────────── */
783
+ /* 统一压制而不是逐个列举消费者,这样以后新增的 transition 不会漏掉。
784
+ running/waiting 的 pulse 停下后,色点和文字标签仍然表达状态。 */
785
+ @media (prefers-reduced-motion: reduce) {
786
+ *, *::before, *::after {
787
+ animation-duration: .01ms !important;
788
+ animation-iteration-count: 1 !important;
789
+ transition-duration: .01ms !important;
790
+ }
791
+ }
617
792
  `;