shadok-ai 0.15.35 → 0.15.37
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 +1 -1
- package/package.json +1 -1
- package/public/index.html +117 -89
package/README.md
CHANGED
|
@@ -255,7 +255,7 @@ Enter to skip; you can add it later from the web UI).
|
|
|
255
255
|
folds away while you type). Fields are 16px, which is what stops Safari from
|
|
256
256
|
zooming in on focus. The agents column is replaced by a channel selector in
|
|
257
257
|
the channel bar.
|
|
258
|
-
- **Tweak Shadok-AI** — a card pinned at the bottom of the agents column. One
|
|
258
|
+
- **Tweak Shadok-AI** — a card pinned at the bottom of the agents column, with the running version in grey beside its title (the code a tweak starts from). One
|
|
259
259
|
click clones shadok-ai's own source into `~/.shadok-ai/self/shadok-ai` and
|
|
260
260
|
starts an agent on it in its own worktree; that agent delivers its change as a
|
|
261
261
|
**pull request** — a fork under your GitHub account, since you need no rights
|
package/package.json
CHANGED
package/public/index.html
CHANGED
|
@@ -14,6 +14,10 @@
|
|
|
14
14
|
<link rel="icon" id="favicon" href="data:image/svg+xml,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20viewBox%3D%220%200%2032%2032%22%3E%3Crect%20width%3D%2232%22%20height%3D%2232%22%20rx%3D%227%22%20fill%3D%22%2314161d%22%2F%3E%3Cline%20x1%3D%2210.8%22%20y1%3D%2223%22%20x2%3D%2210.4%22%20y2%3D%2230.6%22%20stroke%3D%22%23f0a848%22%20stroke-width%3D%221.3%22%20stroke-linecap%3D%22round%22%2F%3E%3Cline%20x1%3D%2216.400000000000002%22%20y1%3D%2223%22%20x2%3D%2216.8%22%20y2%3D%2230.6%22%20stroke%3D%22%23f0a848%22%20stroke-width%3D%221.3%22%20stroke-linecap%3D%22round%22%2F%3E%3Cline%20x1%3D%228.8%22%20y1%3D%2230.7%22%20x2%3D%2211.9%22%20y2%3D%2230.7%22%20stroke%3D%22%23f0a848%22%20stroke-width%3D%221.3%22%20stroke-linecap%3D%22round%22%2F%3E%3Cline%20x1%3D%2215.4%22%20y1%3D%2230.7%22%20x2%3D%2218.5%22%20y2%3D%2230.7%22%20stroke%3D%22%23f0a848%22%20stroke-width%3D%221.3%22%20stroke-linecap%3D%22round%22%2F%3E%3Cline%20x1%3D%2219.6%22%20y1%3D%2217.2%22%20x2%3D%2224.000000000000004%22%20y2%3D%2220.4%22%20stroke%3D%22%23f0a848%22%20stroke-width%3D%221.3%22%20stroke-linecap%3D%22round%22%2F%3E%3Cg%3E%3Cline%20x1%3D%2211.600000000000001%22%20y1%3D%225.399999999999999%22%20x2%3D%229.600000000000001%22%20y2%3D%222.8%22%20stroke%3D%22%23f0a848%22%20stroke-width%3D%220.9%22%20stroke-linecap%3D%22round%22%2F%3E%3Ccircle%20cx%3D%229.600000000000001%22%20cy%3D%222.8%22%20r%3D%221%22%20fill%3D%22%23f0a848%22%2F%3E%3Cline%20x1%3D%2216%22%20y1%3D%225.399999999999999%22%20x2%3D%2218%22%20y2%3D%222.8%22%20stroke%3D%22%23f0a848%22%20stroke-width%3D%220.9%22%20stroke-linecap%3D%22round%22%2F%3E%3Ccircle%20cx%3D%2218%22%20cy%3D%222.8%22%20r%3D%221%22%20fill%3D%22%23f0a848%22%2F%3E%3Ccircle%20cx%3D%2213.8%22%20cy%3D%2216.2%22%20r%3D%228.4%22%20fill%3D%22%23f0a848%22%2F%3E%3Cpath%20d%3D%22M12.200000000000001%2018.2%20L15.4%2018.2%20L13.8%2021.6%20Z%22%20fill%3D%22%23f0a848%22%2F%3E%3Ccircle%20cx%3D%2210.9%22%20cy%3D%227.799999999999999%22%20r%3D%222.6%22%20fill%3D%22%23fff%22%2F%3E%3Ccircle%20cx%3D%2216.7%22%20cy%3D%227.799999999999999%22%20r%3D%222.6%22%20fill%3D%22%23fff%22%2F%3E%3Ccircle%20cx%3D%2211.200000000000001%22%20cy%3D%228.1%22%20r%3D%221.3%22%20fill%3D%22%2314161d%22%2F%3E%3Ccircle%20cx%3D%2217%22%20cy%3D%228.1%22%20r%3D%221.3%22%20fill%3D%22%2314161d%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E">
|
|
15
15
|
<style>
|
|
16
16
|
:root {
|
|
17
|
+
/* The page the panels sit on: a shade darker than --bg, so the nav and the
|
|
18
|
+
conversation read as cards (the "sober" pass, 2026-10-28). */
|
|
19
|
+
--page: #0d0f14;
|
|
20
|
+
--radius: 12px;
|
|
17
21
|
--bg: #14161d;
|
|
18
22
|
--bg-raised: #1b1e27;
|
|
19
23
|
--bg-inset: #0e1015;
|
|
@@ -32,7 +36,9 @@
|
|
|
32
36
|
--menu-bg: #14140f;
|
|
33
37
|
--menu-hover: #26261c;
|
|
34
38
|
--mono: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
|
|
35
|
-
|
|
39
|
+
/* One sans for the whole interface; the mono is kept for what IS code —
|
|
40
|
+
code blocks, session ids, the terminal. */
|
|
41
|
+
--sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, Roboto, "Helvetica Neue", Arial, sans-serif;
|
|
36
42
|
}
|
|
37
43
|
/* Light mode. An ORTHOGONAL axis to the accent palette: only the base surfaces
|
|
38
44
|
and text flip; the instance's accent (--amber/--phosphor) stays its identity.
|
|
@@ -42,7 +48,8 @@
|
|
|
42
48
|
a pale amber on white. Accent-tinted surfaces (--amber-soft) derive from
|
|
43
49
|
--amber and follow on their own. */
|
|
44
50
|
:root[data-mode="light"] {
|
|
45
|
-
--
|
|
51
|
+
--page: #eef0f4;
|
|
52
|
+
--bg: #f7f8fa;
|
|
46
53
|
--bg-raised: #ffffff;
|
|
47
54
|
--bg-inset: #e5e8ee;
|
|
48
55
|
--line: #d2d7e0;
|
|
@@ -69,10 +76,11 @@
|
|
|
69
76
|
html, body { height: 100%; }
|
|
70
77
|
html { overflow: hidden; }
|
|
71
78
|
body {
|
|
72
|
-
background: var(--
|
|
79
|
+
background: var(--page);
|
|
73
80
|
color: var(--text);
|
|
74
81
|
font-family: var(--sans);
|
|
75
|
-
font-size:
|
|
82
|
+
font-size: 14px;
|
|
83
|
+
-webkit-font-smoothing: antialiased;
|
|
76
84
|
display: flex;
|
|
77
85
|
flex-direction: column;
|
|
78
86
|
/* Fixed chassis: the page never scrolls — only the inner panels (channel
|
|
@@ -101,17 +109,16 @@
|
|
|
101
109
|
reports. Set from `visualViewport` (see `syncViewport`), touch only. */
|
|
102
110
|
body { height: 100dvh; }
|
|
103
111
|
body.vv-sized { height: var(--app-h); }
|
|
112
|
+
/* Labels read as quiet sentence-case captions, not stamped capitals. */
|
|
104
113
|
.label {
|
|
105
|
-
font-
|
|
106
|
-
font-
|
|
107
|
-
letter-spacing: 0.18em;
|
|
108
|
-
text-transform: uppercase;
|
|
114
|
+
font-size: 12px;
|
|
115
|
+
font-weight: 500;
|
|
109
116
|
color: var(--text-dim);
|
|
110
117
|
}
|
|
111
118
|
/* Message time, hooked onto the speaker's label. Paler and less spaced out
|
|
112
119
|
than the label: there for whoever looks for it, quiet otherwise. */
|
|
113
120
|
.label .time {
|
|
114
|
-
|
|
121
|
+
font-weight: 400;
|
|
115
122
|
opacity: 0.6;
|
|
116
123
|
}
|
|
117
124
|
.label .time::before {
|
|
@@ -126,8 +133,7 @@
|
|
|
126
133
|
align-items: center;
|
|
127
134
|
gap: 12px;
|
|
128
135
|
padding: 10px 16px;
|
|
129
|
-
|
|
130
|
-
background: var(--bg-raised);
|
|
136
|
+
background: var(--page);
|
|
131
137
|
flex-wrap: wrap;
|
|
132
138
|
}
|
|
133
139
|
/* Keep the toolbar buttons together so they never split across lines. */
|
|
@@ -156,11 +162,11 @@
|
|
|
156
162
|
#starBtn:hover { border-color: var(--amber); color: var(--amber); }
|
|
157
163
|
#starBtn:hover .star-count { color: var(--amber); }
|
|
158
164
|
header .brand {
|
|
159
|
-
font-
|
|
160
|
-
font-
|
|
161
|
-
color: var(--
|
|
162
|
-
letter-spacing: 0.06em;
|
|
165
|
+
font-size: 15px;
|
|
166
|
+
font-weight: 700;
|
|
167
|
+
color: var(--text);
|
|
163
168
|
}
|
|
169
|
+
header .brand::before { color: var(--amber); }
|
|
164
170
|
header .brand::before { content: "◆ "; }
|
|
165
171
|
/* The brand name doubles as the cockpit's editable title: click to rename,
|
|
166
172
|
Enter/blur commits, Escape cancels. A dashed outline + pencil on hover make
|
|
@@ -225,7 +231,7 @@
|
|
|
225
231
|
#verMenu {
|
|
226
232
|
position: fixed; top: 42px; left: 12px; z-index: 1001;
|
|
227
233
|
background: var(--menu-bg); border: 1px solid var(--line); border-radius: 6px;
|
|
228
|
-
padding: 10px 12px; font-family: var(--
|
|
234
|
+
padding: 10px 12px; font-family: var(--sans); font-size: 12px;
|
|
229
235
|
min-width: 210px; box-shadow: 0 6px 20px rgba(0,0,0,0.5);
|
|
230
236
|
}
|
|
231
237
|
#verMenu .vm-row { display: flex; justify-content: space-between; gap: 16px; margin-bottom: 4px; }
|
|
@@ -241,7 +247,7 @@
|
|
|
241
247
|
#tabMenu {
|
|
242
248
|
position: fixed; z-index: 1002;
|
|
243
249
|
background: var(--menu-bg); border: 1px solid var(--line); border-radius: 6px;
|
|
244
|
-
padding: 4px; font-family: var(--
|
|
250
|
+
padding: 4px; font-family: var(--sans); font-size: 12px;
|
|
245
251
|
min-width: 170px; box-shadow: 0 6px 20px rgba(0,0,0,0.5);
|
|
246
252
|
}
|
|
247
253
|
#tabMenu .tm-item {
|
|
@@ -298,7 +304,7 @@
|
|
|
298
304
|
#updateBanner {
|
|
299
305
|
position: fixed; top: 0; left: 0; right: 0; z-index: 1000;
|
|
300
306
|
background: var(--amber); color: #1a1200;
|
|
301
|
-
font-family: var(--
|
|
307
|
+
font-family: var(--sans); font-size: 12px; text-align: center;
|
|
302
308
|
padding: 6px 12px;
|
|
303
309
|
}
|
|
304
310
|
/* The re-login reminder (sign-in within 48h / expired). Same top strip as the
|
|
@@ -306,7 +312,7 @@
|
|
|
306
312
|
#expiryBanner {
|
|
307
313
|
position: fixed; top: 0; left: 0; right: 0; z-index: 1000;
|
|
308
314
|
background: var(--amber); color: #1a1200;
|
|
309
|
-
font-family: var(--
|
|
315
|
+
font-family: var(--sans); font-size: 12px;
|
|
310
316
|
padding: 6px 12px;
|
|
311
317
|
display: flex; gap: 10px; align-items: center; justify-content: center; flex-wrap: wrap;
|
|
312
318
|
}
|
|
@@ -317,7 +323,7 @@
|
|
|
317
323
|
}
|
|
318
324
|
.gauge { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
|
|
319
325
|
.gauge .value {
|
|
320
|
-
font-family: var(--
|
|
326
|
+
font-family: var(--sans);
|
|
321
327
|
font-size: 12px;
|
|
322
328
|
color: var(--text);
|
|
323
329
|
white-space: nowrap;
|
|
@@ -385,23 +391,25 @@
|
|
|
385
391
|
.dial .needle, .dial .pct { transition: none; }
|
|
386
392
|
}
|
|
387
393
|
button {
|
|
388
|
-
font-family: var(--
|
|
389
|
-
font-size:
|
|
390
|
-
|
|
394
|
+
font-family: var(--sans);
|
|
395
|
+
font-size: 13px;
|
|
396
|
+
font-weight: 500;
|
|
391
397
|
background: transparent;
|
|
392
398
|
color: var(--text);
|
|
393
399
|
border: 1px solid var(--line);
|
|
394
|
-
border-radius:
|
|
400
|
+
border-radius: 8px;
|
|
395
401
|
padding: 6px 12px;
|
|
396
402
|
cursor: pointer;
|
|
403
|
+
transition: background 0.12s, color 0.12s, border-color 0.12s;
|
|
397
404
|
}
|
|
398
|
-
/*
|
|
405
|
+
/* Icon buttons carry no frame: a soft fill on hover is the whole affordance. */
|
|
399
406
|
header button.icon {
|
|
400
|
-
padding:
|
|
407
|
+
padding: 7px 9px;
|
|
401
408
|
font-size: 14px;
|
|
402
409
|
line-height: 1;
|
|
403
|
-
|
|
410
|
+
border-color: transparent;
|
|
404
411
|
}
|
|
412
|
+
header button.icon:hover { background: var(--bg-raised); border-color: transparent; color: var(--text); }
|
|
405
413
|
header button.icon.stop:hover { border-color: var(--err); color: var(--err); }
|
|
406
414
|
/* The bell's diagonal slash shows only when notifications are muted. */
|
|
407
415
|
#muteNotif:not(.muted) .mute-slash { display: none; }
|
|
@@ -431,7 +439,7 @@
|
|
|
431
439
|
.mm-tools:empty { display: none; }
|
|
432
440
|
#moreMenu .mm-tools button { width: auto; } /* override #moreMenu button width:100% */
|
|
433
441
|
#moreMenu .mm-sep { height: 1px; background: var(--line); margin: 4px 2px; }
|
|
434
|
-
#moreMenu .mm-label { padding: 2px 4px; font-size:
|
|
442
|
+
#moreMenu .mm-label { padding: 2px 4px; font-size: 12px; font-weight: 500; color: var(--text-dim); }
|
|
435
443
|
.mm-themes { display: flex; gap: 6px; padding: 2px 4px 4px; }
|
|
436
444
|
/* Swatch buttons must override `#moreMenu button { width:100% }` — hence the
|
|
437
445
|
id-scoped selector so specificity wins. */
|
|
@@ -450,9 +458,10 @@
|
|
|
450
458
|
}
|
|
451
459
|
#moreMenu .mm-mode button:hover { border-color: var(--text-dim); color: var(--text); }
|
|
452
460
|
#moreMenu .mm-mode button.active { border-color: var(--amber); color: var(--amber); background: color-mix(in srgb, var(--amber) 12%, transparent); }
|
|
453
|
-
button:hover { border-color: var(--
|
|
461
|
+
button:hover { background: var(--bg-inset); border-color: var(--line); color: var(--text); }
|
|
454
462
|
button:focus-visible { outline: 2px solid var(--amber); outline-offset: 2px; }
|
|
455
463
|
button.primary { background: var(--amber); border-color: var(--amber); color: #1a1205; font-weight: 600; }
|
|
464
|
+
button.primary:hover { background: var(--amber); border-color: var(--amber); color: #1a1205; }
|
|
456
465
|
button.primary:hover { filter: brightness(1.1); }
|
|
457
466
|
button:disabled { opacity: 0.4; cursor: default; }
|
|
458
467
|
|
|
@@ -464,22 +473,22 @@
|
|
|
464
473
|
flex-direction: column;
|
|
465
474
|
gap: 2px;
|
|
466
475
|
background: var(--bg-raised);
|
|
467
|
-
border
|
|
476
|
+
border: 1px solid var(--line);
|
|
477
|
+
border-radius: var(--radius);
|
|
468
478
|
padding: 12px 8px;
|
|
469
479
|
overflow-y: auto;
|
|
470
480
|
}
|
|
471
|
-
#tabbar .side-label { padding: 0 8px 8px; }
|
|
481
|
+
#tabbar .side-label { padding: 0 8px 8px; font-size: 13px; font-weight: 600; color: var(--text); }
|
|
472
482
|
.tab {
|
|
473
483
|
position: relative;
|
|
474
484
|
display: flex;
|
|
475
485
|
flex-direction: column; /* row 1 (led+name+icons) then row 2 (info) */
|
|
476
486
|
gap: 1px;
|
|
477
|
-
font-
|
|
478
|
-
font-size: 12px;
|
|
487
|
+
font-size: 14px;
|
|
479
488
|
color: var(--text-dim);
|
|
480
489
|
border-left: 2px solid transparent;
|
|
481
|
-
border-radius:
|
|
482
|
-
padding:
|
|
490
|
+
border-radius: 8px;
|
|
491
|
+
padding: 8px 10px 10px;
|
|
483
492
|
cursor: pointer;
|
|
484
493
|
user-select: none;
|
|
485
494
|
}
|
|
@@ -497,7 +506,7 @@
|
|
|
497
506
|
right: 10px;
|
|
498
507
|
bottom: 3px;
|
|
499
508
|
height: 2px;
|
|
500
|
-
background:
|
|
509
|
+
background: transparent;
|
|
501
510
|
border-radius: 1px;
|
|
502
511
|
overflow: hidden;
|
|
503
512
|
}
|
|
@@ -521,7 +530,7 @@
|
|
|
521
530
|
color: var(--text);
|
|
522
531
|
font-weight: 600;
|
|
523
532
|
border-left-color: var(--phosphor);
|
|
524
|
-
border-radius: 0
|
|
533
|
+
border-radius: 0 8px 8px 0;
|
|
525
534
|
box-shadow: inset 3px 0 0 var(--phosphor);
|
|
526
535
|
}
|
|
527
536
|
/* Full-width row 2: "xxx ago" on the left, context % hard right. */
|
|
@@ -541,8 +550,7 @@
|
|
|
541
550
|
.tab input.rename {
|
|
542
551
|
flex: 1;
|
|
543
552
|
min-width: 0;
|
|
544
|
-
font-
|
|
545
|
-
font-size: 12px;
|
|
553
|
+
font-size: 13px;
|
|
546
554
|
background: var(--bg-inset);
|
|
547
555
|
border: 1px solid var(--amber);
|
|
548
556
|
border-radius: 3px;
|
|
@@ -591,13 +599,14 @@
|
|
|
591
599
|
}
|
|
592
600
|
@media (prefers-reduced-motion: reduce) { .tab.working, .tab.has-bg { animation: none; } }
|
|
593
601
|
#newTab, #newGroup, #newGroupBare {
|
|
594
|
-
margin-top:
|
|
595
|
-
border:
|
|
596
|
-
font-size:
|
|
602
|
+
margin-top: 6px;
|
|
603
|
+
border-color: transparent;
|
|
604
|
+
font-size: 13px;
|
|
597
605
|
color: var(--text-dim);
|
|
598
|
-
padding: 8px;
|
|
606
|
+
padding: 8px 10px;
|
|
607
|
+
text-align: left;
|
|
599
608
|
}
|
|
600
|
-
#newTab:hover, #newGroup:hover, #newGroupBare:hover { color: var(--amber);
|
|
609
|
+
#newTab:hover, #newGroup:hover, #newGroupBare:hover { color: var(--amber); background: var(--amber-soft); border-color: transparent; }
|
|
601
610
|
#newGroup { margin-top: 4px; }
|
|
602
611
|
/* The fallback "new group" entry: only on desktop, only while the rail (which
|
|
603
612
|
has its own) is hidden for want of a group. */
|
|
@@ -618,7 +627,7 @@
|
|
|
618
627
|
padding-top: 8px;
|
|
619
628
|
background: var(--bg-raised);
|
|
620
629
|
/* Separates it from the list scrolling underneath, with no extra rule. */
|
|
621
|
-
box-shadow: 0 -8px 10px -
|
|
630
|
+
box-shadow: 0 -8px 10px -10px rgba(0, 0, 0, 0.35);
|
|
622
631
|
}
|
|
623
632
|
/* The tweak channel's tab keeps its slot's tint, so it is recognisable in the
|
|
624
633
|
same place as before it was started. */
|
|
@@ -633,18 +642,22 @@
|
|
|
633
642
|
gap: 2px;
|
|
634
643
|
text-align: left;
|
|
635
644
|
padding: 8px;
|
|
636
|
-
border: 1px solid var(--amber);
|
|
637
|
-
border-radius:
|
|
645
|
+
border: 1px solid color-mix(in srgb, var(--amber) 45%, transparent);
|
|
646
|
+
border-radius: 10px;
|
|
638
647
|
width: 100%;
|
|
639
648
|
background: linear-gradient(var(--amber-soft), var(--amber-soft)), var(--bg-raised);
|
|
640
649
|
}
|
|
641
650
|
#tweakCta .tweak-title {
|
|
642
|
-
font-family: var(--
|
|
643
|
-
font-size:
|
|
651
|
+
font-family: var(--sans);
|
|
652
|
+
font-size: 13px;
|
|
644
653
|
font-weight: 600;
|
|
645
654
|
color: var(--amber);
|
|
646
655
|
}
|
|
647
|
-
|
|
656
|
+
/* The running version beside the title: the code a tweak starts from. Its own
|
|
657
|
+
span, because the title's text is rewritten while the source is fetched. */
|
|
658
|
+
#tweakCta .tweak-row { display: flex; align-items: baseline; gap: 8px; }
|
|
659
|
+
#tweakCta .tweak-ver { margin-left: auto; font-family: var(--mono); font-size: 11px; color: var(--text-dim); }
|
|
660
|
+
#tweakCta .tweak-sub { font-size: 11px; color: var(--text-dim); }
|
|
648
661
|
#tweakCta .tweak-arrow { display: inline-block; transition: transform 0.15s ease; }
|
|
649
662
|
/* No permanent animation: an element blinking here would compete with the
|
|
650
663
|
real signals (a waiting tab, the gauges) and would turn into noise. */
|
|
@@ -662,12 +675,11 @@
|
|
|
662
675
|
display: flex;
|
|
663
676
|
align-items: center;
|
|
664
677
|
gap: 6px;
|
|
665
|
-
font-family: var(--
|
|
666
|
-
font-size:
|
|
667
|
-
|
|
668
|
-
text-transform: uppercase;
|
|
678
|
+
font-family: var(--sans);
|
|
679
|
+
font-size: 12px;
|
|
680
|
+
font-weight: 600;
|
|
669
681
|
color: var(--text-dim);
|
|
670
|
-
border-radius:
|
|
682
|
+
border-radius: 6px;
|
|
671
683
|
padding: 5px 8px;
|
|
672
684
|
cursor: pointer;
|
|
673
685
|
user-select: none;
|
|
@@ -683,7 +695,7 @@
|
|
|
683
695
|
.group-head input.rename {
|
|
684
696
|
flex: 1;
|
|
685
697
|
min-width: 0;
|
|
686
|
-
font-family: var(--
|
|
698
|
+
font-family: var(--sans);
|
|
687
699
|
font-size: 11px;
|
|
688
700
|
text-transform: none;
|
|
689
701
|
letter-spacing: normal;
|
|
@@ -719,13 +731,19 @@
|
|
|
719
731
|
/* The column only earns its space once a group exists: with none, the
|
|
720
732
|
cockpit is the single agents list it always was (body.has-groups is set
|
|
721
733
|
from groups.length in applyView). */
|
|
734
|
+
/* The rail and the agents column are ONE card: the rail is its tinted
|
|
735
|
+
left half, the agents column its right half. */
|
|
722
736
|
body.has-groups #groupRail {
|
|
723
737
|
width: 190px; flex: none;
|
|
724
738
|
display: flex; flex-direction: column; gap: 2px;
|
|
725
739
|
background: var(--bg-inset);
|
|
726
|
-
border
|
|
740
|
+
border: 1px solid var(--line); border-right: none;
|
|
741
|
+
border-radius: var(--radius) 0 0 var(--radius);
|
|
727
742
|
padding: 12px 8px; overflow-y: auto;
|
|
728
743
|
}
|
|
744
|
+
body.has-groups #tabbar { border-radius: 0 var(--radius) var(--radius) 0; }
|
|
745
|
+
/* Cancel <main>'s gap between the two halves of the card. */
|
|
746
|
+
body.has-groups #groupRail { margin-right: -12px; }
|
|
729
747
|
.rail-head { display: flex; align-items: center; justify-content: space-between; padding: 0 4px 8px 8px; }
|
|
730
748
|
#railMini { border: none; background: none; padding: 2px 6px; color: var(--text-dim); font-size: 13px; }
|
|
731
749
|
#railMini:hover { color: var(--amber); }
|
|
@@ -752,7 +770,7 @@
|
|
|
752
770
|
background: var(--bg-inset); border: 1px solid var(--amber); border-radius: 3px;
|
|
753
771
|
color: var(--text); padding: 2px 5px;
|
|
754
772
|
}
|
|
755
|
-
.rail-count { flex: none; font-family: var(--
|
|
773
|
+
.rail-count { flex: none; font-family: var(--sans); font-size: 10px; color: var(--text-dim); }
|
|
756
774
|
/* What a group that is not on screen asks of you — the single place it shows. */
|
|
757
775
|
.rail-dot { flex: none; width: 7px; height: 7px; border-radius: 50%; display: none; }
|
|
758
776
|
.rail-item.needs-answer .rail-dot { display: block; background: var(--amber); animation: breathe 1.2s ease-in-out infinite; }
|
|
@@ -777,8 +795,8 @@
|
|
|
777
795
|
.rail-add:hover { color: var(--amber); }
|
|
778
796
|
.rail-del:hover { color: var(--err); }
|
|
779
797
|
#groupRail #newGroup {
|
|
780
|
-
margin-top:
|
|
781
|
-
font-size:
|
|
798
|
+
margin-top: 6px; border-color: transparent; text-align: left;
|
|
799
|
+
font-size: 13px; color: var(--text-dim); padding: 8px 10px;
|
|
782
800
|
}
|
|
783
801
|
#groupRail #newGroup:hover { color: var(--amber); border-color: var(--amber); }
|
|
784
802
|
/* Collapsed to icons, like a dock: the names live in the tooltips. */
|
|
@@ -827,11 +845,16 @@
|
|
|
827
845
|
.icon-picker input { width: 100%; font-size: 13px; box-sizing: border-box; }
|
|
828
846
|
|
|
829
847
|
/* ── Body ────────────────────────────────────────────── */
|
|
830
|
-
|
|
848
|
+
/* The panels are cards on the page: a gap around them, rounded corners.
|
|
849
|
+
A phone keeps edge-to-edge panels (see the mobile query). */
|
|
850
|
+
main { flex: 1; display: flex; min-height: 0; padding: 0 12px 12px; gap: 12px; }
|
|
831
851
|
/* min-height:0 so the transcript (flex:1) bounds the height instead of pushing
|
|
832
852
|
the chassis; overflow-y:auto keeps the setup screen reachable when it
|
|
833
853
|
overflows (with a session running the transcript fits exactly → inert). */
|
|
834
|
-
.chat-pane {
|
|
854
|
+
.chat-pane {
|
|
855
|
+
flex: 1; display: flex; flex-direction: column; min-width: 0; min-height: 0; overflow-y: auto; position: relative;
|
|
856
|
+
background: var(--bg); border: 1px solid var(--line); border-radius: var(--radius);
|
|
857
|
+
}
|
|
835
858
|
/* File drag-and-drop target: a dashed accent overlay while a file hovers.
|
|
836
859
|
pointer-events:none so the drop still lands on the pane underneath. */
|
|
837
860
|
.chat-pane.dropping::after {
|
|
@@ -846,7 +869,7 @@
|
|
|
846
869
|
|
|
847
870
|
.field { display: flex; flex-direction: column; gap: 6px; }
|
|
848
871
|
input[type="text"] {
|
|
849
|
-
font-family: var(--
|
|
872
|
+
font-family: var(--sans);
|
|
850
873
|
font-size: 13px;
|
|
851
874
|
background: var(--bg-inset);
|
|
852
875
|
border: 1px solid var(--line);
|
|
@@ -909,7 +932,7 @@
|
|
|
909
932
|
.profile-card.selected { border-color: var(--amber); box-shadow: inset 0 0 0 1px var(--amber); }
|
|
910
933
|
.profile-card.selected .pc-name { color: var(--amber); }
|
|
911
934
|
.profile-card:focus-visible { outline: 2px solid var(--amber); outline-offset: 1px; }
|
|
912
|
-
.pc-name { font-
|
|
935
|
+
.pc-name { font-size: 14px; font-weight: 600; }
|
|
913
936
|
.pc-blurb {
|
|
914
937
|
color: var(--text-dim); font-size: 11.5px; line-height: 1.35;
|
|
915
938
|
display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
|
|
@@ -1081,8 +1104,8 @@
|
|
|
1081
1104
|
.turn.user { align-self: flex-end; align-items: flex-end; }
|
|
1082
1105
|
.turn.claude { align-self: flex-start; }
|
|
1083
1106
|
.bubble {
|
|
1084
|
-
padding:
|
|
1085
|
-
border-radius:
|
|
1107
|
+
padding: 9px 14px;
|
|
1108
|
+
border-radius: 14px;
|
|
1086
1109
|
font-size: 14px;
|
|
1087
1110
|
line-height: 1.4;
|
|
1088
1111
|
white-space: pre-wrap;
|
|
@@ -1134,10 +1157,11 @@
|
|
|
1134
1157
|
color: #fff; border-radius: 50%; width: 16px; height: 16px; font-size: 9px; line-height: 1; cursor: pointer; padding: 0; }
|
|
1135
1158
|
.cmp-att .cmp-x:hover { background: var(--err); }
|
|
1136
1159
|
.turn.claude .bubble {
|
|
1137
|
-
background: var(--bg-
|
|
1160
|
+
background: var(--bg-raised);
|
|
1138
1161
|
border: 1px solid var(--line);
|
|
1139
|
-
font-family: var(--
|
|
1140
|
-
font-size:
|
|
1162
|
+
font-family: var(--sans);
|
|
1163
|
+
font-size: 14px;
|
|
1164
|
+
line-height: 1.55;
|
|
1141
1165
|
/* Wrap long prose lines so nothing is clipped; still preserves the
|
|
1142
1166
|
TUI's own newlines. (Wide tables come through history as real HTML.) */
|
|
1143
1167
|
white-space: pre-wrap;
|
|
@@ -1152,7 +1176,7 @@
|
|
|
1152
1176
|
.turn.claude.live-preview .bubble {
|
|
1153
1177
|
opacity: 0.55;
|
|
1154
1178
|
white-space: pre-wrap;
|
|
1155
|
-
font-family: var(--
|
|
1179
|
+
font-family: var(--sans);
|
|
1156
1180
|
}
|
|
1157
1181
|
.turn.claude.live-preview .bubble::after {
|
|
1158
1182
|
content: "▍";
|
|
@@ -1433,7 +1457,7 @@
|
|
|
1433
1457
|
.validate { align-self: flex-end; margin-top: 2px; }
|
|
1434
1458
|
.freetext-row { display: flex; gap: 8px; width: 100%; }
|
|
1435
1459
|
.freetext-row input { flex: 1; }
|
|
1436
|
-
#thinking { display: none; align-self: flex-start; color: var(--text-dim); font-family: var(--
|
|
1460
|
+
#thinking { display: none; align-self: flex-start; color: var(--text-dim); font-family: var(--sans); font-size: 12.5px; padding: 0 22px 6px; }
|
|
1437
1461
|
#thinking.visible { display: flex; align-items: center; gap: 6px; }
|
|
1438
1462
|
/* Shimmering text (an amber sweep) + a little Shadok pumping alongside. */
|
|
1439
1463
|
#thinking .tw-text {
|
|
@@ -1460,9 +1484,8 @@
|
|
|
1460
1484
|
gap: 10px;
|
|
1461
1485
|
/* The bottom padding absorbs the home indicator (viewport-fit=cover): without
|
|
1462
1486
|
it the field slides under it and half the text becomes unreadable. */
|
|
1463
|
-
padding:
|
|
1464
|
-
|
|
1465
|
-
background: var(--bg-raised);
|
|
1487
|
+
padding: 12px 16px calc(14px + env(safe-area-inset-bottom, 0px));
|
|
1488
|
+
background: var(--bg);
|
|
1466
1489
|
}
|
|
1467
1490
|
#composer textarea {
|
|
1468
1491
|
flex: 1;
|
|
@@ -1471,17 +1494,17 @@
|
|
|
1471
1494
|
min-width: 0;
|
|
1472
1495
|
font-family: var(--sans);
|
|
1473
1496
|
font-size: 14px;
|
|
1474
|
-
background: var(--bg-
|
|
1497
|
+
background: var(--bg-raised);
|
|
1475
1498
|
color: var(--text);
|
|
1476
1499
|
border: 1px solid var(--line);
|
|
1477
|
-
border-radius:
|
|
1478
|
-
padding:
|
|
1500
|
+
border-radius: var(--radius);
|
|
1501
|
+
padding: 11px 14px;
|
|
1479
1502
|
resize: none;
|
|
1480
1503
|
min-height: 42px;
|
|
1481
1504
|
max-height: 160px;
|
|
1482
1505
|
line-height: 1.45;
|
|
1483
1506
|
}
|
|
1484
|
-
#composer textarea:focus-visible { outline:
|
|
1507
|
+
#composer textarea:focus-visible { outline: none; border-color: var(--amber); box-shadow: 0 0 0 3px var(--amber-soft); }
|
|
1485
1508
|
|
|
1486
1509
|
/* ── Engine room (live terminal) ─────────────────────── */
|
|
1487
1510
|
#machine {
|
|
@@ -1523,13 +1546,13 @@
|
|
|
1523
1546
|
channel's actions only existed in terminal mode; it now sits above both
|
|
1524
1547
|
views, and `hidden` only removes it while the "New agent" form is up (no
|
|
1525
1548
|
channel to act on yet). */
|
|
1526
|
-
#chanBar { display: flex; align-items: center; gap:
|
|
1549
|
+
#chanBar { display: flex; align-items: center; gap: 10px; padding: 10px 14px; border-bottom: 1px solid var(--line); background: var(--bg-raised); font-size: 13px; }
|
|
1527
1550
|
#chanBar[hidden] { display: none; }
|
|
1528
1551
|
#chanBar .label { color: var(--text-dim); }
|
|
1529
|
-
#chanBar #chanBarName { color: var(--
|
|
1552
|
+
#chanBar #chanBarName { color: var(--text); font-size: 14px; font-weight: 600; }
|
|
1530
1553
|
/* Channel actions on the right of the bar (icons like the header). */
|
|
1531
1554
|
.chan-actions { margin-left: auto; display: flex; align-items: center; gap: 6px; }
|
|
1532
|
-
#chanBar button.icon { padding:
|
|
1555
|
+
#chanBar button.icon { padding: 6px 8px; font-size: 14px; line-height: 1; border-color: transparent; }
|
|
1533
1556
|
#chanBar button.icon.stop:hover { border-color: var(--err); color: var(--err); }
|
|
1534
1557
|
#chanBar button.icon.on { border-color: var(--amber); color: var(--amber); background: color-mix(in srgb, var(--amber) 15%, transparent); }
|
|
1535
1558
|
/* Reload-to-apply: a green, pulsing text pill (not a bare icon) so an available
|
|
@@ -1549,7 +1572,7 @@
|
|
|
1549
1572
|
shown as a compact "● name ▾" pill on a phone. */
|
|
1550
1573
|
#chanPicker {
|
|
1551
1574
|
display: none; align-items: center; gap: 6px;
|
|
1552
|
-
font-family: var(--
|
|
1575
|
+
font-family: var(--sans); font-size: 13px; cursor: pointer;
|
|
1553
1576
|
background: var(--bg-inset); color: var(--text);
|
|
1554
1577
|
border: 1px solid var(--line); border-radius: 6px; padding: 5px 8px;
|
|
1555
1578
|
max-width: 55vw;
|
|
@@ -1559,6 +1582,12 @@
|
|
|
1559
1582
|
body.picker-open #chanPicker { border-color: var(--amber); }
|
|
1560
1583
|
body.picker-open #chanPicker .pk-caret { transform: rotate(180deg); }
|
|
1561
1584
|
/* ── Mobile: sidebar hidden, navigation via the channel header's selector ── */
|
|
1585
|
+
/* A phone has no room for cards: panels go edge to edge, as before. */
|
|
1586
|
+
@media (max-width: 640px) {
|
|
1587
|
+
main { padding: 0; gap: 0; }
|
|
1588
|
+
.chat-pane { border: none; border-radius: 0; }
|
|
1589
|
+
#tabbar { border-radius: 0; }
|
|
1590
|
+
}
|
|
1562
1591
|
@media (max-width: 640px) {
|
|
1563
1592
|
#tabbar { display: none; }
|
|
1564
1593
|
#chanPicker { display: inline-flex; min-width: 0; }
|
|
@@ -1649,8 +1678,7 @@
|
|
|
1649
1678
|
}
|
|
1650
1679
|
#emptyState.visible, #startingState.visible { display: flex; }
|
|
1651
1680
|
#emptyState .es-title, #startingState .es-title {
|
|
1652
|
-
font-family: var(--
|
|
1653
|
-
letter-spacing: 0.18em; text-transform: uppercase; color: var(--text-dim);
|
|
1681
|
+
font-family: var(--sans); font-size: 15px; font-weight: 600; color: var(--text);
|
|
1654
1682
|
}
|
|
1655
1683
|
#emptyState .es-hint, #startingState .es-hint { color: var(--text-dim); font-size: 13px; line-height: 1.5; max-width: 44ch; }
|
|
1656
1684
|
.keys {
|
|
@@ -1783,7 +1811,7 @@
|
|
|
1783
1811
|
.preprompt { margin: 0 0 14px; border: 1px solid var(--line); border-radius: 8px; background: var(--bg-raised); }
|
|
1784
1812
|
.preprompt > summary {
|
|
1785
1813
|
cursor: pointer; padding: 8px 12px; color: var(--text-dim);
|
|
1786
|
-
font-size: 12px; font-family: var(--
|
|
1814
|
+
font-size: 12px; font-family: var(--sans); list-style: none;
|
|
1787
1815
|
}
|
|
1788
1816
|
.preprompt > summary::-webkit-details-marker { display: none; }
|
|
1789
1817
|
.preprompt > summary::before { content: "▸ "; }
|
|
@@ -1878,10 +1906,8 @@
|
|
|
1878
1906
|
/* Same treatment as the cockpit's labels (.label, channel bar): the popin
|
|
1879
1907
|
visibly belongs to the same family. */
|
|
1880
1908
|
.modal > .sec-head strong {
|
|
1881
|
-
font-family: var(--
|
|
1882
|
-
letter-spacing: 0.18em; text-transform: uppercase; color: var(--text-dim);
|
|
1909
|
+
font-family: var(--sans); font-size: 16px; font-weight: 600; color: var(--text);
|
|
1883
1910
|
}
|
|
1884
|
-
.modal > .sec-head strong .obj { color: var(--amber); }
|
|
1885
1911
|
.modal-body { flex: 1 1 auto; overflow: auto; padding: 14px 16px; }
|
|
1886
1912
|
.modal-foot {
|
|
1887
1913
|
flex: 0 0 auto; display: flex; align-items: center; justify-content: flex-end;
|
|
@@ -2596,7 +2622,7 @@
|
|
|
2596
2622
|
<div id="tweakSlot">
|
|
2597
2623
|
<button id="tweakCta" type="button"
|
|
2598
2624
|
title="Change shadok-ai itself — the agent works on a branch and opens a pull request">
|
|
2599
|
-
<span class="tweak-title">🛠 Tweak Shadok-AI <span class="tweak-arrow">›</span></span>
|
|
2625
|
+
<span class="tweak-row"><span class="tweak-title">🛠 Tweak Shadok-AI <span class="tweak-arrow">›</span></span><span class="tweak-ver" id="tweakVer"></span></span>
|
|
2600
2626
|
<span class="tweak-sub">change the cockpit itself</span>
|
|
2601
2627
|
</button>
|
|
2602
2628
|
</div>
|
|
@@ -6702,6 +6728,8 @@
|
|
|
6702
6728
|
return;
|
|
6703
6729
|
}
|
|
6704
6730
|
lastVersion = msg;
|
|
6731
|
+
const tv = document.getElementById("tweakVer");
|
|
6732
|
+
if (tv) tv.textContent = msg.current ? "v" + msg.current : "";
|
|
6705
6733
|
if (!verView) return;
|
|
6706
6734
|
const ahead = msg.latest && verIsNewer(msg.latest, msg.current);
|
|
6707
6735
|
verView.textContent = ahead ? "v" + msg.current + " → " + msg.latest : "v" + (msg.current || "?");
|