typebulb 0.20.4 → 0.21.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -70,8 +70,11 @@ body {
70
70
  line-height: 1.55;
71
71
  }
72
72
 
73
- /* position:relative anchors the overlaid (absolute) statusbar to the viewport box. */
74
- .app { position: relative; display: flex; flex-direction: column; height: 100vh; }
73
+ .app { display: flex; flex-direction: column; height: 100vh; }
74
+ /* The transcript region. position:relative anchors the overlaid (absolute) statusbar and banners to
75
+ THIS box, not the app: with a composer below the pills stay over the transcript's bottom edge
76
+ instead of landing on the input panel. */
77
+ .chat { position: relative; flex: 1; min-height: 0; display: flex; flex-direction: column; }
75
78
 
76
79
  /* Bottom status strip, overlaid (not in flow) on the chat — which runs
77
80
  full-height to the very bottom. The strip itself has NO fill, so the message
@@ -236,6 +239,154 @@ body {
236
239
  stay opaque over the message text the strip lets through. */
237
240
  .token.busy { border-color: var(--accent); --shimmer-base: var(--panel); --shimmer-mix: 25%; }
238
241
 
242
+ /* ── The composer (TB-Agent-Composer.md): the prompt panel under the transcript. In flow (not
243
+ overlaid like the statusbar) — it owns real height and must never cover content. ── */
244
+ .composer { position: relative; flex: none; background: var(--bg); }
245
+ /* A 4px drag zone centered on the composer's top border; z-index lifts it above the input-wrap
246
+ border so the line itself is grabbable. */
247
+ .splitter {
248
+ position: relative;
249
+ height: 4px;
250
+ margin-top: -2px;
251
+ margin-bottom: -2px;
252
+ z-index: 5;
253
+ cursor: row-resize;
254
+ background: transparent;
255
+ flex-shrink: 0;
256
+ }
257
+ .splitter:hover { background: color-mix(in srgb, var(--accent) 25%, transparent); }
258
+ .input-wrap { position: relative; border-top: 1px solid var(--border); }
259
+ .composer-input {
260
+ width: 100%;
261
+ display: block;
262
+ resize: none; /* height is splitter-driven (inline style), not the native handle */
263
+ border: none;
264
+ border-radius: 0;
265
+ background: var(--bg);
266
+ color: var(--fg);
267
+ font: inherit;
268
+ font-size: .9rem;
269
+ line-height: 1.45;
270
+ /* Right padding clears the three overlaid 28px buttons: .5rem inset + 3×28px + 2×.15rem gaps. */
271
+ padding: .5rem 6.2rem .5rem .75rem;
272
+ }
273
+ .composer-input:focus { outline: none; }
274
+ .composer-input:disabled { opacity: .6; }
275
+ .composer-input::placeholder { color: var(--muted); }
276
+ /* The icons.ts shell: one span, sized HERE (never by svg attrs), the material/custom svg filling
277
+ it. 14px default; context classes (.btn-icon, .caret-tri, …) override. */
278
+ .icon { display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; flex: none; }
279
+ .icon svg { width: 100%; height: 100%; display: block; }
280
+ /* The overlay row, bottom-anchored to the textarea's right edge: send/stop is the primary CTA;
281
+ + (new conversation) and the clipboard clip are the quiet secondaries to its left. */
282
+ .composer-act, .composer-new, .composer-clip {
283
+ position: absolute;
284
+ bottom: .5rem;
285
+ width: 28px;
286
+ height: 28px;
287
+ display: flex;
288
+ align-items: center;
289
+ justify-content: center;
290
+ padding: 0;
291
+ margin: 0;
292
+ appearance: none;
293
+ border: none;
294
+ border-radius: 50%;
295
+ cursor: pointer;
296
+ transition: background .15s, color .15s, transform .08s;
297
+ }
298
+ /* Send/stop are CIRCLE GLYPHS (play_circle / stop_circle — typebulb.com's play look): the icon IS
299
+ the button, no painted disc. One size for all three — the circles' diameter and the paperclip's
300
+ ink height are both 800/960 of the material viewBox, so equal boxes = equal visual height. */
301
+ .composer-act .icon, .composer-new .icon, .composer-clip .icon { width: 24px; height: 24px; }
302
+ .composer-act { right: .5rem; background: transparent; }
303
+ .composer-act.send { color: var(--accent); }
304
+ .composer-act.send:hover:not(:disabled) { color: color-mix(in srgb, var(--accent) 80%, white); background: color-mix(in srgb, var(--accent) 10%, transparent); }
305
+ .composer-act.stop { color: var(--err); }
306
+ .composer-act.stop:hover { color: color-mix(in srgb, var(--err) 80%, white); background: color-mix(in srgb, var(--err) 10%, transparent); }
307
+ .composer-act:active, .composer-new:active, .composer-clip:active { transform: scale(.94); }
308
+ .composer-act:disabled, .composer-new:disabled, .composer-clip:disabled { opacity: .5; cursor: default; }
309
+ .composer-new {
310
+ /* offset = act's right inset (.5rem) + act width (28px) + gap (.15rem) */
311
+ right: calc(.5rem + 28px + .15rem);
312
+ background: transparent;
313
+ color: var(--muted);
314
+ }
315
+ .composer-new:hover:not(:disabled) { color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
316
+ .composer-clip {
317
+ /* one more button-width left of .composer-new */
318
+ right: calc(.5rem + 2 * (28px + .15rem));
319
+ background: transparent;
320
+ color: var(--muted);
321
+ }
322
+ .composer-clip:hover:not(:disabled) { color: var(--accent); background: color-mix(in srgb, var(--accent) 10%, transparent); }
323
+ .composer-err { padding: .3rem .75rem; color: var(--err); font-size: .78rem; }
324
+ /* The ambient status line (TB-Agent-Composer-Toolkit.md Piece 2): one slim kind-tinted row above the
325
+ input — a retry/compaction in progress, an extension notice, a recipe's transient result. */
326
+ .composer-status { padding: .3rem .75rem; font-size: .78rem; color: var(--muted); }
327
+ .composer-status.warning { color: color-mix(in srgb, var(--err) 55%, var(--fg)); }
328
+ .composer-status.error { color: var(--err); }
329
+ /* The pending-queue strip (parity #2): queued steer/follow-up texts above the input. Block rows,
330
+ not a flex column — .queue-row's overflow:hidden would zero flex min-heights (the .dlg-opts
331
+ lesson). */
332
+ .composer-queue { padding: .15rem .75rem 0; }
333
+ .queue-row { font-size: .78rem; color: var(--muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
334
+ .queue-tag { color: var(--accent); font-size: .68rem; text-transform: uppercase; letter-spacing: .05em; margin-right: .5rem; }
335
+ /* The @-file-mention popup, anchored above the composer. */
336
+ .at-popup {
337
+ position: absolute;
338
+ bottom: calc(100% + .25rem);
339
+ left: 1rem;
340
+ right: 1rem;
341
+ max-width: 600px;
342
+ max-height: 280px;
343
+ overflow-y: auto;
344
+ background: var(--panel);
345
+ border: 1px solid var(--border);
346
+ border-radius: 10px;
347
+ box-shadow: 0 8px 30px rgba(0, 0, 0, .35);
348
+ padding: .25rem;
349
+ z-index: 10;
350
+ }
351
+ .at-row {
352
+ padding: .35rem .55rem;
353
+ border-radius: 6px;
354
+ cursor: pointer;
355
+ font-family: ui-monospace, Menlo, monospace;
356
+ font-size: .82rem;
357
+ white-space: nowrap;
358
+ overflow: hidden;
359
+ text-overflow: ellipsis;
360
+ }
361
+ .at-row.active { background: color-mix(in srgb, var(--accent) 18%, transparent); }
362
+ .at-row:hover { background: color-mix(in srgb, var(--accent) 10%, transparent); }
363
+ /* The '/' palette rides the same popup chrome; its rows pair a command with a muted description. */
364
+ .slash-desc { color: var(--muted); font-size: .74rem; margin-left: .6rem; }
365
+ /* The composer's dialog modal (TB-Agent-Composer-Toolkit.md Piece 3) rides the trust-modal chrome; these
366
+ are only its extra fields. Select options reuse .at-row inside a bordered scroll box. */
367
+ /* Block, NOT flex: .at-row's overflow:hidden zeroes flex min-heights, squashing a long option
368
+ list (pi can return the whole OpenRouter catalog); block rows keep their natural height and
369
+ the box scrolls. */
370
+ .composer-dlg .dlg-opts {
371
+ max-height: 40vh; overflow-y: auto;
372
+ border: 1px solid var(--border); border-radius: 8px; padding: .25rem;
373
+ }
374
+ .composer-dlg .dlg-input, .composer-dlg .dlg-editor {
375
+ font: inherit; font-size: .85rem; color: var(--fg); background: transparent;
376
+ border: 1px solid var(--border); border-radius: 7px; padding: .4rem .6rem; width: 100%;
377
+ }
378
+ .composer-dlg .dlg-input:focus, .composer-dlg .dlg-editor:focus { outline: none; border-color: var(--accent); }
379
+ .composer-dlg .dlg-editor { min-height: 8rem; resize: vertical; }
380
+ .composer-dlg .dlg-filter { margin-top: .4rem; }
381
+ .at-empty { padding: .6rem; color: var(--muted); font-size: .85rem; text-align: center; }
382
+ /* The driver's in-flight assistant message — visibly provisional next to landed bubbles; the
383
+ durable row replaces it when the entry hits the transcript. */
384
+ .bubble.draft { opacity: .9; }
385
+ .draft-wait { color: var(--muted); }
386
+ /* Pasted-image thumbnails under a user message that @-mentions .typebulb/paste files. */
387
+ .paste-thumbs { margin-top: .4rem; }
388
+ .paste-thumb { display: block; max-width: min(360px, 100%); max-height: 240px; margin-top: .3rem; border: 1px solid var(--border); border-radius: 8px; }
389
+
239
390
  /* Session list — shares the popover chrome (.picker above); these are
240
391
  just its own dimensions. */
241
392
  .picker { width: min(440px, calc(100vw - 2rem)); }
@@ -601,13 +752,16 @@ a.server-port:hover { text-decoration: underline; }
601
752
  .trust-toggle { font-size: .76rem; height: 1.45rem; padding: 0 .5rem; color: var(--muted); justify-self: center; }
602
753
  .trust-toggle:hover, .trust-toggle.on { color: var(--accent); border-color: var(--accent); }
603
754
  .server-stop, .bulb-launch { width: 1.7rem; padding: 0; border-radius: 50%; margin-left: .4rem; }
604
- .btn-icon { display: block; }
755
+ .btn-icon { width: 16px; height: 16px; }
605
756
  /* A stopped bulb's play button is dormant — the title is the primary launch target — so it's
606
757
  hidden until the row is hovered or keyboard-selected. visibility (not display) reserves its slot,
607
758
  so the name column doesn't shift when it appears. Painted the fold-marker green, matching the
608
759
  :port link: green is the live-app axis (play to launch → :port to open it), distinct from the
609
760
  blue source/name. The green even travels left→right as a bulb goes stopped→running. */
610
761
  .bulb-launch { color: var(--fold-marker); visibility: hidden; }
762
+ /* A right triangle's visual mass sits left of its bounding box, so geometric centring reads
763
+ too-far-left in a round button — shift the play glyph. */
764
+ .bulb-launch .icon svg { transform: translateX(1px); }
611
765
  .server-row:hover .bulb-launch, .server-row.active .bulb-launch { visibility: visible; }
612
766
  .bulb-launch:hover { border-color: var(--fold-marker); background: color-mix(in srgb, var(--fold-marker) 12%, transparent); }
613
767
  /* Launching: stays visible (hover-independent) and shimmers until the row flips to a stop button,
@@ -1118,6 +1272,23 @@ a.server-port:hover { text-decoration: underline; }
1118
1272
  color: var(--fg); font-weight: 600;
1119
1273
  }
1120
1274
  .bulb-code .hljs-symbol, .bulb-code .hljs-bullet, .bulb-code .hljs-punctuation { color: var(--muted); }
1275
+ /* Draft-streaming bulb card (#draftBulbCard): the code view wearing a progress header — never a
1276
+ live mount; the durable row's BulbEmbed takes this slot when the entry lands. Cap tighter than
1277
+ .bulb-code's resting 480px: ambient progress, not reading material. */
1278
+ .md .bulb-streaming { flex-direction: column; }
1279
+ .md .bulb-streaming > .bulb-code { max-height: 220px; border-radius: 0 0 8px 8px; }
1280
+ .bulb-streaming-head {
1281
+ display: flex;
1282
+ align-items: baseline;
1283
+ gap: .45rem;
1284
+ padding: .3rem .85rem;
1285
+ border-radius: 8px 8px 0 0;
1286
+ /* A notch above the file-label bars inside the listing, so the header owns the card. */
1287
+ background: color-mix(in srgb, var(--fg) 10%, var(--tool-bg));
1288
+ font-size: .78rem;
1289
+ color: var(--muted);
1290
+ }
1291
+ .bulb-streaming-count { margin-left: auto; font-variant-numeric: tabular-nums; }
1121
1292
  .md .bulb-embed.err {
1122
1293
  padding: .6rem .8rem;
1123
1294
  font-family: ui-monospace, monospace;
@@ -1167,7 +1338,7 @@ a.server-port:hover { text-decoration: underline; }
1167
1338
  }
1168
1339
  /* The shared disclosure triangle (caret() in messageList.ts). flex:none so a squeezed row can't
1169
1340
  crush it; the digest row has no flex gap, so its spacing rides the marker. */
1170
- .caret-tri { flex: none; transition: transform .15s ease; }
1341
+ .caret-tri { width: 10px; height: 10px; transition: transform .15s ease; }
1171
1342
  .caret-tri.open { transform: rotate(90deg); }
1172
1343
  .tool-digest .caret-tri { margin-right: .5rem; }
1173
1344
  /* Plain bold — an accent verb reads as a hyperlink; accent is reserved for the file-path link. */
@@ -1180,7 +1351,7 @@ a.server-port:hover { text-decoration: underline; }
1180
1351
  answer). Same caret/row shape as a tool head, italic muted label. */
1181
1352
  .turn-summary { color: var(--muted); font-size: .85rem; }
1182
1353
  .turn-summary-text { font-style: italic; }
1183
- .fork-icon { vertical-align: -1px; margin-right: .15rem; }
1354
+ .fork-icon { width: 11px; height: 11px; vertical-align: -1px; margin-right: .15rem; }
1184
1355
  .turn-summary:hover .turn-summary-text { color: var(--fg); }
1185
1356
 
1186
1357
  /* An expanded abandoned-branch (fork) stub renders its orphan messages here — set apart from the live
@@ -1307,9 +1478,15 @@ a.server-port:hover { text-decoration: underline; }
1307
1478
  .tool-key { color: var(--muted); margin-right: .6rem; user-select: text; }
1308
1479
  .tool-val { display: inline; margin: 0; font: inherit; white-space: pre-wrap; word-break: break-word; }
1309
1480
  /* Line-banded unified-diff view (± lines only): the same add/remove band colors as
1310
- .diff-new/.diff-old; a muted ⋯ row separates hunks. */
1481
+ .diff-new/.diff-old; a muted ⋯ row separates hunks. The ± marker is ::before content in a
1482
+ reserved gutter — visible (the non-color cue colorblind readers need) but outside the DOM
1483
+ text, so selection-copy grabs only the code. min-height keeps blank changed lines from
1484
+ collapsing now that they carry no marker char. */
1311
1485
  .udiff { white-space: pre-wrap; word-break: break-word; }
1312
- .udiff-line { padding: 0 .2rem; }
1486
+ .udiff-line { position: relative; padding: 0 .2rem 0 1.05rem; min-height: 1lh; }
1487
+ .udiff-line::before { position: absolute; left: .25rem; }
1488
+ .udiff-add::before { content: '+'; }
1489
+ .udiff-del::before { content: '-'; }
1313
1490
  .udiff-add { background: color-mix(in srgb, var(--diff-add) 24%, transparent); }
1314
1491
  .udiff-del { background: color-mix(in srgb, var(--err) 24%, transparent); }
1315
1492
  .udiff-gap { color: var(--muted); user-select: none; }