@lloyal-labs/dev-tools 0.4.2 → 0.5.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/react.js CHANGED
@@ -17,13 +17,13 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
17
17
  */
18
18
  import React, { useEffect, useMemo, useRef, useState } from 'react';
19
19
  import { useStore } from 'zustand';
20
- import { pressureStrip, pressurePercent, readConfigPath, lanePpl, isLive, KEY_TIERS, } from './index.js';
20
+ import { pressureStrip, pressurePercent, readConfigPath, lanePpl, isLive, configRows, configCommand, liveConfigKeys, changing, } from './index.js';
21
21
  import { devStoreFor, EDGE_STEP } from './store.js';
22
22
  // ── palette: monochrome chrome, color reserved for data ──
23
23
  const C = {
24
24
  text: '#202124', dim: '#5f6368', faint: '#9aa0a6', border: '#e8eaed',
25
25
  hair: '#f4f5f7', chromeBg: '#f1f3f4', panelBg: '#fafbfc',
26
- agent: '#1a73e8', agentDark: '#174ea6', fail: '#b3261e', ok: '#188038',
26
+ agent: '#1a73e8', agentDark: '#174ea6', recon: '#7cacf8', fail: '#b3261e', ok: '#188038',
27
27
  warn: '#9a6700', warnBg: '#fef7e0', warnBorder: '#f9d67a',
28
28
  };
29
29
  const HOST_CPU = '#00897b';
@@ -246,12 +246,12 @@ function runEndS(m) {
246
246
  return m.runStartAt === null ? 0 : Math.max(0, (end - m.runStartAt) / 1000);
247
247
  }
248
248
  // ═══════════════════════════════════════════════════════════════
249
- export function DevPane({ bridge, controls = [], title, runCommands = {}, children }) {
249
+ export function DevPane({ bridge, config, title, runCommands = {}, framing, children }) {
250
250
  // The store is a per-bridge SINGLETON: a remount reattaches to the running
251
251
  // fold (full history intact) instead of restarting it and desyncing. It is
252
252
  // deliberately NOT destroyed on unmount — it lives with the page, like the
253
253
  // bridge itself (dev-gated; a production stream folds nothing).
254
- const store = devStoreFor(bridge);
254
+ const store = devStoreFor(bridge, framing);
255
255
  const rev = useStore(store, (s) => s.rev);
256
256
  const m = store.getState().model;
257
257
  const [open, setOpen] = useState(false);
@@ -328,10 +328,13 @@ export function DevPane({ bridge, controls = [], title, runCommands = {}, childr
328
328
  } }), m.clarifying ? '?' : liveCount > 0 ? liveCount : '!'] })), _jsx("span", { children: summary })] }), toast && _jsx(Notice, { at: toastAt, text: toast }), _jsx("span", { style: { flex: 1 } }), _jsxs("span", { "aria-hidden": "true", style: { display: 'inline-flex', alignItems: 'center', gap: 14 }, children: [_jsx(MiniSpark, { heading: "context", color: C.agent, values: barStrip.map((p) => p.pct), value: barPct === null ? '—' : `${barPct}%` }), _jsx(MiniSpark, { heading: "cpu", color: HOST_CPU, values: barHost.map((h) => h.cpu), value: barLast ? `${barLast.cpu}%` : '—' }), _jsx(MiniSpark, { heading: "mem", color: "#9aa0a6", values: barHost.filter((h) => h.memUsedMb !== null).map((h) => h.memUsedMb), value: barLast && barLast.memUsedMb !== null && barLast.memTotalMb > 0
329
329
  ? `${(barLast.memUsedMb / 1024).toFixed(1)} / ${Math.round(barLast.memTotalMb / 1024)}G` : '—' }), _jsx(MiniSpark, { heading: "harness", color: "#5f6368", values: barHost.map((h) => h.rssMb), value: barLast ? `${(barLast.rssMb / 1024).toFixed(1)}G` : '—' })] }), _jsx("span", { style: { flex: 1 } }), _jsx("span", { style: { color: C.faint }, "aria-hidden": "true", children: "click to expand" })] }));
330
330
  }
331
- return shell(_jsx(Pane, { store: store, m: m, rev: rev, controls: controls, title: title, runCommands: runCommands, onClose: () => setOpen(false) }));
331
+ return shell(_jsx(Pane, { store: store, m: m, rev: rev, config: config, title: title, runCommands: runCommands, onClose: () => setOpen(false),
332
+ // Thumbnails resolve through the bridge when the harness exposes a
333
+ // content route; the pane never learns the transport, only the URL.
334
+ mediaUrl: bridge.representationUrl ? (d, i) => bridge.representationUrl(d, i) : undefined }));
332
335
  }
333
336
  // ═══ the docked pane ═══
334
- function Pane({ store, m, rev, controls, title, runCommands, onClose }) {
337
+ function Pane({ store, m, rev, config, title, runCommands, onClose, mediaUrl }) {
335
338
  const [tab, setTab] = useState('timeline');
336
339
  const [selAgent, setSelAgent] = useState(null);
337
340
  const [feedW, setFeedW] = useState(feedWidthPref);
@@ -401,7 +404,7 @@ function Pane({ store, m, rev, controls, title, runCommands, onClose }) {
401
404
  : 'finish up — agents wrap up and report; the trajectory is kept', style: m.pausedAt !== null || m.windingDownAt !== null
402
405
  ? { ...runBtn, opacity: 0.4, cursor: 'default' } : runBtn, children: m.windingDownAt !== null ? 'finishing…' : 'finish up' })), runCommands.stop && (_jsx("button", { onClick: () => store.send({ type: 'stop' }), title: "halt the run", style: { ...runBtn, color: C.fail, borderColor: '#f0c4c1' }, children: "stop" }))] })), _jsxs("span", { style: { fontFamily: mono, display: 'inline-flex', alignItems: 'center', gap: 7 }, children: [_jsx("span", { style: { width: 7, height: 7, borderRadius: '50%', background: live ? (m.pausedAt !== null ? C.warn : C.ok) : C.faint } }), live
403
406
  ? (m.pausedAt !== null ? 'paused' : m.windingDownAt !== null ? 'finishing' : 'live')
404
- : m.runStartAt === null ? 'idle' : 'run complete'] }), _jsx("span", { style: { cursor: 'pointer', color: C.dim }, onClick: onClose, title: "collapse to the cog", children: "\u2715" })] })] }), tab === 'timeline' && (_jsxs("div", { style: { flex: 1, minHeight: 0, display: 'flex' }, children: [_jsx(Timeline, { m: m, rev: rev, store: store, selAgent: selAgent, onSelect: setSelAgent, toolColor: toolColor }), selAgent !== null && m.lanes.has(selAgent) && (_jsxs(_Fragment, { children: [_jsx(FeedResizer, { width: feedW, onWidth: (w) => { feedWidthPref = w; setFeedW(w); } }), _jsx(AgentFeed, { m: m, lane: m.lanes.get(selAgent), toolColor: toolColor, onClose: () => setSelAgent(null), onJump: setSelAgent, nowMs: store.getState().paintedAt, width: feedW, send: (c) => store.send(c), canCancel: !!runCommands.cancelAgent })] }))] })), tab === 'sources' && _jsx(Sources, { m: m, toolColor: toolColor }), tab === 'settings' && _jsx(Settings, { m: m, controls: controls, send: (c) => store.send(c) }), _jsxs("div", { style: {
407
+ : m.runStartAt === null ? 'idle' : 'run complete'] }), _jsx("span", { style: { cursor: 'pointer', color: C.dim }, onClick: onClose, title: "collapse to the cog", children: "\u2715" })] })] }), tab === 'timeline' && (_jsxs("div", { style: { flex: 1, minHeight: 0, display: 'flex' }, children: [_jsx(Timeline, { m: m, rev: rev, store: store, selAgent: selAgent, onSelect: setSelAgent, toolColor: toolColor }), selAgent === 'spine' && m.spine && (_jsxs(_Fragment, { children: [_jsx(FeedResizer, { width: feedW, onWidth: (w) => { feedWidthPref = w; setFeedW(w); } }), _jsx(SpineFeed, { m: m, onClose: () => setSelAgent(null), width: feedW, mediaUrl: mediaUrl, toolColor: toolColor })] })), selAgent === 'trunk' && m.trunk.length > 0 && (_jsxs(_Fragment, { children: [_jsx(FeedResizer, { width: feedW, onWidth: (w) => { feedWidthPref = w; setFeedW(w); } }), _jsx(TrunkFeed, { m: m, onClose: () => setSelAgent(null), width: feedW, mediaUrl: mediaUrl })] })), typeof selAgent === 'number' && m.lanes.has(selAgent) && (_jsxs(_Fragment, { children: [_jsx(FeedResizer, { width: feedW, onWidth: (w) => { feedWidthPref = w; setFeedW(w); } }), _jsx(AgentFeed, { m: m, lane: m.lanes.get(selAgent), toolColor: toolColor, onClose: () => setSelAgent(null), onJump: setSelAgent, nowMs: store.getState().paintedAt, width: feedW, send: (c) => store.send(c), canCancel: !!runCommands.cancelAgent })] }))] })), tab === 'sources' && _jsx(Sources, { m: m, toolColor: toolColor }), tab === 'settings' && _jsx(Settings, { m: m, config: config, send: (c) => store.send(c) }), _jsxs("div", { style: {
405
408
  height: 24, display: 'flex', alignItems: 'center', gap: 14, padding: '0 12px',
406
409
  borderTop: `1px solid ${C.border}`, background: '#f8f9fa', fontSize: 10.5, color: C.dim, flex: 'none',
407
410
  }, children: [_jsxs("span", { style: { fontFamily: mono }, children: [m.runStartAt === null
@@ -492,11 +495,121 @@ function Timeline({ m, rev, store, selAgent, onSelect, toolColor }) {
492
495
  };
493
496
  const onMouseUp = () => { drag.current = null; };
494
497
  return (_jsxs("div", { style: { flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', minHeight: 0 }, children: [_jsxs("div", { style: { height: 54, borderBottom: `1px solid ${C.border}`, display: 'flex', flex: 'none' }, children: [_jsx(MetricCell, { heading: "context", color: C.agent, values: strip.slice(-60).map((p) => p.pct), value: pct === null ? '—' : `${pct}% · ${m.pressure[m.pressure.length - 1]?.cellsUsed.toLocaleString()} / ${m.pressure[m.pressure.length - 1]?.nCtx.toLocaleString()}`, title: "kv cells used \u2014 context pressure on the model side" }), _jsx(MetricCell, { heading: "cpu", color: HOST_CPU, values: host.slice(-60).map((h) => h.cpu), value: lastHost ? `${lastHost.cpu}%` : '—', title: "this process's cpu, % of the whole machine" }), _jsx(MetricCell, { heading: "mem", color: "#9aa0a6", values: host.slice(-60).filter((h) => h.memUsedMb !== null).map((h) => h.memUsedMb), value: lastHost && lastHost.memUsedMb !== null && lastHost.memTotalMb > 0
495
- ? `${(lastHost.memUsedMb / 1024).toFixed(1)} / ${Math.round(lastHost.memTotalMb / 1024)}G` : '—', title: "machine memory in use, honestly counted (vm_stat / MemAvailable)" }), _jsx(MetricCell, { heading: "harness", color: "#5f6368", last: true, values: host.slice(-60).map((h) => h.rssMb), value: lastHost ? `${(lastHost.rssMb / 1024).toFixed(1)}G` : '—', title: "this process's resident memory \u2014 weights + KV + runtime" })] }), _jsxs("div", { style: { height: 20, display: 'flex', borderBottom: `1px solid ${C.border}`, flex: 'none' }, children: [_jsx("div", { style: { width: GUTTER, flex: 'none', padding: '4px 0 0 14px' }, children: _jsx("span", { style: label, children: lanes.length ? `${lanes.length} agents` : '' }) }), _jsx("div", { style: { flex: 1, position: 'relative', fontFamily: mono }, children: ticks.map((t) => (_jsx("span", { style: { position: 'absolute', left: px(t) - GUTTER, fontSize: 9, color: C.faint }, children: t >= 60 ? `${Math.floor(t / 60)}m${t % 60 ? String(t % 60).padStart(2, '0') : ''}` : `${t}s` }, t))) })] }), _jsxs("div", { ref: trackRef, style: { flex: 1, position: 'relative', overflowY: 'auto', overflowX: 'hidden', cursor: drag.current ? 'grabbing' : undefined }, onMouseDown: onMouseDown, onMouseMove: onMouseMove, onMouseUp: onMouseUp, onMouseLeave: onMouseUp, onDoubleClick: () => { setFollow(true); setPanWindow(null); }, children: [m.runStartAt === null && (_jsx("div", { style: { position: 'absolute', inset: 0, display: 'grid', placeItems: 'center', color: C.faint, fontSize: 11.5, pointerEvents: 'none' }, children: "run a query \u2014 agents appear here live" })), !follow && live && (_jsx("button", { onClick: (e) => { e.stopPropagation(); setFollow(true); setPanWindow(null); }, style: {
498
+ ? `${(lastHost.memUsedMb / 1024).toFixed(1)} / ${Math.round(lastHost.memTotalMb / 1024)}G` : '—', title: "machine memory in use, honestly counted (vm_stat / MemAvailable)" }), _jsx(MetricCell, { heading: "harness", color: "#5f6368", last: true, values: host.slice(-60).map((h) => h.rssMb), value: lastHost ? `${(lastHost.rssMb / 1024).toFixed(1)}G` : '—', title: "this process's resident memory \u2014 weights + KV + runtime" })] }), _jsxs("div", { style: { height: 20, display: 'flex', borderBottom: `1px solid ${C.border}`, flex: 'none' }, children: [_jsx("div", { style: { width: GUTTER, flex: 'none', padding: '4px 0 0 14px' }, children: _jsx("span", { style: label, children: lanes.length ? `${lanes.length} agents` : '' }) }), _jsx("div", { style: { flex: 1, position: 'relative', overflow: 'hidden', fontFamily: mono }, children: ticks.map((t) => (_jsx("span", { style: { position: 'absolute', left: px(t) - GUTTER, fontSize: 9, color: C.faint }, children: t >= 60 ? `${Math.floor(t / 60)}m${t % 60 ? String(t % 60).padStart(2, '0') : ''}` : `${t}s` }, t))) })] }), _jsxs("div", { ref: trackRef, style: { flex: 1, position: 'relative', overflowY: 'auto', overflowX: 'hidden', cursor: drag.current ? 'grabbing' : undefined }, onMouseDown: onMouseDown, onMouseMove: onMouseMove, onMouseUp: onMouseUp, onMouseLeave: onMouseUp, onDoubleClick: () => { setFollow(true); setPanWindow(null); }, children: [m.runStartAt === null && (_jsx("div", { style: { position: 'absolute', inset: 0, display: 'grid', placeItems: 'center', color: C.faint, fontSize: 11.5, pointerEvents: 'none' }, children: "run a query \u2014 agents appear here live" })), !follow && live && (_jsx("button", { onClick: (e) => { e.stopPropagation(); setFollow(true); setPanWindow(null); }, style: {
496
499
  position: 'absolute', top: 6, right: 10, zIndex: 3, cursor: 'pointer',
497
500
  fontSize: 10.5, padding: '3px 10px', borderRadius: 12, border: `1px solid ${C.border}`,
498
501
  background: '#fff', color: C.agentDark, fontWeight: 600, boxShadow: '0 1px 4px rgba(32,33,36,.12)',
499
- }, children: "\u27F3 follow live" })), _jsxs("div", { style: { position: 'absolute', left: GUTTER, right: 0, top: 0, bottom: 0, pointerEvents: 'none' }, children: [ticks.map((t) => (_jsx("div", { style: { position: 'absolute', left: px(t) - GUTTER, top: 0, bottom: 0, width: 1, background: t % (step * 3) === 0 ? C.border : C.hair } }, t))), live && on(nowS) && (_jsxs(_Fragment, { children: [_jsx("div", { style: { position: 'absolute', left: px(nowS) - GUTTER, right: 0, top: 0, bottom: 0, background: C.panelBg } }), _jsx("div", { style: { position: 'absolute', left: px(nowS) - GUTTER, top: 0, bottom: 0, width: 1, background: C.text, zIndex: 1 } }), _jsx("div", { style: { position: 'absolute', left: px(nowS) - GUTTER, top: 2, transform: 'translateX(-50%)', fontSize: 8.5, background: C.text, color: '#fff', padding: '0 5px', borderRadius: 2, zIndex: 2, fontFamily: mono }, children: "now" })] }))] }), lanes.map((l) => (_jsx(Lane, { m: m, l: l, px: px, on: on, secOf: secOf, nowS: nowS, live: live, selected: selAgent === l.agentId, toolColor: toolColor, onClick: () => onSelect(selAgent === l.agentId ? null : l.agentId), gutter: GUTTER, windowEnd: w1 }, l.agentId)))] })] }));
502
+ }, children: "\u27F3 follow live" })), _jsxs("div", { style: { position: 'absolute', left: GUTTER, right: 0, top: 0, bottom: 0, pointerEvents: 'none' }, children: [ticks.map((t) => (_jsx("div", { style: { position: 'absolute', left: px(t) - GUTTER, top: 0, bottom: 0, width: 1, background: t % (step * 3) === 0 ? C.border : C.hair } }, t))), live && on(nowS) && (_jsxs(_Fragment, { children: [_jsx("div", { style: { position: 'absolute', left: px(nowS) - GUTTER, right: 0, top: 0, bottom: 0, background: C.panelBg } }), _jsx("div", { style: { position: 'absolute', left: px(nowS) - GUTTER, top: 0, bottom: 0, width: 1, background: C.text, zIndex: 1 } }), _jsx("div", { style: { position: 'absolute', left: px(nowS) - GUTTER, top: 2, transform: 'translateX(-50%)', fontSize: 8.5, background: C.text, color: '#fff', padding: '0 5px', borderRadius: 2, zIndex: 2, fontFamily: mono }, children: "now" })] }))] }), (() => {
503
+ // Fork topology, drawn. Pure px()/ROW_H geometry — no DOM reads —
504
+ // and absolutely positioned INSIDE the scroll container, so curves
505
+ // ride with their rows through scroll, pan, and every resize.
506
+ const rows = [];
507
+ if (m.trunk.length > 0)
508
+ rows.push('session');
509
+ if (m.spine)
510
+ rows.push('spine');
511
+ for (const l of lanes)
512
+ rows.push(l.agentId);
513
+ const rowIdx = new Map(rows.map((r, i) => [r, i]));
514
+ const yMid = (r) => rowIdx.get(r) * ROW_H + 19;
515
+ const paths = [];
516
+ if (m.spine && rowIdx.has('spine')) {
517
+ const sx = px(secOf(m.spine.spineAt ?? m.spine.at));
518
+ // Warm lineage: the session's conversation feeds the spine.
519
+ if (rowIdx.has('session') && (m.spine.inherited ?? 0) > 0 && sx >= GUTTER) {
520
+ const sy = rowIdx.get('session') * ROW_H + 22;
521
+ const ty = rowIdx.get('spine') * ROW_H + 19;
522
+ const e = sx - 10;
523
+ const r = 4;
524
+ paths.push(_jsx("path", { d: `M ${sx} ${sy} L ${e + r} ${sy} Q ${e} ${sy} ${e} ${sy + r} L ${e} ${ty - r} Q ${e} ${ty} ${e + r} ${ty} L ${sx - 2} ${ty}`, stroke: "#9aa0a6", strokeWidth: "1.3", fill: "none" }, "warm"));
525
+ }
526
+ // Every lane hangs off the spine at its true spawn moment.
527
+ const spineRow = rowIdx.get('spine');
528
+ for (const l of lanes) {
529
+ // Only lanes that forked AFTER the spine existed hang off it —
530
+ // a planner forks from the session, and the pane draws no
531
+ // parentage it does not know.
532
+ if (m.spine.spineAt === null || l.spawnedAt + 250 < m.spine.spineAt)
533
+ continue;
534
+ const x = px(secOf(l.spawnedAt));
535
+ if (x < GUTTER || !on(secOf(l.spawnedAt)))
536
+ continue;
537
+ const laneRow = rowIdx.get(l.agentId);
538
+ // Nested elbows: drop at a small left offset (wider for deeper
539
+ // rows, so simultaneous forks read as nested guides), rounded
540
+ // corner, horizontal entry into the bar's left edge.
541
+ const off = 8 + (laneRow - spineRow - 1) * 5;
542
+ const sy = spineRow * ROW_H + 23;
543
+ const ty = laneRow * ROW_H + 19;
544
+ const e = x - off;
545
+ const r = 4;
546
+ paths.push(_jsx("path", { d: `M ${x} ${sy} L ${e + r} ${sy} Q ${e} ${sy} ${e} ${sy + r} L ${e} ${ty - r} Q ${e} ${ty} ${e + r} ${ty} L ${x - 2} ${ty}`, stroke: "#9aa0a6", strokeWidth: "1.3", fill: "none" }, `f${l.agentId}`));
547
+ }
548
+ }
549
+ // DAG dependency edges — declared by the orchestrator, never inferred.
550
+ for (const l of lanes) {
551
+ for (const dep of l.after ?? []) {
552
+ const d = m.lanes.get(dep);
553
+ if (!d || d.doneAt === null || !rowIdx.has(dep))
554
+ continue;
555
+ const x2 = px(secOf(l.spawnedAt));
556
+ if (x2 < GUTTER)
557
+ continue;
558
+ const x1 = Math.max(px(secOf(d.doneAt)), GUTTER);
559
+ const y1 = yMid(dep);
560
+ const y2 = yMid(l.agentId);
561
+ const e = Math.max(x2 - 8, x1 + 4);
562
+ const r = 4;
563
+ const vdir = y2 > y1 ? 1 : -1;
564
+ paths.push(_jsx("path", { d: `M ${x1} ${y1} L ${e - r} ${y1} Q ${e} ${y1} ${e} ${y1 + r * vdir} L ${e} ${y2 - r * vdir} Q ${e} ${y2} ${e + r} ${y2} L ${x2} ${y2}`, stroke: "#9aa0a6", strokeWidth: "1.2", strokeDasharray: "4 3", fill: "none" }, `d${dep}-${l.agentId}`));
565
+ }
566
+ }
567
+ if (paths.length === 0)
568
+ return null;
569
+ return (_jsx("svg", { width: "100%", height: rows.length * ROW_H, style: { position: 'absolute', left: 0, top: 0, pointerEvents: 'none', zIndex: 1 }, children: paths }));
570
+ })(), m.trunk.length > 0 && (_jsxs("div", { role: "button", tabIndex: 0, onClick: () => onSelect(selAgent === 'trunk' ? null : 'trunk'), onKeyDown: keyActivate(() => onSelect(selAgent === 'trunk' ? null : 'trunk')), style: {
571
+ position: 'relative', height: ROW_H, display: 'flex', cursor: 'pointer',
572
+ borderBottom: `1px solid ${C.hair}`,
573
+ background: selAgent === 'trunk' ? C.chromeBg : undefined,
574
+ boxShadow: selAgent === 'trunk' ? `inset 3px 0 0 ${C.text}` : undefined,
575
+ }, children: [_jsxs("div", { style: { width: GUTTER, flex: 'none', display: 'flex', alignItems: 'baseline', gap: 6, padding: '12px 0 0 14px', fontSize: 11.5 }, children: [_jsx("span", { style: { fontWeight: 600 }, children: "session" }), _jsxs("span", { style: { color: C.dim, fontSize: 10.5, fontFamily: mono }, children: [m.trunk.length, " turn", m.trunk.length === 1 ? '' : 's'] })] }), _jsx("div", { style: { flex: 1, position: 'relative', overflow: 'hidden' }, children: m.trunk.map((t, i) => {
576
+ const s = secOf(t.at);
577
+ if (!on(s))
578
+ return null;
579
+ // One diamond per side, colored by who spoke; a committed
580
+ // exchange ('turn') lands both at once and shows the pair.
581
+ const sides = t.speaker === 'turn' ? [TRUNK_QUERY, TRUNK_RESPONSE]
582
+ : t.speaker === 'user' ? [TRUNK_QUERY]
583
+ : t.speaker === 'tool' ? [TRUNK_TOOL]
584
+ : [TRUNK_RESPONSE];
585
+ return (_jsxs("span", { title: (t.query ?? t.content).slice(0, 200), children: [sides.map((c, j) => (_jsx("span", { style: {
586
+ position: 'absolute', left: px(s) - GUTTER - 5 + j * 9, top: 13, width: 10, height: 10,
587
+ borderRadius: 2, transform: 'rotate(45deg)', background: c, display: 'inline-block',
588
+ } }, j))), t.attachments.length > 0 && (_jsxs("span", { style: { position: 'absolute', left: px(s) - GUTTER + (sides.length > 1 ? 17 : 8), top: 11, fontSize: 9.5, color: C.dim }, children: ["\uD83D\uDCCE", t.attachments.length] }))] }, i));
589
+ }) })] })), m.spine && (_jsxs("div", { role: "button", tabIndex: 0, onClick: () => onSelect(selAgent === 'spine' ? null : 'spine'), onKeyDown: keyActivate(() => onSelect(selAgent === 'spine' ? null : 'spine')), style: {
590
+ position: 'relative', height: ROW_H, display: 'flex', cursor: 'pointer',
591
+ borderBottom: `1px solid ${C.hair}`,
592
+ background: selAgent === 'spine' ? C.chromeBg : undefined,
593
+ boxShadow: selAgent === 'spine' ? `inset 3px 0 0 ${C.text}` : undefined,
594
+ }, children: [_jsxs("div", { style: { width: GUTTER, flex: 'none', display: 'flex', alignItems: 'baseline', gap: 6, padding: '12px 0 0 14px', fontSize: 11.5 }, children: [_jsx("span", { style: { fontWeight: 600 }, children: "spine" }), _jsx("span", { style: { color: C.dim, fontSize: 10.5, fontFamily: mono }, children: (m.spine.spineCells || m.spine.headerTokens) > 0
595
+ ? `${(m.spine.spineCells || m.spine.headerTokens).toLocaleString()} tokens` : 'seeding…' })] }), _jsx("div", { style: { flex: 1, position: 'relative', overflow: 'hidden' }, children: (() => {
596
+ // The spine as a BAR — alive for the whole run — with a tick
597
+ // wherever it grew (the seed, then each extension).
598
+ const s0 = secOf(m.spine.spineAt ?? m.spine.at);
599
+ const x0 = Math.max(px(s0), GUTTER);
600
+ const x1 = Math.max(px(Math.min(endS, w1)), x0 + 4);
601
+ if (px(s0) > px(w1))
602
+ return null;
603
+ return (_jsxs("span", { title: (m.spine.query ?? '').slice(0, 200), children: [_jsx("span", { style: {
604
+ position: 'absolute', top: 15, height: 8, left: x0 - GUTTER, width: x1 - x0,
605
+ background: '#e3e6ea', borderRadius: 4, border: `1px solid ${C.hair}`, display: 'inline-block',
606
+ } }), m.spine.growth.map((g, gi) => {
607
+ const gs = secOf(g.at);
608
+ if (!on(gs))
609
+ return null;
610
+ return (_jsx("span", { title: `+${g.tokens.toLocaleString()} tokens`, style: { position: 'absolute', left: px(gs) - GUTTER, top: 13, width: 2, height: 12, background: C.text } }, gi));
611
+ }), m.spine.attachments.length > 0 && (_jsxs("span", { style: { position: 'absolute', left: x0 - GUTTER + 6, top: 11, fontSize: 9.5, color: C.dim }, children: ["\uD83D\uDCCE", m.spine.attachments.length] }))] }));
612
+ })() })] })), lanes.map((l) => (_jsx(Lane, { m: m, l: l, px: px, on: on, secOf: secOf, nowS: nowS, live: live, selected: selAgent === l.agentId, toolColor: toolColor, onClick: () => onSelect(selAgent === l.agentId ? null : l.agentId), gutter: GUTTER, windowEnd: w1 }, l.agentId)))] })] }));
500
613
  }
501
614
  const label = {
502
615
  fontSize: 10, fontWeight: 600, letterSpacing: '.06em', textTransform: 'uppercase', color: '#b0b6c2',
@@ -511,8 +624,14 @@ function Lane({ m, l, px, on, secOf, nowS, live, selected, toolColor, onClick, g
511
624
  const capL = px(s);
512
625
  const capR = px(Math.min(e, windowEnd));
513
626
  const running = l.doneAt === null;
514
- const color = l.outcome === 'failed' ? C.fail : l.role === 'synth' ? C.agentDark : C.agent;
515
- const rgb = l.outcome === 'failed' ? '179,38,30' : l.role === 'synth' ? '23,78,166' : '26,115,232';
627
+ const color = l.outcome === 'failed' ? C.fail
628
+ : l.role === 'synth' ? C.agentDark
629
+ : l.role === 'recon' ? C.recon
630
+ : C.agent;
631
+ const rgb = l.outcome === 'failed' ? '179,38,30'
632
+ : l.role === 'synth' ? '23,78,166'
633
+ : l.role === 'recon' ? '124,172,248'
634
+ : '26,115,232';
516
635
  const myCalls = m.retrievals.filter((r) => r.agentId === l.agentId);
517
636
  const myGuards = m.interventions.filter((iv) => iv.agentId === l.agentId && iv.kind !== 'nudge');
518
637
  const stripe = (x0, x1, grey = false) => {
@@ -536,7 +655,7 @@ function Lane({ m, l, px, on, secOf, nowS, live, selected, toolColor, onClick, g
536
655
  : l.outcome === 'failed' ? `${l.failReason ?? l.dropReason ?? 'failed'} · ${fmtS(e - s)}` : fmtS(e - s);
537
656
  const endColor = l.outcome === 'failed' ? C.fail : l.outcome === 'recovered' ? C.agent : '#3c4043';
538
657
  return (_jsxs("div", { onClick: onClick, role: "button", tabIndex: 0, onKeyDown: keyActivate(onClick), "aria-label": `open agent ${l.agentId}`, style: {
539
- display: 'flex', height: 38, borderTop: `1px solid ${C.hair}`, position: 'relative', cursor: 'pointer',
658
+ display: 'flex', height: ROW_H, borderTop: `1px solid ${C.hair}`, position: 'relative', cursor: 'pointer',
540
659
  background: selected ? C.chromeBg : cancelled ? 'rgba(179,38,30,.05)' : undefined,
541
660
  boxShadow: selected ? `inset 3px 0 0 ${C.text}` : undefined,
542
661
  }, children: [cancelled && (_jsx("span", { style: {
@@ -806,7 +925,125 @@ function AgentFeed({ m, lane, toolColor, onClose, onJump, nowMs, width, send, ca
806
925
  }, children: [_jsxs("div", { style: {
807
926
  height: 30, flex: 'none', display: 'flex', alignItems: 'center', gap: 8, padding: '0 12px',
808
927
  borderBottom: `1px solid ${C.border}`, background: '#f8f9fa',
809
- }, children: [_jsxs("span", { style: { fontFamily: mono, fontWeight: 600, fontSize: 11 }, children: [lane.role ?? 'agent', " #", lane.agentId] }), lane.parentAgentId !== null && m.lanes.has(lane.parentAgentId) && (_jsxs("span", { style: chip, children: ["forked from #", lane.parentAgentId] })), _jsxs("span", { style: chip, children: [lane.outcome, lane.doneAt !== null && m.runStartAt !== null ? ` · ${fmtS((lane.doneAt - lane.spawnedAt) / 1000)}` : ''] }), _jsx("span", { style: { flex: 1 } }), canCancel && lane.doneAt === null && (_jsx("button", { onClick: () => send({ type: 'cancel_agent', agentId: lane.agentId }), "aria-label": "cancel this agent", title: "cancel this agent \u2014 its branch is reclaimed; siblings continue. Works while paused: evaluate trajectories, cull, play", style: { ...runBtn, color: C.fail, borderColor: '#f0c4c1', padding: '2px 7px', display: 'inline-flex', alignItems: 'center' }, children: _jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("polyline", { points: "3 6 5 6 21 6" }), _jsx("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }), _jsx("line", { x1: "10", y1: "11", x2: "10", y2: "17" }), _jsx("line", { x1: "14", y1: "11", x2: "14", y2: "17" })] }) })), _jsx("span", { style: { cursor: 'pointer', color: C.dim }, onClick: onClose, title: "close \u2014 the timeline returns to full width", children: "\u2715" })] }), _jsxs("div", { style: { overflowY: 'auto', flex: 1, fontSize: 11, paddingBottom: 8 }, children: [_jsx(EpistemicsChart, { m: m, lane: lane, nowMs: nowMs }), lane.prompt && (_jsxs("div", { style: { borderBottom: `1px solid ${C.border}`, padding: '4px 12px 6px' }, children: [_jsxs("div", { role: "button", tabIndex: 0, onClick: () => toggle('prompt'), onKeyDown: keyActivate(() => toggle('prompt')), style: { display: 'flex', alignItems: 'baseline', gap: 7, cursor: 'pointer', padding: '2px 0' }, title: "the compiled prompt suffix that seeded this agent. In shared-spine mode the system + tool header lives on the spine PREFIX (inherited via fork) and is not repeated here; recursive agents inherit further parent context the same way", children: [_jsx("span", { style: { color: C.faint, fontSize: 9, width: 9, flex: 'none' }, children: expanded.has('prompt') ? '▾' : '▸' }), _jsx("span", { style: { color: C.dim }, children: "prompt" }), _jsxs("span", { style: { fontFamily: mono, fontSize: 10, color: C.faint }, children: [lane.prompt.tokenCount.toLocaleString(), " tok"] })] }), expanded.has('prompt') && _jsx(JsonBlock, { text: lane.prompt.text, raw: true })] })), (lane.failReason || lane.dropReason) && (_jsxs("div", { style: { display: 'flex', alignItems: 'baseline', padding: '6px 12px', gap: 8 }, children: [_jsx("span", { style: { color: C.dim, width: 92, flex: 'none' }, children: "pool said" }), _jsx("span", { style: { fontFamily: mono, fontSize: 11 }, children: lane.dropReason ?? lane.failReason })] })), items.map((it) => it.el), planView, lane.role !== 'planner' && (lane.report !== null || lane.outcome === 'failed') && (_jsxs("div", { style: feedItem, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 7, cursor: 'pointer' }, onClick: () => toggle('report'), children: [_jsx("span", { style: { color: C.faint, fontSize: 9, width: 9, flex: 'none' }, children: reportOpen ? '▾' : '▸' }), _jsx("b", { style: { fontSize: 11 }, children: "report" }), _jsx("span", { style: { color: C.faint }, children: lane.report === null ? 'not delivered' : lane.reportSource === 'recovery' ? 'extracted by recovery' : 'delivered' })] }), reportOpen && lane.report !== null && (_jsx("div", { style: { margin: '6px 0 2px 16px', lineHeight: 1.5, color: '#3c4043', whiteSpace: 'pre-wrap' }, children: lane.report }))] }))] })] }));
928
+ }, children: [_jsxs("span", { style: { fontFamily: mono, fontWeight: 600, fontSize: 11 }, children: [lane.role ?? 'agent', " #", lane.agentId] }), lane.parentAgentId !== null && m.lanes.has(lane.parentAgentId) && (_jsxs("span", { style: chip, children: ["forked from #", lane.parentAgentId] })), _jsxs("span", { style: chip, children: [lane.outcome, lane.doneAt !== null && m.runStartAt !== null ? ` · ${fmtS((lane.doneAt - lane.spawnedAt) / 1000)}` : ''] }), _jsx("span", { style: { flex: 1 } }), canCancel && lane.doneAt === null && (_jsx("button", { onClick: () => send({ type: 'cancel_agent', agentId: lane.agentId }), "aria-label": "cancel this agent", title: "cancel this agent \u2014 its branch is reclaimed; siblings continue. Works while paused: evaluate trajectories, cull, play", style: { ...runBtn, color: C.fail, borderColor: '#f0c4c1', padding: '2px 7px', display: 'inline-flex', alignItems: 'center' }, children: _jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [_jsx("polyline", { points: "3 6 5 6 21 6" }), _jsx("path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" }), _jsx("line", { x1: "10", y1: "11", x2: "10", y2: "17" }), _jsx("line", { x1: "14", y1: "11", x2: "14", y2: "17" })] }) })), _jsx("span", { style: { cursor: 'pointer', color: C.dim }, onClick: onClose, title: "close \u2014 the timeline returns to full width", children: "\u2715" })] }), _jsxs("div", { style: { overflowY: 'auto', flex: 1, fontSize: 11, paddingBottom: 8 }, children: [_jsx(EpistemicsChart, { m: m, lane: lane, nowMs: nowMs }), lane.prompt && (_jsxs("div", { style: { borderBottom: `1px solid ${C.border}`, padding: '4px 12px 6px' }, children: [_jsxs("div", { role: "button", tabIndex: 0, onClick: () => toggle('prompt'), onKeyDown: keyActivate(() => toggle('prompt')), style: { display: 'flex', alignItems: 'baseline', gap: 7, cursor: 'pointer', padding: '2px 0' }, title: "the compiled prompt suffix that seeded this agent. In shared-spine mode the system + tool header lives on the spine PREFIX (inherited via fork) and is not repeated here; recursive agents inherit further parent context the same way", children: [_jsx("span", { style: { color: C.faint, fontSize: 9, width: 9, flex: 'none' }, children: expanded.has('prompt') ? '▾' : '▸' }), _jsx("span", { style: { color: C.dim }, children: "prompt" }), _jsxs("span", { style: { fontFamily: mono, fontSize: 10, color: C.faint }, children: [lane.prompt.tokenCount.toLocaleString(), " tok"] })] }), expanded.has('prompt') && _jsx(JsonBlock, { text: lane.prompt.text, raw: true })] })), (lane.failReason || lane.dropReason) && (_jsxs("div", { style: { display: 'flex', alignItems: 'baseline', padding: '6px 12px', gap: 8 }, children: [_jsx("span", { style: { color: C.dim, width: 92, flex: 'none' }, children: "pool said" }), _jsx("span", { style: { fontFamily: mono, fontSize: 11 }, children: lane.dropReason ?? lane.failReason })] })), items.map((it) => it.el), planView, lane.role !== 'planner' && (lane.report !== null || lane.outcome === 'failed') && (_jsxs("div", { style: feedItem, children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 7, cursor: 'pointer' }, onClick: () => toggle('report'), children: [_jsx("span", { style: { color: C.faint, fontSize: 9, width: 9, flex: 'none' }, children: reportOpen ? '▾' : '▸' }), _jsx("b", { style: { fontSize: 11 }, children: "report" }), _jsx("span", { style: { color: C.faint }, children: lane.report === null ? 'not delivered' : lane.reportSource === 'recovery' ? 'extracted by recovery' : 'delivered' })] }), reportOpen && lane.report !== null && (() => {
929
+ // Raw <think> never renders — the report splits into the
930
+ // shared reasoning box + what the agent actually said.
931
+ const { reasoning, said } = splitThink(lane.report);
932
+ return (_jsxs("div", { style: { margin: '6px 0 2px 16px' }, children: [reasoning && _jsx(Reasoning, { text: reasoning, open: expanded.has('report-reasoning'), onToggle: () => toggle('report-reasoning') }), _jsx("div", { style: { lineHeight: 1.5, color: '#3c4043', whiteSpace: 'pre-wrap' }, children: said })] }));
933
+ })()] }))] })] }));
934
+ }
935
+ /** One timeline row — session, spine, and every lane share it. The
936
+ * connector overlay derives its geometry from this same constant, which is
937
+ * what makes curves survive any resize without DOM measurement. */
938
+ const ROW_H = 38;
939
+ /** Trunk marker colors — one per conversation side, same family as the
940
+ * lanes: the query is the deep blue everything forks from, the response the
941
+ * light one. Tools are grey. */
942
+ const TRUNK_QUERY = '#174ea6';
943
+ const TRUNK_RESPONSE = '#5f8fd9';
944
+ const TRUNK_TOOL = '#9aa0a6';
945
+ /** Split verbatim model text into its reasoning and its said text. The pane
946
+ * never renders raw `<think>` markup anywhere — reasoning is shown behind
947
+ * {@link Reasoning}. An unclosed block (a cut stream) still splits clean. */
948
+ function splitThink(text) {
949
+ const parts = text.split(/<think>([\s\S]*?)(?:<\/think>|$)/);
950
+ return {
951
+ reasoning: parts.filter((_, k) => k % 2 === 1).join('\n').trim(),
952
+ said: parts.filter((_, k) => k % 2 === 0).join('').trim(),
953
+ };
954
+ }
955
+ /** The expandable reasoning box — one look for every surface that carries
956
+ * model thinking (trunk turns, agent reports). Collapsed by default. */
957
+ function Reasoning({ text, open, onToggle }) {
958
+ return (_jsxs("div", { style: { margin: '0 0 4px' }, children: [_jsxs("div", { role: "button", tabIndex: 0, onClick: onToggle, onKeyDown: keyActivate(onToggle), style: { display: 'flex', alignItems: 'baseline', gap: 7, cursor: 'pointer', padding: '2px 0' }, children: [_jsx("span", { style: { color: C.faint, fontSize: 9, width: 9, flex: 'none' }, children: open ? '▾' : '▸' }), _jsx("span", { style: { color: C.dim }, children: "reasoning" })] }), open && (_jsx("div", { style: { whiteSpace: 'pre-wrap', lineHeight: 1.5, color: C.dim, fontFamily: mono, fontSize: 10.5, maxHeight: 240, overflowY: 'auto', margin: '2px 0 0 16px' }, children: text }))] }));
959
+ }
960
+ /** The spine's feed — the run's root: the user's instruction verbatim
961
+ * (only when the harness declared where it lives — see
962
+ * {@link RunFraming.instruction}), then the compiled header that seeded
963
+ * position 0. This is where a prompt survives when a run fails. */
964
+ function SpineFeed({ m, onClose, width, mediaUrl, toolColor }) {
965
+ // Substance visible by default — only the raw bytes stay behind a click.
966
+ const [headerOpen, setHeaderOpen] = useState(true);
967
+ const [compiledOpen, setCompiledOpen] = useState(false);
968
+ const k = m.spine;
969
+ if (!k)
970
+ return null;
971
+ return (_jsxs("div", { style: {
972
+ width, flex: 'none', borderLeft: '1px solid #d9dce1', display: 'flex',
973
+ flexDirection: 'column', minHeight: 0, background: C.panelBg,
974
+ }, children: [_jsxs("div", { style: {
975
+ height: 30, flex: 'none', display: 'flex', alignItems: 'center', gap: 8, padding: '0 12px',
976
+ borderBottom: `1px solid ${C.border}`, background: '#f8f9fa',
977
+ }, children: [_jsx("span", { style: { fontFamily: mono, fontWeight: 600, fontSize: 11 }, children: "spine" }), _jsx("span", { style: chip, children: "shared agent memory" }), k.inherited !== undefined && (_jsx("span", { style: chip, children: k.inherited > 0 ? `warm · ${k.inherited.toLocaleString()} tok from trunk` : 'cold start' })), k.headerTokens > 0 && (() => {
978
+ const nCtx = m.pressure.length > 0 ? m.pressure[m.pressure.length - 1].nCtx : 0;
979
+ const pct = nCtx > 0 ? Math.round((k.headerTokens / nCtx) * 1000) / 10 : null;
980
+ return _jsxs("span", { style: chip, children: [k.headerTokens.toLocaleString(), " tok", pct !== null ? ` · ${pct}% ctx` : ''] });
981
+ })(), _jsx("span", { style: { flex: 1 } }), _jsx("span", { style: { cursor: 'pointer', color: C.dim }, onClick: onClose, title: "close \u2014 the timeline returns to full width", children: "\u2715" })] }), _jsxs("div", { style: { overflowY: 'auto', flex: 1, fontSize: 11, paddingBottom: 8 }, children: [k.query !== null && (_jsx("div", { style: feedItem, children: _jsxs("div", { style: { background: 'rgba(26,115,232,.05)', borderRadius: 4, padding: '6px 9px' }, children: [_jsxs("div", { style: { display: 'flex', gap: 7, alignItems: 'baseline', marginBottom: 3 }, children: [_jsx("b", { style: { fontSize: 11, color: TRUNK_QUERY }, children: "query" }), _jsx("span", { style: { fontSize: 10.5, color: C.faint }, children: "the user's instruction, as submitted" })] }), k.attachments.length > 0 && (_jsx("div", { style: { display: 'flex', gap: 6, flexWrap: 'wrap', margin: '2px 0 6px' }, children: k.attachments.map((a, j) => mediaUrl ? (_jsx("img", { src: mediaUrl(a.digest), alt: a.digest.slice(0, 12), title: `${a.digest.slice(0, 19)}\u2026`, style: { height: 72, maxWidth: 160, objectFit: 'cover', borderRadius: 4, border: `1px solid ${C.border}` } }, j)) : (_jsxs("span", { style: chip, title: a.digest, children: [a.digest.slice(0, 19), "\\u2026"] }, j))) })), _jsx("div", { style: { whiteSpace: 'pre-wrap', lineHeight: 1.5, color: '#3c4043', fontSize: 11.5, maxHeight: 200, overflowY: 'auto' }, children: k.query })] }) })), (k.tools && k.tools.length > 0) || k.systemText || k.headerText ? (_jsxs("div", { style: { borderBottom: `1px solid ${C.border}`, padding: '4px 12px 6px' }, children: [_jsxs("div", { role: "button", tabIndex: 0, onClick: () => setHeaderOpen((v) => !v), onKeyDown: keyActivate(() => setHeaderOpen((v) => !v)), style: { display: 'flex', alignItems: 'baseline', gap: 7, cursor: 'pointer', padding: '2px 0' }, title: "the shared header prefilled at position 0 \u2014 every agent inherits it via fork", children: [_jsx("span", { style: { color: C.faint, fontSize: 9, width: 9, flex: 'none' }, children: headerOpen ? '▾' : '▸' }), _jsx("span", { style: { color: C.dim }, children: "system + tools" })] }), headerOpen && (_jsxs("div", { style: { margin: '4px 0 2px 16px', display: 'flex', flexDirection: 'column', gap: 8 }, children: [k.tools && k.tools.length > 0 && (_jsx("div", { style: { display: 'flex', flexDirection: 'column', gap: 4 }, children: k.tools.map((t2) => (_jsxs("div", { style: { display: 'flex', gap: 8, alignItems: 'baseline' }, children: [_jsx("span", { style: { flex: 'none', transform: 'translateY(2px)' }, children: _jsx(Badge, { color: toolColor(t2.name), letter: letterOf(t2.name), size: 14 }) }), _jsx("b", { style: { fontFamily: mono, fontSize: 10.5, flex: 'none' }, children: t2.name }), _jsx("span", { style: { color: C.dim, fontSize: 11, lineHeight: 1.4, display: '-webkit-box', WebkitLineClamp: 2, WebkitBoxOrient: 'vertical', overflow: 'hidden' }, title: t2.description, children: t2.description })] }, t2.name))) })), k.systemText && (_jsxs("div", { children: [_jsx("div", { style: { color: C.faint, fontSize: 10, marginBottom: 2 }, children: "system" }), _jsx("div", { style: { lineHeight: 1.5, color: '#3c4043', whiteSpace: 'pre-wrap', fontSize: 11.5, maxHeight: 220, overflowY: 'auto' }, children: k.systemText })] })), k.headerText && (_jsxs("div", { children: [_jsxs("div", { role: "button", tabIndex: 0, onClick: () => setCompiledOpen((v) => !v), onKeyDown: keyActivate(() => setCompiledOpen((v) => !v)), style: { display: 'flex', alignItems: 'baseline', gap: 7, cursor: 'pointer', padding: '2px 0' }, title: "the exact rendered template \u2014 what position 0 actually holds", children: [_jsx("span", { style: { color: C.faint, fontSize: 9, width: 9, flex: 'none' }, children: compiledOpen ? '▾' : '▸' }), _jsx("span", { style: { color: C.dim }, children: "compiled" })] }), compiledOpen && _jsx(JsonBlock, { text: k.headerText, raw: true })] }))] })), (() => {
982
+ // Full accrual: what every fork inherited for free, minus the
983
+ // one shared copy actually prefilled this run. Correct for
984
+ // chain extensions, warm trunk inheritance, and recursive
985
+ // forks — parallel degenerates to header × (n − 1).
986
+ // Only lanes that actually forked the spine count as sharers —
987
+ // the same attribution the connectors draw. A pre-spine lane
988
+ // (the planner) never inherited it and never shows here.
989
+ // Saved follows the cache-read convention: every token an agent
990
+ // forked instead of prefilling counts. The spine's own build is
991
+ // the cache write — never netted out of the headline.
992
+ const sharers = [...m.lanes.values()].filter((l2) => l2.inherited !== undefined);
993
+ const saved = sharers.reduce((n2, l2) => n2 + (l2.inherited ?? 0), 0);
994
+ if (saved <= 0 && sharers.length < 2)
995
+ return null;
996
+ return (_jsxs("div", { style: { padding: '5px 0 1px 16px', fontSize: 11, color: C.dim }, children: [sharers.length >= 2 && (_jsxs(_Fragment, { children: ["shared by ", _jsx("span", { style: { fontFamily: mono }, children: sharers.length }), " agents", saved > 0 ? ' · ' : ''] })), saved > 0 && (_jsxs(_Fragment, { children: ["tokens saved ", _jsx("span", { style: { fontFamily: mono }, children: saved.toLocaleString() })] }))] }));
997
+ })()] })) : null] })] }));
998
+ }
999
+ /** The trunk's feed — the same panel grammar as {@link AgentFeed}, for the
1000
+ * session's own conversation: each `warmDelta` turn verbatim, its KV cost,
1001
+ * and the media that entered with it (thumbnails when the bridge exposes a
1002
+ * content resolver, digest chips otherwise). */
1003
+ function TrunkFeed({ m, onClose, width, mediaUrl }) {
1004
+ const [thinkOpen, setThinkOpen] = useState(() => new Set());
1005
+ // Responses default COLLAPSED — stats stay visible, the body (reasoning +
1006
+ // text) expands on click. A committed exchange's response half can be a
1007
+ // whole brief; the feed must not pay its render until asked.
1008
+ const [respOpen, setRespOpen] = useState(() => new Set());
1009
+ const toggleResp = (i) => {
1010
+ setRespOpen((prev) => {
1011
+ const next = new Set(prev);
1012
+ if (next.has(i))
1013
+ next.delete(i);
1014
+ else
1015
+ next.add(i);
1016
+ return next;
1017
+ });
1018
+ };
1019
+ const toggleThink = (i) => {
1020
+ setThinkOpen((prev) => {
1021
+ const next = new Set(prev);
1022
+ if (next.has(i))
1023
+ next.delete(i);
1024
+ else
1025
+ next.add(i);
1026
+ return next;
1027
+ });
1028
+ };
1029
+ return (_jsxs("div", { style: {
1030
+ width, flex: 'none', borderLeft: '1px solid #d9dce1', display: 'flex',
1031
+ flexDirection: 'column', minHeight: 0, background: C.panelBg,
1032
+ }, children: [_jsxs("div", { style: {
1033
+ height: 30, flex: 'none', display: 'flex', alignItems: 'center', gap: 8, padding: '0 12px',
1034
+ borderBottom: `1px solid ${C.border}`, background: '#f8f9fa',
1035
+ }, children: [_jsx("span", { style: { fontFamily: mono, fontWeight: 600, fontSize: 11 }, children: "session" }), _jsx("span", { style: chip, children: "the conversation" }), _jsx("span", { style: { flex: 1 } }), _jsx("span", { style: { cursor: 'pointer', color: C.dim }, onClick: onClose, title: "close \u2014 the timeline returns to full width", children: "\u2715" })] }), _jsx("div", { style: { overflowY: 'auto', flex: 1, fontSize: 11, paddingBottom: 8 }, children: m.trunk.map((t, i) => {
1036
+ // Query and response render as their OWN blocks — a committed
1037
+ // exchange (`speaker: 'turn'`) carries both halves structurally,
1038
+ // and single-sided deltas carry one. Raw <think> never renders:
1039
+ // the response side splits into the shared reasoning box.
1040
+ const isTurn = t.speaker === 'turn';
1041
+ const q = isTurn ? (t.query ?? '') : t.speaker === 'user' ? t.content : '';
1042
+ const rRaw = isTurn ? (t.response ?? '') : (t.speaker === 'assistant' || t.speaker === 'tool' || t.speaker === undefined) ? t.content : '';
1043
+ const { reasoning, said } = splitThink(rRaw);
1044
+ const meta = (_jsxs("span", { style: { fontFamily: mono, fontSize: 10, color: C.faint }, children: [t.cells.toLocaleString(), " tokens"] }));
1045
+ return (_jsxs("div", { style: feedItem, children: [(q || t.attachments.length > 0) && (_jsxs("div", { style: { background: 'rgba(26,115,232,.05)', borderRadius: 4, padding: '6px 9px', margin: '0 0 6px' }, children: [_jsxs("div", { style: { display: 'flex', gap: 7, alignItems: 'baseline', marginBottom: 3 }, children: [_jsx("b", { style: { fontSize: 11, color: C.agentDark }, children: "query" }), meta] }), t.attachments.length > 0 && (_jsx("div", { style: { display: 'flex', gap: 6, flexWrap: 'wrap', margin: '2px 0 6px' }, children: t.attachments.map((a, j) => mediaUrl ? (_jsx("img", { src: mediaUrl(a.digest), alt: a.mediaType ?? a.digest.slice(0, 12), title: `${a.mediaType ?? 'media'} · ${a.digest.slice(0, 19)}…`, style: { height: 72, maxWidth: 160, objectFit: 'cover', borderRadius: 4, border: `1px solid ${C.border}` } }, j)) : (_jsxs("span", { style: chip, title: a.digest, children: [a.mediaType ?? 'media', " \u00B7 ", a.digest.slice(0, 19), "\u2026"] }, j))) })), q && (_jsx("div", { style: { whiteSpace: 'pre-wrap', lineHeight: 1.5, color: '#3c4043', fontFamily: mono, fontSize: 10.5, maxHeight: 200, overflowY: 'auto' }, children: q }))] })), rRaw && (_jsxs("div", { children: [_jsxs("div", { role: "button", tabIndex: 0, onClick: () => toggleResp(i), onKeyDown: keyActivate(() => toggleResp(i)), style: { display: 'flex', gap: 7, alignItems: 'baseline', marginBottom: 3, cursor: 'pointer' }, children: [_jsx("span", { style: { color: C.faint, fontSize: 9, width: 9, flex: 'none' }, children: respOpen.has(i) ? '\u25be' : '\u25b8' }), _jsx("b", { style: { fontSize: 11, color: TRUNK_RESPONSE }, children: t.speaker === 'tool' ? 'tool' : 'response' }), !q && meta, (t.agentTokens ?? 0) > 0 && (_jsxs("span", { style: { fontFamily: mono, fontSize: 10, color: C.faint }, children: [t.agentTokens.toLocaleString(), " tokens"] })), t.wallMs !== undefined && (_jsx("span", { style: { fontFamily: mono, fontSize: 10, color: C.faint }, children: fmtS(t.wallMs / 1000) }))] }), respOpen.has(i) && (_jsxs("div", { style: { margin: '0 0 0 16px' }, children: [reasoning && _jsx(Reasoning, { text: reasoning, open: thinkOpen.has(i), onToggle: () => toggleThink(i) }), said && (_jsx("div", { style: { whiteSpace: 'pre-wrap', lineHeight: 1.5, color: '#3c4043', fontFamily: mono, fontSize: 10.5, maxHeight: 300, overflowY: 'auto' }, children: said }))] }))] }))] }, i));
1046
+ }) })] }));
810
1047
  }
811
1048
  const feedItem = { padding: '7px 12px', borderTop: '1px solid #eceef1' };
812
1049
  const chip = {
@@ -895,69 +1132,19 @@ const cutline = {
895
1132
  borderTop: '1px dashed #dadce0', marginTop: 6,
896
1133
  };
897
1134
  // ═══ Settings: category nav → harness (master list + detail) · ability pages ═══
898
- /** What the detail panel knows about each well-known harness key: what it is,
899
- * and how to change it. Prose is product copy — one clause per sentence. */
900
- /** Config path → the ConfigOrigin field carrying its rung, so the
901
- * exception note (env/cli overrode the manifest) fires for read-only rows
902
- * too — full-rung provenance display stays demoted by design. */
903
- const ORIGIN_KEYS = {
904
- 'model.path': 'modelPath',
905
- 'model.reranker': 'reranker',
906
- 'model.nCtx': 'nCtx',
907
- 'model.gpu': 'gpu',
908
- 'sources.outputDir': 'outputDir',
909
- 'defaults.reasoningMode': 'reasoningMode',
910
- };
911
- const SETTING_META = {
912
- 'defaults.effort': {
913
- desc: 'Run effort preset — agent budget, planner breadth, recovery cap.',
914
- how: 'Change it here; it applies to your next run and is remembered locally. The committed default lives in harness.yml → defaults.effort.',
915
- },
916
- 'defaults.reasoningMode': {
917
- desc: 'flat runs one research wave over the plan; deep lets agents recurse into sub-plans.',
918
- how: 'Change it here; it applies to your next run.',
919
- },
920
- 'sources.outputDir': {
921
- desc: 'Where per-query run-dirs and the session trace are written. Empty means where the harness started.',
922
- how: 'Edit harness.yml → sources.outputDir; the next run picks it up.',
923
- },
924
- 'defaults.maxTurns': {
925
- desc: 'Turn cap per agent run.',
926
- how: 'Edit harness.yml → defaults.maxTurns; the next run picks it up.',
927
- },
928
- 'model.path': {
929
- desc: 'Filesystem path or catalog id of the reasoning model.',
930
- how: 'Saved changes load at the next start; this run keeps the model it booted with.',
931
- },
932
- 'model.reranker': {
933
- desc: 'The admission judge — a pointwise yes/no reranker that gates what enters the context.',
934
- how: 'Saved changes load at the next start.',
935
- },
936
- 'model.nCtx': {
937
- desc: 'Context window of the one shared llama_context — every branch leases cells out of this budget.',
938
- how: 'Edit harness.yml → model.llm.context, then restart.',
939
- },
940
- 'model.branches': {
941
- desc: 'Concurrent sequences — createContext takes it as nSeqMax. Each sequence holds its own KV lease.',
942
- how: 'Edit harness.yml → model.llm.branches, then restart.',
943
- },
944
- 'model.kvCache': {
945
- desc: 'KV cache type for the attention layers — raise for precision, lower for memory.',
946
- how: 'Edit harness.yml → model.llm.kvCache, then restart.',
947
- },
948
- 'model.gpu': {
949
- desc: 'Which native backend the process loaded — picked once at start. A configured backend fails loud if unavailable, never silently CPU.',
950
- how: 'A deploy choice: set harness.yml → model.llm.gpu (or LLOYAL_GPU), then restart.',
951
- },
952
- };
953
1135
  const TIER_NOTE = {
954
1136
  session: 'applies to the next run',
955
1137
  reload: 'saved now — a restart loads it',
956
1138
  boot: 'fixed for this run',
957
1139
  };
958
- function Settings({ m, controls, send }) {
1140
+ function Settings({ m, config, send }) {
959
1141
  const [cat, setCat] = useState('harness');
960
- const [selKey, setSelKey] = useState(controls[0]?.key ?? 'model.path');
1142
+ // With a table the rows are the application's own keys; without one, whatever config the harness announced.
1143
+ const rows = config
1144
+ ? configRows(config)
1145
+ : liveConfigKeys(m.config).map((key) => ({ key, applies: 'session', values: null }));
1146
+ // Open on the first thing that can be changed now, else the first that can be changed at all.
1147
+ const [selKey, setSelKey] = useState((rows.find((r) => r.values && r.applies === 'session') ?? rows.find((r) => r.values) ?? rows[0])?.key ?? '');
961
1148
  // The nav lists INSTALLED abilities (`abilities:state` descriptors) — not
962
1149
  // merely configured ones, or the page you'd use to configure an ability
963
1150
  // could never appear. Harnesses that don't emit descriptors degrade to the
@@ -977,38 +1164,41 @@ function Settings({ m, controls, send }) {
977
1164
  borderLeft: on ? `3px solid ${C.text}` : '3px solid transparent',
978
1165
  }, children: name }, name));
979
1166
  return (_jsxs("div", { style: { flex: 1, minHeight: 0, display: 'flex' }, children: [_jsxs("div", { style: { width: 148, flex: 'none', borderRight: '1px solid #d9dce1', paddingTop: 10, background: C.panelBg, overflowY: 'auto' }, children: [navItem('harness', cat === 'harness'), abilities.length > 0 && _jsx("div", { style: { ...label, padding: '12px 16px 3px' }, children: "abilities" }), abilities.map((a) => navItem(a, cat === a))] }), cat === 'harness'
980
- ? _jsx(HarnessSettings, { m: m, controls: controls, send: send, selKey: selKey, onSelect: setSelKey })
1167
+ ? _jsx(HarnessSettings, { m: m, rows: rows, tiered: config !== undefined, send: send, selKey: selKey, onSelect: setSelKey })
981
1168
  : _jsx(AbilityPage, { m: m, name: cat, send: send })] }));
982
1169
  }
983
- function HarnessSettings({ m, controls, send, selKey, onSelect }) {
1170
+ function HarnessSettings({ m, rows, tiered, send, selKey, onSelect }) {
984
1171
  const config = m.config;
985
- const byTier = (tier) => Object.entries(KEY_TIERS).filter(([, t]) => t === tier).map(([k]) => k);
986
- const controlFor = (key) => controls.find((c) => c.key === key);
987
- const row = (key) => {
988
- const ctl = controlFor(key);
989
- const value = ctl ? ctl.read(config) : readConfigPath(config, key);
990
- if (value === undefined && !ctl)
991
- return null; // skip-if-absent: basic has no defaults block
1172
+ const byTier = (tier) => rows.filter((r) => r.applies === tier);
1173
+ const row = (r) => {
1174
+ const { key } = r;
1175
+ const raw = readConfigPath(config, key); // a declared key the harness never set is still a row: its value is —
1176
+ // A value that is itself a table (an app's own structured key) is shown as it is written.
1177
+ const value = raw === undefined || raw === null ? undefined : typeof raw === 'object' ? JSON.stringify(raw) : String(raw);
992
1178
  const selected = selKey === key;
1179
+ // Choosing the value already in force is a selection, never a command: on a reload row the command would
1180
+ // end the session to apply nothing.
1181
+ const choose = (v) => { onSelect(key); if (v === value)
1182
+ return; const command = configCommand(r, v); if (command)
1183
+ send(command); };
993
1184
  return (_jsxs("div", { onClick: () => onSelect(key), role: "button", tabIndex: 0, onKeyDown: keyActivate(() => onSelect(key)), style: {
994
1185
  display: 'flex', alignItems: 'center', gap: 8, padding: '5px 14px 5px 11px', minHeight: 36,
995
1186
  borderLeft: selected ? `3px solid ${C.text}` : '3px solid transparent', cursor: 'pointer',
996
1187
  background: selected ? C.chromeBg : undefined,
997
- }, children: [_jsx("span", { style: { fontFamily: mono, fontSize: 11.5, fontWeight: 500 }, children: key }), _jsx("span", { style: { flex: 1 } }), ctl?.note && _jsx("span", { style: { color: C.faint, fontSize: 10.5, marginRight: 10, flex: 'none' }, children: ctl.note }), ctl ? (_jsx("span", { style: { display: 'flex', border: '1px solid #dadce0', borderRadius: 4, overflow: 'hidden', width: 276, flex: 'none' }, children: ctl.values.map((v) => (_jsx("span", { onClick: (e) => { e.stopPropagation(); onSelect(key); send({ type: ctl.command, [ctl.field]: v }); }, role: "button", tabIndex: 0, "aria-pressed": v === value, onKeyDown: keyActivate(() => { onSelect(key); send({ type: ctl.command, [ctl.field]: v }); }), style: {
1188
+ }, children: [_jsx("span", { style: { fontFamily: mono, fontSize: 11.5, fontWeight: 500 }, children: key }), _jsx("span", { style: { flex: 1 } }), r.values ? (_jsx("span", { style: { display: 'flex', border: '1px solid #dadce0', borderRadius: 4, overflow: 'hidden', width: 276, flex: 'none' }, children: r.values.map((v) => (_jsx("span", { onClick: (e) => { e.stopPropagation(); choose(v); }, role: "button", tabIndex: 0, "aria-pressed": v === value, onKeyDown: keyActivate(() => choose(v)), style: {
998
1189
  flex: 1, fontSize: 11, padding: '5px 0', textAlign: 'center', cursor: 'pointer',
999
1190
  background: v === value ? C.text : '#fff', color: v === value ? '#fff' : C.dim,
1000
1191
  fontWeight: v === value ? 500 : 400, borderLeft: '1px solid #e8eaed',
1001
- }, children: v }, v))) })) : (_jsxs("span", { style: { fontFamily: mono, fontSize: 11, color: C.dim, maxWidth: 300, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: [value === undefined || value === null || value === '' ? '—' : String(value), key === 'model.branches' && _jsx("span", { style: { color: C.faint }, children: " \u2192 nSeqMax" })] }))] }, key));
1192
+ }, children: v }, v))) })) : (_jsxs("span", { style: { fontFamily: mono, fontSize: 11, color: C.dim, maxWidth: 300, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }, children: [value === undefined || value === '' ? '—' : value, key === 'model.branches' && _jsx("span", { style: { color: C.faint }, children: " \u2192 nSeqMax" })] }))] }, key));
1002
1193
  };
1003
1194
  const head = (t) => (_jsxs("div", { style: { display: 'flex', alignItems: 'baseline', gap: 8, padding: '13px 14px 3px' }, children: [_jsx("span", { style: label, children: t }), _jsx("span", { style: { color: C.faint, fontSize: 10.5 }, children: TIER_NOTE[t] })] }));
1004
- const meta = SETTING_META[selKey];
1005
- const tier = KEY_TIERS[selKey];
1195
+ const selected = rows.find((r) => r.key === selKey);
1196
+ const tier = tiered ? selected?.applies : undefined;
1006
1197
  // The exception case, surfaced exactly when true: something outside the
1007
- // manifest set this value. No badges anywhere else.
1008
- const originKey = controlFor(selKey)?.originKey ?? ORIGIN_KEYS[selKey];
1009
- const origin = originKey && m.origin ? m.origin[originKey] : undefined;
1198
+ // manifest set this value. No badges anywhere else. Provenance is keyed by the config path itself.
1199
+ const origin = m.origin ? m.origin[selKey] : undefined;
1010
1200
  const overridden = origin === 'env' || origin === 'cli';
1011
- return (_jsxs(_Fragment, { children: [_jsxs("div", { style: { flex: 1, minWidth: 0, overflowY: 'auto', paddingBottom: 10 }, children: [byTier('session').length > 0 && head('session'), byTier('session').map(row), byTier('reload').length > 0 && head('reload'), byTier('reload').map(row), byTier('boot').length > 0 && head('boot'), byTier('boot').map(row)] }), _jsxs("div", { style: { width: 400, flex: 'none', borderLeft: '1px solid #d9dce1', overflowY: 'auto', padding: '16px 20px', background: C.panelBg }, children: [meta ? (_jsxs(_Fragment, { children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8 }, children: [_jsx("span", { style: { fontFamily: mono, fontSize: 13, fontWeight: 500 }, children: selKey }), tier && _jsx("span", { style: chip, children: TIER_NOTE[tier] })] }), _jsx("p", { style: { maxWidth: 340, margin: '8px 0 0', fontSize: 12, lineHeight: 1.55, color: '#3c4043' }, children: meta.desc }), _jsx("div", { style: { ...label, marginTop: 16 }, children: "changing it" }), _jsx("p", { style: { maxWidth: 340, margin: '6px 0 0', fontSize: 12, lineHeight: 1.55, color: '#3c4043' }, children: meta.how }), overridden && (_jsxs("div", { style: {
1201
+ return (_jsxs(_Fragment, { children: [_jsx("div", { style: { flex: 1, minWidth: 0, overflowY: 'auto', paddingBottom: 10 }, children: tiered ? ['session', 'reload', 'boot'].map((t) => byTier(t).length > 0 && (_jsxs("div", { children: [head(t), byTier(t).map(row)] }, t))) : rows.map(row) }), _jsxs("div", { style: { width: 400, flex: 'none', borderLeft: '1px solid #d9dce1', overflowY: 'auto', padding: '16px 20px', background: C.panelBg }, children: [selected ? (_jsxs(_Fragment, { children: [_jsxs("div", { style: { display: 'flex', alignItems: 'center', gap: 8 }, children: [_jsx("span", { style: { fontFamily: mono, fontSize: 13, fontWeight: 500 }, children: selKey }), tier && _jsx("span", { style: chip, children: TIER_NOTE[tier] })] }), selected.describe && (_jsx("p", { style: { maxWidth: 340, margin: '8px 0 0', fontSize: 12, lineHeight: 1.55, color: '#3c4043' }, children: selected.describe })), tiered && (_jsxs(_Fragment, { children: [_jsx("div", { style: { ...label, marginTop: 16 }, children: "changing it" }), _jsx("p", { style: { maxWidth: 340, margin: '6px 0 0', fontSize: 12, lineHeight: 1.55, color: '#3c4043' }, children: changing(selected) })] })), overridden && (_jsxs("div", { style: {
1012
1202
  display: 'flex', alignItems: 'baseline', gap: 8, padding: '8px 11px', marginTop: 14,
1013
1203
  background: C.warnBg, border: `1px solid ${C.warnBorder}`, borderRadius: 4, fontSize: 11, maxWidth: 360,
1014
1204
  }, children: [_jsx("b", { children: "currently overridden" }), _jsxs("span", { style: { color: C.dim }, children: [origin === 'env' ? 'an environment variable' : 'a command-line flag', " is overriding the manifest \u2014 the value shown is the one in effect."] })] }))] })) : (_jsx("span", { style: { color: C.faint }, children: "select a setting" })), m.lastSavedTo !== undefined && (_jsx("div", { style: { marginTop: 18, fontFamily: mono, fontSize: 10.5, color: C.dim }, children: m.lastSavedTo === null