agent-dag 1.35.39 → 1.35.41
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 +5 -0
- package/bin/deck.js +56 -19
- package/dist/web/assets/index-Cek9RbkJ.js +78 -0
- package/dist/web/assets/index-lLi5vZlE.css +1 -0
- package/dist/web/index.html +2 -2
- package/package.json +1 -1
- package/src/server/args.mjs +58 -0
- package/src/server/index.mjs +6 -0
- package/src/server/system-metrics.mjs +230 -0
- package/dist/web/assets/index-B9aJiIdI.css +0 -1
- package/dist/web/assets/index-urwzWy4Z.js +0 -77
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.react-flow{direction:ltr}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1;cursor:-webkit-grab;cursor:grab}.react-flow__pane.selection{cursor:pointer}.react-flow__pane.dragging{cursor:-webkit-grabbing;cursor:grabbing}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow .react-flow__edges{pointer-events:none;overflow:visible}.react-flow__edge-path,.react-flow__connection-path{stroke:#b1b1b7;stroke-width:1;fill:none}.react-flow__edge{pointer-events:visibleStroke;cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;-webkit-animation:dashdraw .5s linear infinite;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;-webkit-animation:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge:focus .react-flow__edge-path,.react-flow__edge:focus-visible .react-flow__edge-path{stroke:#555}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge-textbg{fill:#fff}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;-webkit-animation:dashdraw .5s linear infinite;animation:dashdraw .5s linear infinite}.react-flow__connectionline{z-index:1001}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:-webkit-grab;cursor:grab}.react-flow__node.dragging{cursor:-webkit-grabbing;cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:-webkit-grab;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background:#1a192b;border:1px solid white;border-radius:100%}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:-4px;transform:translate(-50%)}.react-flow__handle-top{left:50%;top:-4px;transform:translate(-50%)}.react-flow__handle-left{top:50%;left:-4px;transform:translateY(-50%)}.react-flow__handle-right{right:-4px;top:50%;transform:translateY(-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.center{left:50%;transform:translate(-50%)}.react-flow__attribution{font-size:10px;background:#ffffff80;padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@-webkit-keyframes dashdraw{0%{stroke-dashoffset:10}}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-default,.react-flow__node-input,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:3px;width:150px;font-size:12px;color:#222;text-align:center;border-width:1px;border-style:solid;border-color:#1a192b;background-color:#fff}.react-flow__node-default.selectable:hover,.react-flow__node-input.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:0 1px 4px 1px #00000014}.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:0 0 0 .5px #1a192b}.react-flow__node-group{background-color:#f0f0f040}.react-flow__nodesselection-rect,.react-flow__selection{background:#0059dc14;border:1px dotted rgba(0,89,220,.8)}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls{box-shadow:0 0 2px 1px #00000014}.react-flow__controls-button{border:none;background:#fefefe;border-bottom:1px solid #eee;box-sizing:content-box;display:flex;justify-content:center;align-items:center;width:16px;height:16px;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;padding:5px}.react-flow__controls-button:hover{background:#f4f4f4}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__minimap{background-color:#fff}.react-flow__minimap svg{display:block}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:4px;height:4px;border:1px solid #fff;border-radius:1px;background-color:#3367d9;transform:translate(-50%,-50%)}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:#3367d9;border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}:root,:root[data-theme=dark]{--bg: #0b0c10;--bg-soft: #0f1116;--panel: #14161b;--line: #1f2229;--line-soft: #1a1c22;--text: #d8dae0;--ctl-fill: color-mix(in srgb, var(--text) 7%, transparent);--ctl-edge: color-mix(in srgb, var(--text) 50%, transparent);--muted: #7e828c;--muted-dim: #50535b;--text-dim: #7e828c;--accent: #7dd3fc;--accent-dim: #38bdf850;--ok: #86efac;--warn: #fcd34d;--err: #fca5a5;--inflight: #f0abfc;--shadow-1: 0 6px 18px rgba(0,0,0,.25);--shadow-2: 0 10px 24px rgba(0,0,0,.32);--node-grad: linear-gradient(180deg, var(--panel), var(--bg-soft));--topbar-grad: linear-gradient(to bottom, var(--panel), var(--bg-soft));--bg-grid-1: rgba(125,211,252,.06);--bg-grid-2: rgba(240,171,252,.05);--grid-line: #1a1d24;--minimap-mask: rgba(11,12,16,.85);--session-label-l: 78%;--session-accent-l: 60%;--session-rim-l: 55%;--session-edge-l: 72%;--session-edge-idle-l: 55%;--mcp-dot-l: 65%;color-scheme:dark}:root[data-theme=light]{--bg: #eef1f6;--bg-soft: #ffffff;--panel: #ffffff;--line: #c8cdd6;--line-soft: #dde1e8;--text: #0d1117;--muted: #4a5260;--muted-dim: #7c8493;--text-dim: #5f6673;--ctl-fill: color-mix(in srgb, var(--text) 7%, transparent);--ctl-edge: color-mix(in srgb, var(--text) 50%, transparent);--accent: #0369a1;--accent-dim: rgba(3,105,161,.22);--ok: #157a3a;--warn: #ad4e08;--err: #b91c1c;--inflight: #7e22ce;--shadow-1: 0 4px 14px rgba(15,23,42,.1);--shadow-2: 0 10px 28px rgba(15,23,42,.16);--node-grad: linear-gradient(180deg, #ffffff, #f2f5fa);--topbar-grad: linear-gradient(to bottom, #ffffff, #eef1f6);--bg-grid-1: rgba(3,105,161,.1);--bg-grid-2: rgba(126,34,206,.08);--grid-line: #d0d5dd;--minimap-mask: rgba(238,241,246,.85);--session-label-l: 26%;--session-accent-l: 26%;--session-rim-l: 38%;--session-edge-l: 30%;--session-edge-idle-l: 36%;--mcp-dot-l: 32%;color-scheme:light}:root{--panel-inset: 14px;--ctl-h: 30px}:root{--dim-off: .6;--dim-stale: .45}:root{--edge-transition: opacity .5s ease, stroke-width .2s ease;--ctx-arc-transition: stroke-dasharray .4s ease}@media(prefers-reduced-motion:reduce){:root{--edge-transition: opacity .5s ease;--ctx-arc-transition: none}}:root{--pulse-live: 1.2s ease-in-out}*{box-sizing:border-box}html,body,#root{margin:0;height:100%;background:var(--bg);color:var(--text);font:13px/1.45 -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif;-webkit-font-smoothing:antialiased;overscroll-behavior:none}*::-webkit-scrollbar{width:10px;height:10px}*::-webkit-scrollbar-track{background:transparent}*::-webkit-scrollbar-thumb{background:var(--line);border:2px solid var(--bg);border-radius:999px}*::-webkit-scrollbar-thumb:hover{background:var(--muted-dim)}*{scrollbar-color:var(--line) transparent;scrollbar-width:thin}:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:4px}button:focus-visible,.search input:focus-visible{outline-offset:1px}.app{display:grid;grid-template-columns:1fr 360px;grid-template-rows:52px auto 1fr;height:100vh}.app:has(.session-list){grid-template-columns:240px 1fr 360px}.app:has(.accounts-panel){grid-template-columns:288px 1fr 360px}.app:has(.session-list) .canvas-wrap,.app:has(.accounts-panel) .canvas-wrap{grid-column:2}.app:has(.session-list) .conn-banner,.app:has(.accounts-panel) .conn-banner,.app:has(.session-list) .ver-banner,.app:has(.accounts-panel) .ver-banner{grid-column:2}.canvas-wrap{grid-column:1;grid-row:3}.detail{grid-column:2;grid-row:2 / -1}.app:has(.session-list) .detail{grid-column:3}.vis-hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}.skip-link{position:fixed;top:8px;left:8px;z-index:100;padding:8px 14px;border-radius:8px;background:var(--panel);border:1px solid var(--accent);color:var(--text);font-size:12px;font-weight:600;text-decoration:none;transform:translateY(calc(-100% - 16px))}.skip-link:focus{transform:none}.canvas-wrap:focus-visible{outline-offset:-3px}.topbar{grid-column:1 / -1;display:flex;align-items:center;justify-content:space-between;padding:0 18px;background:var(--topbar-grad);border-bottom:1px solid var(--line);-webkit-user-select:none;user-select:none}.topbar .brand{font-weight:600;letter-spacing:.02em;color:var(--text);display:flex;align-items:center;gap:10px;font-size:14px;white-space:nowrap;flex:none}.topbar .brand h1{font:inherit;margin:0}.topbar .brand .logo{width:14px;height:14px;border-radius:4px;background:conic-gradient(from 220deg,#7dd3fc,#f0abfc,#86efac,#7dd3fc);box-shadow:0 0 12px #7dd3fc73}.topbar .brand .v{color:var(--muted);font-weight:400;font-size:11px;margin-left:2px}.topbar .brand button.v{display:inline-flex;align-items:center;flex:none;gap:5px;padding:2px 7px;border:1px solid transparent;border-radius:999px;background:none;font:inherit;font-size:11px;font-weight:500;cursor:pointer;transition:background .13s,border-color .13s,color .13s,transform .14s cubic-bezier(.23,1,.32,1)}.topbar .brand button.v:active{transform:scale(.97)}.topbar .brand button.v:not(.stale){color:var(--muted);font-weight:400;border-color:var(--ctl-edge)}.topbar .brand button.v:not(.stale):hover{color:var(--text);border-color:var(--text);background:var(--ctl-fill)}.topbar .brand button.v.checking{cursor:progress;opacity:var(--dim-off)}.topbar .brand button.v.stale{color:var(--warn);border-color:color-mix(in srgb,var(--warn) 85%,transparent);background:color-mix(in srgb,var(--warn) 10%,transparent)}.topbar .brand button.v.stale:hover{border-color:var(--warn);background:color-mix(in srgb,var(--warn) 18%,transparent)}.topbar .brand button.v .v-dot{width:5px;height:5px;border-radius:50%;background:var(--warn);box-shadow:0 0 7px var(--warn);animation:pulse 2.4s infinite}.topbar .actions{display:flex;gap:8px;align-items:center}.selected-ribbon{display:inline-flex;align-items:center;gap:8px;padding:4px 6px 4px 10px;margin:0 12px 0 4px;background:var(--bg-soft);border:1px solid var(--ctl-edge);border-radius:999px;color:var(--text);font:inherit;font-size:12px;cursor:pointer;max-width:380px;min-width:0;transition:border-color .12s,background .12s,transform .14s cubic-bezier(.23,1,.32,1)}.selected-ribbon:hover{border-color:var(--accent);background:var(--bg)}.selected-ribbon:active:not(:has(.selected-close:active)){transform:scale(.97)}.selected-ribbon:focus-visible{outline:2px solid var(--accent);outline-offset:1px}.selected-ribbon .selected-label{font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;flex:0 1 auto}.selected-ribbon .selected-cost{color:var(--ok);font-variant-numeric:tabular-nums;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px}.selected-ribbon .selected-rate{color:var(--muted);font-size:10px}.selected-ribbon .selected-extra{display:inline-flex;align-items:center;padding:1px 6px;border-radius:999px;background:var(--accent-dim);color:var(--text);font-size:10px;font-weight:600;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.selected-ribbon .selected-close{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;border-radius:999px;color:var(--muted);font-size:14px;line-height:1;cursor:pointer;transition:background .12s,color .12s,transform .14s cubic-bezier(.23,1,.32,1)}.selected-ribbon .selected-close:hover{background:var(--line);color:var(--text)}.selected-ribbon .selected-close:active{transform:scale(.94)}.topbar .status{color:var(--muted);font-size:12px;margin-right:6px;display:inline-flex;align-items:center;gap:14px}.topbar .status .stat{display:inline-flex;align-items:baseline;gap:4px;font-variant-numeric:tabular-nums}.topbar .status .stat .lbl{color:var(--muted)}.topbar .status .stat+.stat:before{content:"";display:inline-block;width:1px;height:12px;background:var(--line);margin-right:10px;position:relative;top:1px}.topbar .status .sysmeter{display:inline-flex;align-items:center}.topbar .status .stat+.sysmeter:before{content:"";display:inline-block;width:1px;height:12px;background:var(--line);margin-right:10px;position:relative;top:1px}.sysmeter .sm-box{position:relative;width:36px;height:14px;cursor:default}.sysmeter .sm-graphic,.sysmeter .sm-read{position:absolute;top:0;right:0;bottom:0;left:0;transition:opacity .14s ease}.sysmeter .sm-graphic{display:flex;flex-direction:column;justify-content:space-between}.sysmeter .sm-spark{display:block}.sysmeter .sm-ram{display:block;height:3px;border-radius:999px;background:var(--line);overflow:hidden}.sysmeter .sm-ram-fill{display:block;width:100%;height:100%;border-radius:999px;background:var(--accent);transform-origin:left center;transition:transform .42s cubic-bezier(.22,1,.36,1),background .2s ease}.sysmeter .sm-ram-fill.warn{background:var(--warn)}.sysmeter .sm-read{opacity:0;display:flex;align-items:center;justify-content:center;gap:1px;font-size:10px;line-height:1;font-variant-numeric:tabular-nums;color:var(--text);letter-spacing:-.02em}.sysmeter .sm-read b{font-weight:600}.sysmeter .sm-read i{font-style:normal;color:var(--muted);opacity:.7}.sysmeter:hover .sm-graphic{opacity:0}.sysmeter:hover .sm-read{opacity:1}.sysmeter.idle .sm-graphic,.sysmeter.idle:hover .sm-graphic{opacity:.45}.sysmeter .sm-sr{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}@media(prefers-reduced-motion:reduce){.sysmeter .sm-graphic,.sysmeter .sm-read,.sysmeter .sm-ram-fill{transition:none}}.topbar .status .pill{display:inline-flex;align-items:center;gap:6px;padding:3px 8px;border-radius:999px;background:var(--bg-soft);border:1px solid var(--line);font-size:11px}.topbar .status .pill.live{color:var(--ok);border-color:#86efac40}.topbar .status .pill.live:before{content:"";display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--ok);box-shadow:0 0 6px var(--ok);animation:pulse 1.6s ease-in-out infinite}.topbar .status .pill.paused{color:var(--warn);border-color:#fcd34d59;background:#fcd34d0f}.topbar .status .pill.paused:before{content:"";display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--warn);box-shadow:0 0 6px var(--warn)}.topbar .status .pill.dead{color:var(--err);border-color:#fca5a559;background:#fca5a50f}.topbar .status .pill.dead:before{content:"";display:inline-block;width:6px;height:6px;border-radius:50%;background:var(--err);box-shadow:0 0 6px var(--err)}.topbar .status .count{color:var(--text);font-variant-numeric:tabular-nums}.topbar .status .mcp-legend{display:inline-flex;align-items:center;gap:3px;cursor:default}.topbar .status .mcp-legend .mcp-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:hsl(var(--mcp-hue, 200) 65% var(--mcp-dot-l));border:1px solid rgba(0,0,0,.35);box-shadow:0 0 4px #00000040}.topbar .status .mcp-legend .mcp-more{font-size:9px;color:var(--muted);margin-left:1px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.topbar .waiting-stat{display:inline-flex;align-items:center;gap:6px;padding:3px 9px;margin-right:6px;border-radius:999px;background:transparent;border:1px solid color-mix(in srgb,var(--warn) 85%,transparent);color:var(--warn);font:inherit;font-size:11px;cursor:pointer;white-space:nowrap;transition:border-color .12s,background .12s,transform .14s cubic-bezier(.23,1,.32,1)}.topbar .waiting-stat b{font-weight:700;font-variant-numeric:tabular-nums}.topbar .waiting-stat:hover{border-color:var(--warn);background:color-mix(in srgb,var(--warn) 12%,transparent)}.topbar .waiting-stat:active{transform:scale(.97)}@media(prefers-reduced-motion:reduce){.topbar .waiting-stat:active{transform:none}}@keyframes pulse{0%,to{opacity:1}50%{opacity:.35}}button.btn{background:transparent;color:var(--text);border:1px solid var(--ctl-edge);min-height:var(--ctl-h);padding:0 12px;border-radius:6px;cursor:pointer;display:inline-flex;align-items:center;justify-content:center;font:inherit;font-size:12px;transition:border-color .12s,color .12s,background .12s,transform .14s cubic-bezier(.23,1,.32,1)}button.btn:hover{border-color:var(--accent);color:var(--accent)}button.btn:active:not(:disabled){transform:scale(.97)}button.btn.primary{background:var(--accent-dim);color:var(--text);border-color:var(--accent)}button.btn.warn{border-color:color-mix(in srgb,var(--warn) 85%,transparent);color:var(--warn)}button.btn.warn:hover{border-color:var(--warn);color:var(--warn)}button.btn.danger{color:var(--err);border-color:color-mix(in srgb,var(--err) 65%,transparent)}button.btn.danger:hover{border-color:var(--err);color:var(--err);background:color-mix(in srgb,var(--err) 12%,transparent)}button.btn.icon-btn{width:var(--ctl-h);height:var(--ctl-h);padding:0;font-size:14px;line-height:1}button.btn.icon-btn[aria-pressed=true],button.btn.icon-btn[aria-expanded=true]{background:var(--accent);border-color:var(--accent);color:var(--bg)}button.btn.icon-btn[aria-pressed=true]:hover,button.btn.icon-btn[aria-expanded=true]:hover{box-shadow:0 0 0 2px var(--accent-dim)}.search{position:relative;display:inline-flex;align-items:center;margin-right:4px}.search-icon{position:absolute;left:8px;color:var(--muted);font-size:14px;pointer-events:none}.search input{background:var(--bg-soft);color:var(--text);border:1px solid var(--ctl-edge);padding:6px 26px 6px 24px;border-radius:6px;font:inherit;font-size:12px;min-width:240px;outline:none;transition:border-color .12s,box-shadow .12s}.search input::placeholder{color:var(--muted)}.search input:focus{border-color:var(--accent);box-shadow:0 0 0 2px var(--accent-dim)}.search input:focus-visible{outline:2px solid var(--accent);outline-offset:1px}.search-clear{position:absolute;right:4px;background:transparent;border:none;color:var(--muted);cursor:pointer;font-size:16px;padding:0 6px;line-height:1;transition:color .12s,transform .14s cubic-bezier(.23,1,.32,1)}.search-clear:hover{color:var(--text)}.search-clear:active{transform:scale(.94)}.search-kbd{position:absolute;right:6px;pointer-events:none;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;font-weight:600;color:var(--muted);background:var(--bg);border:1px solid var(--line);border-radius:4px;padding:0 5px;line-height:16px;height:16px}.search input:focus~.search-kbd{opacity:0}.search-count{margin-left:6px;font-size:11px;font-variant-numeric:tabular-nums;color:var(--muted);white-space:nowrap}.search-count.none{color:var(--warn)}.search-empty{position:absolute;top:14px;left:50%;transform:translate(-50%);z-index:7;display:flex;align-items:center;gap:10px;padding:6px 8px 6px 14px;background:#14161be0;border:1px solid var(--line);border-radius:999px;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);box-shadow:0 6px 18px #0000004d}:root[data-theme=light] .search-empty{background:#ffffffe0;box-shadow:0 6px 18px #0f172a1a}.search-empty-text{font-size:12px;color:var(--text)}.conn-banner{grid-column:1;grid-row:2;display:flex;align-items:center;gap:10px;padding:8px 18px;background:linear-gradient(90deg,rgba(252,165,165,.12),transparent);border-bottom:1px solid rgba(252,165,165,.3);color:var(--err);font-size:12px;font-weight:500;animation:fadeIn .2s ease}.conn-banner .conn-dot{width:7px;height:7px;border-radius:50%;background:var(--err);box-shadow:0 0 8px var(--err);animation:pulse 1.2s infinite}.ver-banner{grid-column:1;grid-row:2;display:flex;align-items:center;gap:10px;padding:8px 18px;background:linear-gradient(90deg,color-mix(in srgb,var(--warn) 13%,transparent),transparent);border-bottom:1px solid color-mix(in srgb,var(--warn) 30%,transparent);color:var(--text);font-size:12px;font-weight:500;animation:fadeIn .2s ease}.ver-banner .ver-dot{flex:none;width:7px;height:7px;border-radius:50%;background:var(--warn);box-shadow:0 0 8px var(--warn);animation:pulse 2.4s infinite}.ver-banner strong{font-weight:600}.ver-banner strong,.ver-banner .ver-sub{white-space:nowrap}.ver-banner .ver-sub{color:var(--muted);font-weight:400;min-width:0;overflow:hidden;text-overflow:ellipsis}.ver-banner .ver-cmd{display:inline-flex;align-items:center;gap:8px;padding:3px 5px 3px 9px;border:1px solid var(--ctl-edge);border-radius:999px;background:var(--ctl-fill);color:var(--text);cursor:pointer;transition:border-color .13s,background .13s,transform .14s cubic-bezier(.23,1,.32,1)}.ver-banner .ver-cmd:hover{border-color:var(--accent);background:var(--panel)}.ver-banner .ver-cmd:active{transform:scale(.97)}.ver-banner .ver-cmd code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;-webkit-user-select:text;user-select:text}.ver-banner .ver-cmd-hint{font-size:10px;letter-spacing:.04em;text-transform:uppercase;color:var(--text);background:var(--line);border-radius:999px;padding:2px 7px}.ver-banner.done{background:linear-gradient(90deg,color-mix(in srgb,var(--ok) 13%,transparent),transparent);border-bottom-color:color-mix(in srgb,var(--ok) 30%,transparent)}.ver-banner.done .ver-dot{background:var(--ok);box-shadow:0 0 8px var(--ok);animation:none}.ver-banner .ver-act{padding:3px 11px;border:1px solid color-mix(in srgb,var(--warn) 85%,transparent);border-radius:999px;background:color-mix(in srgb,var(--warn) 16%,transparent);color:var(--warn);font:inherit;font-size:11px;font-weight:600;cursor:pointer;transition:background .13s,border-color .13s,transform .14s cubic-bezier(.23,1,.32,1)}.ver-banner .ver-act:hover:not(:disabled){background:color-mix(in srgb,var(--warn) 26%,transparent);border-color:var(--warn)}.ver-banner .ver-act:active:not(:disabled){transform:scale(.97)}.ver-banner .ver-act:disabled{opacity:var(--dim-off);cursor:default}.ver-banner .ver-sub.fail{color:var(--err)}.ver-banner .ver-auto{display:inline-flex;align-items:center;gap:6px;padding:3px 9px;border:1px solid transparent;border-radius:999px;background:none;color:var(--muted);font:inherit;font-size:11px;cursor:pointer;transition:color .13s,border-color .13s,transform .14s cubic-bezier(.23,1,.32,1)}.ver-banner .ver-auto:hover{color:var(--text);border-color:var(--ctl-edge)}.ver-banner .ver-auto:active{transform:scale(.97)}.ver-banner .ver-auto i{width:6px;height:6px;border-radius:50%;background:var(--muted-dim);transition:background .13s,box-shadow .13s}.ver-banner .ver-auto.on{color:var(--warn)}.ver-banner .ver-auto.on i{background:var(--warn);box-shadow:0 0 6px var(--warn)}.ver-banner .ver-close{display:inline-flex;align-items:center;justify-content:center;margin-left:2px;flex:none;width:24px;height:24px;padding:0;border:0;border-radius:999px;background:none;color:var(--muted);font:inherit;font-size:14px;line-height:1;cursor:pointer;transition:background .12s,color .12s,transform .14s cubic-bezier(.23,1,.32,1)}.ver-banner .ver-close:hover{background:var(--line);color:var(--text)}.ver-banner .ver-close:active{transform:scale(.94)}.react-flow__node.rf-dim{opacity:.22;filter:saturate(.4)}.react-flow__node.rf-dim:hover{opacity:.6}.react-flow__node.rf-spotlit-out{opacity:.16;filter:saturate(.3) blur(.3px);transition:opacity .2s ease,filter .2s ease}.react-flow__node.rf-spotlit-out:hover{opacity:.55;filter:saturate(.7)}.react-flow__edge.rf-edge-selected .react-flow__edge-path{stroke-dasharray:6 3;animation:dashflow .8s linear infinite;filter:drop-shadow(0 0 4px var(--accent-dim))}.react-flow__node.rf-exiting{pointer-events:none}.react-flow__node.rf-exiting .agent-node{animation:nodeExit .6s cubic-bezier(.55,0,.55,1) forwards}@keyframes nodeExit{0%{opacity:1;filter:blur(0) saturate(1);transform:scale(1)}60%{opacity:.4;filter:blur(2px) saturate(.4)}to{opacity:0;filter:blur(6px) saturate(0);transform:scale(.85)}}.react-flow__edge.rf-edge-exiting .react-flow__edge-path{animation:edgeExit .6s ease forwards}@keyframes edgeExit{to{opacity:0;stroke-dashoffset:40}}.canvas-wrap{position:relative;background:radial-gradient(1200px 600px at 60% -10%,var(--bg-grid-1),transparent 60%),radial-gradient(1000px 500px at 10% 110%,var(--bg-grid-2),transparent 60%),var(--bg);overflow:hidden}.cat-filter-bar{position:absolute;top:14px;left:14px;z-index:6;display:flex;gap:4px;padding:4px;background:#14161bc7;border:1px solid var(--line);border-radius:999px;backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);box-shadow:0 6px 18px #0000004d}:root[data-theme=light] .cat-filter-bar{background:#ffffffc7;box-shadow:0 6px 18px #0f172a1a}.cat-filter{display:inline-flex;align-items:center;gap:5px;padding:4px 10px 4px 8px;border-radius:999px;border:1px solid transparent;background:transparent;color:var(--text);font:inherit;font-size:11px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:.02em;cursor:pointer;transition:background .12s,color .12s,transform .14s cubic-bezier(.23,1,.32,1)}.cat-filter .cat-emoji{font-size:13px;line-height:1}.cat-filter .cat-name{text-transform:lowercase}.cat-filter:hover{background:var(--ctl-fill)}.cat-filter:active{transform:scale(.97)}.cat-filter:focus-visible{outline:2px solid var(--accent);outline-offset:1px}.cat-filter.off{color:var(--muted)}.cat-filter.off .cat-emoji{filter:grayscale(.7)}.cat-filter.off:hover{color:var(--text)}.cat-filter.off .cat-name{text-decoration:line-through}.detail{position:relative;background:var(--panel);border-left:1px solid var(--line);padding:18px;overflow:auto;display:flex;flex-direction:column;gap:12px}.detail-close{position:absolute;top:10px;right:12px;width:24px;height:24px;display:grid;place-items:center;font-size:18px;line-height:1;color:var(--muted);background:transparent;border:1px solid transparent;border-radius:6px;cursor:pointer;z-index:2;transition:background .12s ease,color .12s ease,border-color .12s ease,transform .14s cubic-bezier(.23,1,.32,1)}.detail-close:hover{color:var(--text);background:var(--ctl-fill);border-color:var(--ctl-edge)}.detail-close:active{transform:scale(.94)}.app:has(.detail-reopen){grid-template-columns:1fr}.app:has(.session-list):has(.detail-reopen){grid-template-columns:240px 1fr}.app:has(.accounts-panel):has(.detail-reopen){grid-template-columns:288px 1fr}.detail-reopen{position:fixed;top:64px;right:0;width:24px;height:44px;display:grid;place-items:center;font-size:16px;line-height:1;color:var(--muted);background:var(--panel);border:1px solid var(--ctl-edge);border-right:none;border-radius:8px 0 0 8px;cursor:pointer;z-index:10;box-shadow:-2px 2px 8px #0003;transition:color .12s ease,background .12s ease,transform .14s cubic-bezier(.23,1,.32,1)}.detail-reopen:hover{color:var(--text)}.detail-reopen:active{transform:scale(.94)}.detail>h2,.detail h3{margin:0;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-weight:600}.detail .empty{color:var(--muted);font-style:italic}.detail .hint{border:1px dashed var(--line);border-radius:8px;padding:12px;color:var(--muted);font-size:12px;line-height:1.55;background:var(--bg-soft)}.detail .hint code{background:var(--bg);border:1px solid var(--line);padding:1px 6px;border-radius:4px;font-size:11px;color:var(--text)}.detail .row{display:flex;justify-content:space-between;align-items:baseline;padding:5px 0;border-bottom:1px solid var(--line-soft);font-size:12px;gap:12px}.detail .row:last-child{border-bottom:none}.detail .row .k{color:var(--muted)}.detail .row .v{color:var(--text);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;overflow:hidden;text-overflow:ellipsis;max-width:220px;white-space:nowrap}.detail .tool{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;padding:5px 0;color:var(--text);display:flex;justify-content:space-between;gap:8px;border-bottom:1px solid var(--line-soft)}.detail .tool:last-child{border-bottom:none}.detail .tool .name{display:inline-flex;align-items:center;gap:8px}.detail .tool .name .status-dot{display:inline-flex;align-items:center;justify-content:center;width:10px;height:10px;flex:0 0 10px;font-size:11px;font-weight:700;line-height:1}.detail .tool .name .status-dot:before{content:"";width:6px;height:6px;border-radius:50%;background:currentColor}.detail .tool .name .status-dot.inflight{color:var(--inflight)}.detail .tool .name .status-dot.inflight:before{animation:pulse var(--pulse-live) infinite}.detail .tool .name .status-dot.done{color:var(--ok)}.detail .tool .name .status-dot.done:before{content:"✓";width:auto;height:auto;background:none}.detail .tool .name .status-dot.err{color:var(--err)}.detail .tool .name .status-dot.err:before{content:"×";width:auto;height:auto;background:none}.react-flow__renderer{background:transparent}.react-flow__node{transition:transform .32s cubic-bezier(.22,1,.36,1);animation:nodeSpawn .36s cubic-bezier(.22,1,.36,1) both}@keyframes nodeSpawn{0%{opacity:0;filter:blur(2px)}}.react-flow__node.dragging,.react-flow__node:active{transition:none}.react-flow__edge-path{stroke:var(--accent-dim);stroke-width:1.5;transition:stroke .2s ease}.react-flow__edge.animated .react-flow__edge-path{stroke:var(--inflight);stroke-dasharray:5;animation:dashflow .8s linear infinite}.react-flow__edge.sess-edge.sess-live .react-flow__edge-path{stroke:hsl(var(--session-hue, 200) 80% var(--session-edge-l))}.react-flow__edge.sess-edge.sess-idle .react-flow__edge-path{stroke:hsl(var(--session-hue, 200) 50% var(--session-edge-idle-l))}@keyframes dashflow{to{stroke-dashoffset:-10}}.react-flow__attribution{display:none}.react-flow__controls{background:var(--panel);border:1px solid var(--line);border-radius:8px;box-shadow:none;overflow:hidden}.react-flow__controls-button{background:var(--panel);color:var(--text);border-bottom:1px solid var(--line);fill:var(--text)}.react-flow__controls-button:hover{background:var(--ctl-fill)}.agent-node{--accent: hsl(var(--session-hue, 200) 70% var(--session-accent-l));position:relative;min-width:220px;max-width:260px;padding:10px 12px 10px 16px;background:var(--node-grad);border:1px solid var(--line);border-radius:10px;color:var(--text);font-size:12px;box-shadow:var(--shadow-1);transition:border-color .2s ease,box-shadow .2s ease;overflow:hidden;will-change:transform}.agent-node:hover{box-shadow:var(--shadow-2)}.agent-node.selected{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent-dim),0 10px 24px #0006}.agent-node.state-active{border-color:var(--inflight);box-shadow:0 0 0 1px #f0abfc73,0 8px 22px #f0abfc2e}.agent-node.state-done{border-color:#86efac80}.agent-node.state-err{border-color:#fca5a599}.agent-node .accent-stripe{position:absolute;left:0;top:0;bottom:0;width:4px;background:var(--accent);opacity:.7}.agent-node .head{display:flex;align-items:center;justify-content:space-between;gap:8px}.agent-node .head-right{display:flex;align-items:center;gap:6px}.ctx-donut{background:transparent;border:none;padding:0;cursor:pointer;line-height:0;border-radius:50%;transition:filter .12s ease,transform .12s ease}.ctx-donut:hover{filter:brightness(1.2);transform:scale(1.08)}.ctx-donut:active{transform:scale(.94)}.ctx-donut:focus-visible{outline:2px solid var(--accent);outline-offset:2px}.ctx-modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background:#0000008c;display:flex;align-items:center;justify-content:center;z-index:100;padding:24px;animation:fadeIn .14s ease-out}.ctx-modal{background:var(--panel);border:1px solid var(--line);border-radius:12px;box-shadow:0 20px 50px #00000080;width:min(560px,100%);max-height:80vh;overflow:auto;padding:18px 20px 22px;color:var(--text);animation:popIn .18s cubic-bezier(.22,1,.36,1)}.ctx-modal-head{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-bottom:14px}.ctx-modal-title{font-size:14px;font-weight:600}.ctx-modal-sub{font-size:11px;color:var(--muted);margin-top:3px}.ctx-modal-close{background:transparent;border:1px solid var(--ctl-edge);color:var(--text);border-radius:6px;width:28px;height:28px;font-size:18px;line-height:1;cursor:pointer;transition:background .12s,border-color .12s,transform .14s cubic-bezier(.23,1,.32,1)}.ctx-modal-close:hover{background:var(--ctl-fill)}.ctx-modal-close:active{transform:scale(.94)}.ctx-window-row{margin-bottom:16px}.ctx-window-bar{position:relative;height:10px;border-radius:999px;background:var(--bg-soft);border:1px solid var(--line);overflow:hidden}.ctx-window-fill{height:100%;background:linear-gradient(90deg,var(--accent),var(--inflight));transition:width .4s ease}.ctx-window-meta{display:flex;justify-content:space-between;font-size:11px;margin-top:6px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--muted)}.ctx-window-pct{color:var(--text);font-weight:600}.ctx-section-title{font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:var(--muted);margin:18px 0 8px;font-weight:600}.ctx-grid{display:grid;grid-template-columns:1fr 1fr;gap:4px 16px}.ctx-row{display:flex;justify-content:space-between;padding:4px 0;font-size:12px;border-bottom:1px dashed var(--line)}.ctx-row.accent .ctx-row-val{color:var(--accent);font-weight:600}.ctx-row-label{color:var(--muted)}.ctx-row-val{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-variant-numeric:tabular-nums}.ctx-empty{font-size:12px;color:var(--muted);padding:8px 0}.ctx-md-list{list-style:none;padding:0;margin:0}.ctx-md-list li{display:flex;justify-content:space-between;align-items:center;gap:12px;padding:6px 0;border-bottom:1px dashed var(--line);font-size:12px}.ctx-md-path{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.ctx-md-size{color:var(--muted);font-variant-numeric:tabular-nums;flex-shrink:0}.agent-node .title{display:flex;align-items:center;gap:8px;min-width:0}.agent-node .title .label{font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:160px}.agent-node .time{font-variant-numeric:tabular-nums;font-size:11px;color:var(--muted);font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.state-pill{display:inline-flex;align-items:center;padding:1px 7px;font-size:10px;font-weight:600;letter-spacing:.06em;text-transform:uppercase;border-radius:999px;border:1px solid transparent}.state-pill.state-active{color:var(--inflight);border-color:#f0abfc66;background:#f0abfc14}.state-pill.state-active:before{content:"";width:5px;height:5px;border-radius:50%;background:var(--inflight);box-shadow:0 0 6px var(--inflight);margin-right:5px;animation:pulse var(--pulse-live) infinite}.state-pill.state-done{color:var(--ok);border-color:#86efac59;background:#86efac14}.state-pill.state-err{color:var(--err);border-color:#fca5a566;background:#fca5a514}.agent-node .waiting-row{display:flex;align-items:center;gap:6px;margin-top:7px;padding:3px 7px;border:1px solid transparent;border-radius:6px;font-size:10px;font-weight:600;min-width:0}.agent-node .waiting-row.permission{color:var(--warn);border-color:color-mix(in srgb,var(--warn) 85%,transparent)}.agent-node .waiting-row.idle{color:var(--accent);border-color:color-mix(in srgb,var(--accent) 85%,transparent)}.agent-node .waiting-said{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.agent-node .waiting-row b{font-weight:700;font-variant-numeric:tabular-nums}.waiting-dot{width:5px;height:5px;border-radius:50%;background:currentColor;flex-shrink:0}.agent-node .approval-blind-row{display:flex;align-items:center;gap:6px;margin-top:7px;padding:3px 7px;font-size:10px;font-weight:600;min-width:0;color:var(--muted);font-style:italic}.agent-node .approval-blind-said{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.approval-blind-dot{width:5px;height:5px;border-radius:50%;border:1px solid currentColor;flex-shrink:0}.agent-node .sub{color:var(--muted);font-size:11px;margin-top:3px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.tool-spark-row{display:flex;align-items:center;gap:8px;margin-top:6px;height:14px}.tool-spark{flex:0 0 auto;overflow:visible}.tool-spark-bar{fill:var(--muted);transition:fill .2s}.tool-spark-bar.active{fill:var(--accent);opacity:.72}.tool-spark-bar.latest{fill:var(--inflight);opacity:1;filter:drop-shadow(0 0 3px rgba(240,171,252,.55))}.tool-spark-label{color:var(--muted);font-size:9px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:.04em;text-transform:uppercase}:root[data-theme=light] .tool-spark-bar{fill:var(--muted-dim)}:root[data-theme=light] .tool-spark-bar.active{fill:var(--accent);opacity:.85}:root[data-theme=light] .tool-spark-bar.latest{fill:var(--inflight);filter:drop-shadow(0 0 3px rgba(126,34,206,.45))}.agent-node .meta{color:var(--muted);font-size:11px;margin-top:8px;display:flex;gap:12px}.agent-node .meta b{color:var(--text);font-weight:600}.agent-node .meta .inflight-meta,.agent-node .meta .inflight-meta b{color:var(--inflight)}.agent-node .meta .tokens-meta{color:var(--accent);margin-left:auto}.agent-node .meta .tokens-meta b{color:var(--accent)}.agent-node .meta .cost-meta{color:var(--ok);display:inline-flex;align-items:baseline;gap:4px}.agent-node .meta .cost-meta b{color:var(--ok)}.agent-node .meta .cost-unpriced{color:var(--muted);font-style:italic}.agent-node .meta .cost-meta .cost-rate{color:var(--muted);font-size:9px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:.02em}.tokens-grid{display:grid;grid-template-columns:1fr 1fr;gap:6px 12px;padding:8px 10px;background:var(--bg-soft);border:1px solid var(--line);border-radius:8px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.tokens-grid>div{display:flex;justify-content:space-between;align-items:baseline}.tokens-grid .k{color:var(--muted);font-size:10px;text-transform:uppercase;letter-spacing:.06em}.tokens-grid b{color:var(--text);font-weight:600;font-variant-numeric:tabular-nums}.agent-node.synthetic{border-style:dashed;opacity:.92}.agent-node .synth-tag{display:inline-flex;align-items:center;justify-content:center;width:14px;height:14px;border-radius:50%;border:1px solid var(--muted);color:var(--muted);font-size:10px;font-weight:700;margin-left:4px}.spawn-badge{display:inline-flex;align-items:center;padding:1px 6px;margin-left:6px;border-radius:999px;border:1px solid var(--line);color:var(--accent);background:var(--bg-soft);font-size:10px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-weight:600}.model-chip{display:inline-flex;align-items:center;padding:1px 7px;margin-left:6px;border-radius:999px;border:1px solid var(--line);color:var(--text);background:var(--bg-soft);font-size:10px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-weight:600;letter-spacing:.02em}.model-chip[title*=opus]{color:#f0abfc;border-color:#f0abfc66;background:#f0abfc0f}.model-chip[title*=sonnet]{color:#7dd3fc;border-color:#7dd3fc66;background:#7dd3fc0f}.model-chip[title*=haiku]{color:#86efac;border-color:#86efac66;background:#86efac0f}.model-chip[title*=fable]{color:#fcd34d;border-color:#fcd34d66;background:#fcd34d0f}:root[data-theme=light] .model-chip[title*=opus]{color:#6b21a8;border-color:#7e22ce8c;background:#7e22ce24}:root[data-theme=light] .model-chip[title*=sonnet]{color:#075985;border-color:#0369a18c;background:#0369a124}:root[data-theme=light] .model-chip[title*=haiku]{color:#166534;border-color:#15803d8c;background:#15803d24}:root[data-theme=light] .model-chip[title*=fable]{color:#92400e;border-color:#b453098c;background:#b4530924}.react-flow__edge-textbg{fill:var(--bg-soft);fill-opacity:.9}.react-flow__edge-text{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;fill:var(--text)}.session-clusters{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;z-index:0;transform-origin:0 0;will-change:transform}.cluster-card{position:absolute;border-radius:16px;border:1px solid hsl(var(--session-hue, 200) 65% var(--session-rim-l) / .32);background:hsl(var(--session-hue, 200) 70% 50% / .04);transition:opacity .2s ease,left .32s cubic-bezier(.22,1,.36,1),top .32s cubic-bezier(.22,1,.36,1),width .32s cubic-bezier(.22,1,.36,1),height .32s cubic-bezier(.22,1,.36,1);overflow:visible;pointer-events:auto;cursor:grab}.cluster-label{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;font-weight:600;letter-spacing:.08em;text-transform:uppercase;padding:3px 10px;border-radius:999px;background:var(--bg);color:hsl(var(--session-hue, 200) 70% var(--session-label-l));border:1px solid hsl(var(--session-hue, 200) 65% var(--session-rim-l) / .5);box-shadow:0 2px 6px #00000040;white-space:nowrap;line-height:1;cursor:grab;pointer-events:auto;touch-action:none;-webkit-user-select:none;user-select:none;transition:box-shadow .12s ease,filter .12s ease}.cluster-label:hover{filter:brightness(1.25);box-shadow:0 4px 14px #00000073,0 0 0 1px currentColor}.cluster-label.dragging{cursor:grabbing;filter:brightness(1.3);box-shadow:0 6px 18px #00000080,0 0 0 1px currentColor}.session-group-handle{cursor:grab;background:transparent}.react-flow__node-sessionGroup{cursor:grab}.react-flow__node-sessionGroup.dragging,.react-flow__node-sessionGroup:active{cursor:grabbing}.react-flow__node-sessionGroup.selected{box-shadow:none}:root[data-theme=light] .cluster-label{background:var(--bg-soft);box-shadow:0 1px 4px #0f172a14}:root[data-theme=light] .cluster-label:hover{filter:brightness(.9)}:root[data-theme=light] .cluster-label.dragging{filter:brightness(.85)}.tool-bursts-layer{position:absolute;top:0;right:0;bottom:0;left:0;pointer-events:none;z-index:5;overflow:visible}.tool-bursts-svg{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;pointer-events:none;overflow:visible}.tool-conn{fill:none;stroke-width:1.4;stroke-dasharray:5 4;stroke-linecap:round;transition:opacity .3s ease}.tool-conn.status-inflight{stroke:var(--inflight);animation:dashflow .7s linear infinite;filter:drop-shadow(0 0 4px rgba(240,171,252,.45))}.tool-conn.status-done{stroke:#86efacd9}.tool-conn.status-err{stroke:#fca5a5d9}.tool-conn.fading{stroke-dasharray:4 6}.tool-burst-wrap{position:absolute;pointer-events:none;will-change:transform}.tool-burst{display:inline-flex;align-items:center;gap:6px;padding:5px 11px 5px 9px;border-radius:999px;background:var(--panel);border:1px solid var(--line);font-size:11px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;box-shadow:0 4px 14px #00000059,0 0 0 1px #00000040;white-space:nowrap;color:var(--text);animation:bubble-spawn .22s cubic-bezier(.34,1.56,.64,1) both}.tool-burst .tb-emoji{font-size:13px;line-height:1;filter:saturate(1.2);display:inline-block}.tool-burst .tb-name{font-weight:600;letter-spacing:.01em}.tool-burst .tb-spin{width:8px;height:8px;border-radius:50%;background:radial-gradient(circle at 30% 30%,var(--inflight),transparent 70%);box-shadow:0 0 8px var(--inflight);animation:pulse var(--pulse-live) infinite}.tool-burst .tb-mark{font-weight:700;font-size:12px;line-height:1;margin-left:2px;animation:mark-pop .26s cubic-bezier(.34,1.56,.64,1) both}.tool-burst .tb-mark.done{color:var(--ok);text-shadow:0 0 6px rgba(134,239,172,.55)}.tool-burst .tb-mark.err{color:var(--err);text-shadow:0 0 6px rgba(252,165,165,.55)}.tool-burst.status-inflight{border-color:#f0abfc8c;background:linear-gradient(180deg,#f0abfc1a,#7dd3fc0d),var(--panel);box-shadow:0 0 0 1px #f0abfc4d,0 6px 18px #f0abfc40}.tool-burst.status-inflight .tb-emoji{animation:emoji-wobble 1.6s ease-in-out infinite}.tool-burst.status-done{border-color:#86efac8c;background:linear-gradient(180deg,rgba(134,239,172,.1),transparent),var(--panel);box-shadow:0 0 0 1px #86efac38,0 4px 14px #86efac26;animation:bubble-spawn .22s cubic-bezier(.34,1.56,.64,1) both,bubble-done-flash .52s ease-out}.tool-burst.status-err{border-color:#fca5a599;background:linear-gradient(180deg,rgba(252,165,165,.1),transparent),var(--panel);box-shadow:0 0 0 1px #fca5a559,0 4px 12px #fca5a52e;animation:bubble-spawn .22s cubic-bezier(.34,1.56,.64,1) both,bubble-err-shake .38s ease-in-out}.tool-burst.fading{animation:bubble-fade-move .6s cubic-bezier(.22,.61,.36,1) forwards,bubble-fade-out .6s linear forwards}.tool-burst{position:relative}.tool-burst:before{content:"";position:absolute;left:4px;top:6px;bottom:6px;width:3px;border-radius:2px;background:var(--cat-accent, transparent);opacity:.85}.tool-burst.cat-file{--cat-accent: #7dd3fc}.tool-burst.cat-shell{--cat-accent: #fcd34d}.tool-burst.cat-web{--cat-accent: #67e8f9}.tool-burst.cat-agent{--cat-accent: #f0abfc}.tool-burst.cat-task{--cat-accent: #86efac}.tool-burst.cat-plan{--cat-accent: #c4b5fd}.tool-burst.cat-mcp{--cat-accent: #5eead4}.tool-burst.cat-other{--cat-accent: #94a3b8}.tool-burst.cat-mcp.mcp-hue{--cat-accent: hsl(var(--mcp-hue, 170) 65% var(--mcp-dot-l))}.tool-burst.dim{opacity:.22;filter:saturate(.4);transition:opacity .18s ease,filter .18s ease}.tool-burst.dim:hover{opacity:.6}.tool-burst.sub{font-size:10px;padding:4px 10px 4px 8px;opacity:.94;animation:bubble-spawn .22s .11s cubic-bezier(.34,1.56,.64,1) both}.tool-burst.sub .tb-emoji{font-size:12px}.tool-burst.sub.status-done{animation:bubble-spawn .22s .11s cubic-bezier(.34,1.56,.64,1) both,bubble-done-flash .52s ease-out}.tool-burst.sub.status-err{animation:bubble-spawn .22s .11s cubic-bezier(.34,1.56,.64,1) both,bubble-err-shake .38s ease-in-out}.tool-burst.sub.fading{animation:bubble-fade-move .6s cubic-bezier(.22,.61,.36,1) forwards,bubble-fade-out .6s linear forwards}.tool-burst.clickable{pointer-events:auto;cursor:pointer;transition:translate .12s ease,scale .14s cubic-bezier(.23,1,.32,1),box-shadow .12s ease,opacity .18s ease,filter .18s ease}.tool-burst.clickable:hover{translate:0 -1px;box-shadow:0 6px 18px #00000073,0 0 0 1px var(--cat-accent, rgba(255,255,255,.15))}.tool-burst.clickable:active{scale:.97}@keyframes bubble-spawn{0%{opacity:0;transform:translate(var(--spawn-dx, -28px),var(--spawn-dy, 0)) scale(.92);filter:blur(3px) brightness(1.4)}55%{opacity:1;transform:translate(0) scale(1.06);filter:blur(0) brightness(1.15);animation-timing-function:cubic-bezier(.23,1,.32,1)}to{transform:translate(0) scale(1)}}@keyframes bubble-done-flash{0%{scale:1;box-shadow:0 0 0 1px #86efac38,0 4px 14px #86efac26}40%{scale:1.14;box-shadow:0 0 0 2px #86efac8c,0 0 22px #86efac8c}to{scale:1;box-shadow:0 0 0 1px #86efac38,0 4px 14px #86efac26}}@keyframes bubble-err-shake{0%,to{translate:0}15%{translate:-4px}35%{translate:4px}55%{translate:-3px}75%{translate:2px}}@keyframes bubble-fade-move{0%{transform:scale(1) translate(0);filter:blur(0)}to{transform:scale(.82) translate(18px,-4px);filter:blur(1.5px)}}@keyframes bubble-fade-out{0%{opacity:1}to{opacity:0}}@keyframes emoji-wobble{0%,to{transform:rotate(-6deg) scale(1)}50%{transform:rotate(6deg) scale(1.08)}}@keyframes mark-pop{0%{opacity:0;transform:scale(.3) rotate(-30deg)}to{opacity:1;transform:scale(1) rotate(0)}}:root[data-theme=light] .tool-burst{box-shadow:0 2px 8px #0f172a1a,0 0 0 1px #0f172a0a}:root[data-theme=light] .tool-burst.status-inflight{border-color:#7e22ce8c;background:linear-gradient(180deg,rgba(126,34,206,.06),transparent),var(--panel);box-shadow:0 0 0 1px #7e22ce33,0 6px 14px #7e22ce2e}:root[data-theme=light] .tool-burst.status-done{border-color:#15803d80}:root[data-theme=light] .tool-burst.status-err{border-color:#b91c1c8c}:root[data-theme=light] .tool-conn.status-inflight{stroke:#7e22ced9;filter:drop-shadow(0 0 3px rgba(126,34,206,.35))}:root[data-theme=light] .tool-conn.status-done{stroke:#15803dd9}:root[data-theme=light] .tool-conn.status-err{stroke:#b91c1cd9}.session-list{grid-column:1;grid-row:2 / -1;background:var(--panel);border-right:1px solid var(--line);display:flex;flex-direction:column;min-height:0;overflow-y:auto}.session-list .sl-header{display:flex;align-items:center;gap:8px;padding:12px var(--panel-inset) 10px;border-bottom:1px solid var(--line);position:sticky;top:0;background:var(--panel);z-index:1}.up-header h2,.ap-header h2,.session-list .sl-header h2{font-size:13px;font-weight:600}.session-list .sl-header h2{margin:0;flex:1;display:inline-flex;align-items:center;gap:8px}.session-list .sl-count{display:inline-flex;align-items:center;padding:1px 7px;border-radius:999px;background:var(--bg-soft);border:1px solid var(--line);color:var(--text);font-size:10px;font-weight:600;text-transform:none;letter-spacing:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.session-list .sl-live-count{font-size:10px;letter-spacing:.06em;text-transform:uppercase;color:var(--inflight);font-weight:600}.session-list .sl-waiting-count{font-size:10px;letter-spacing:.06em;text-transform:uppercase;color:var(--warn);font-weight:600}.session-list .sl-close{width:26px;height:26px}.session-list .sl-rows{--sl-card-gutter: 4px;--sl-card-edge: 1px;flex:1;padding:6px var(--sl-card-gutter);display:flex;flex-direction:column;gap:4px}.session-list .sl-empty{padding:16px 12px;color:var(--muted);font-size:12px;font-style:italic}.session-list .sl-row{display:flex;align-items:flex-start;gap:9px;padding:9px calc(var(--panel-inset) - var(--sl-card-gutter) - var(--sl-card-edge));background:transparent;border-width:var(--sl-card-edge);border-style:solid;border-color:transparent;border-radius:8px;cursor:pointer;text-align:left;color:var(--text);font:inherit;transition:background .12s,border-color .12s,transform .14s cubic-bezier(.23,1,.32,1);min-width:0}.session-list .sl-row:hover{background:var(--bg-soft);border-color:var(--ctl-edge)}.session-list .sl-row:active{transform:scale(.97)}.session-list .sl-row.selected{background:var(--bg-soft);border-color:var(--accent)}.session-list .sl-row:focus-visible{outline:2px solid var(--accent);outline-offset:1px}.sl-dot{display:inline-flex;align-items:center;justify-content:center;width:10px;height:10px;margin-top:5px;flex:0 0 10px;font-size:11px;font-weight:700;line-height:1;color:var(--muted)}.sl-dot:before{content:"";width:8px;height:8px;border-radius:50%;background:currentColor}.up-session-row .sl-dot{margin-top:0}.sl-dot.state-active{color:var(--inflight)}.sl-dot.state-active:before{box-shadow:0 0 8px var(--inflight);animation:pulse var(--pulse-live) infinite}.sl-dot.state-done{color:var(--ok)}.sl-dot.state-done:before{content:"✓";width:auto;height:auto;background:none}.sl-dot.state-err{color:var(--err)}.sl-dot.state-err:before{content:"×";width:auto;height:auto;background:none}.session-list .sl-row-body{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.session-list .sl-row-head{display:flex;align-items:center;gap:6px;min-width:0}.session-list .sl-label{font-weight:600;font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0;flex:1}.session-list .sl-row-meta{display:flex;flex-wrap:wrap;gap:8px;font-size:11px;color:var(--muted);font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.session-list .sl-row-meta b{color:var(--text);font-weight:600;font-variant-numeric:tabular-nums}.session-list .sl-cost b{color:var(--ok)}.session-list .sl-elapsed{margin-left:auto}.session-list .sl-waiting{margin-left:auto;color:var(--warn);font-weight:600}.detail-hero{display:flex;flex-direction:column;gap:8px;padding:4px 0 14px;border-bottom:1px solid var(--line)}.detail-hero .hero-line{display:flex;align-items:center;gap:10px;min-width:0}.detail-hero .hero-title{margin:0;font-size:18px;font-weight:600;letter-spacing:.01em;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;min-width:0}.detail-hero .hero-meta{display:flex;align-items:center;gap:8px;font-size:11px;color:var(--muted);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;flex-wrap:wrap}.detail-hero .hero-meta-item{letter-spacing:.03em}.detail-hero .hero-sep{color:var(--text-dim)}.detail-hero .hero-cost{margin-top:8px;padding:10px 12px;background:var(--bg-soft);border:1px solid var(--line);border-radius:10px}.detail-hero .hero-actions{display:flex;flex-wrap:wrap;gap:6px;margin-top:4px}.detail-hero .hero-action-btn{padding:5px 12px;font-size:11px}.detail-hero .hero-cost-headline{display:flex;align-items:baseline;gap:6px;margin-bottom:8px}.detail-hero .hero-cost-value{font-size:22px;font-weight:700;color:var(--ok);font-variant-numeric:tabular-nums;letter-spacing:-.01em}.detail-hero .hero-cost-label{font-size:10px;text-transform:uppercase;letter-spacing:.1em;color:var(--muted)}.cost-bar{display:flex;height:8px;width:100%;border-radius:4px;overflow:hidden;background:var(--line);gap:1px}.cost-bar .cb-seg{height:100%;display:block;transition:filter .12s ease}.cost-bar .cb-seg:hover{filter:brightness(1.3)}.cost-bar .cb-input{background:#5e9fed}.cost-bar .cb-output{background:#c679ec}.cost-bar .cb-cache-r{background:#5cd699}.cost-bar .cb-cache-w{background:#f2b25a}.detail-section{display:flex;flex-direction:column;gap:8px;padding-top:4px}.detail-section h3{display:flex;align-items:center;gap:8px}.detail-section h3 .section-count{display:inline-flex;align-items:center;padding:1px 7px;border-radius:999px;background:var(--bg-soft);border:1px solid var(--line);color:var(--text);font-size:10px;font-weight:600;text-transform:none;letter-spacing:0;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.activity-row{display:flex;flex-direction:column;gap:8px}.activity-counters{display:flex;gap:12px;font-size:12px;color:var(--muted)}.activity-counters .ac-item b{color:var(--text);font-weight:600;font-variant-numeric:tabular-nums}.activity-counters .ac-live,.activity-counters .ac-live b{color:var(--inflight)}.activity-counters .ac-err,.activity-counters .ac-err b{color:var(--err)}.cat-strip{display:flex;flex-wrap:wrap;gap:5px}.cat-chip{display:inline-flex;align-items:center;gap:5px;padding:3px 9px 3px 7px;border-radius:999px;border:1px solid var(--line);background:var(--bg-soft);font-size:11px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.cat-chip .cat-emoji{font-size:12px;line-height:1}.cat-chip .cat-count{color:var(--text);font-weight:600;font-variant-numeric:tabular-nums}.cat-chip.cat-file{border-color:#7dd3fc66}.cat-chip.cat-shell{border-color:#fcd34d66}.cat-chip.cat-web{border-color:#67e8f966}.cat-chip.cat-agent{border-color:#f0abfc66}.cat-chip.cat-task{border-color:#86efac66}.cat-chip.cat-plan{border-color:#c4b5fd66}.cat-chip.cat-mcp{border-color:#5eead466}.prompts{display:flex;flex-direction:column;gap:8px}.prompt-entry{border:1px solid var(--line);border-radius:8px;padding:8px 10px;background:var(--bg-soft)}.prompt-time{color:var(--muted);font-size:10px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;letter-spacing:.04em;text-transform:uppercase;margin-bottom:4px}.prompt-text{font-size:12px;line-height:1.5;color:var(--text);white-space:pre-wrap;word-break:break-word}button.tool.clickable{width:100%;background:transparent;border:none;border-bottom:1px solid var(--line-soft);text-align:left;cursor:pointer;color:var(--text);font:inherit;padding:6px 0;display:flex;align-items:center;gap:8px;justify-content:space-between;border-radius:4px;transition:background .12s,transform .14s cubic-bezier(.23,1,.32,1)}button.tool.clickable{padding-left:6px;padding-right:6px}button.tool.clickable:hover{background:var(--ctl-fill)}button.tool.clickable:active{transform:scale(.97)}button.tool.clickable:last-child{border-bottom:none}.shortcuts{display:grid;grid-template-columns:auto 1fr;gap:6px 12px;align-items:center}.shortcuts .sc{display:contents}.shortcuts .sc kbd{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;font-weight:600;color:var(--text);background:var(--bg-soft);border:1px solid var(--line);border-bottom-width:2px;border-radius:4px;padding:2px 7px;text-align:center;min-width:38px}.shortcuts .sc span{color:var(--muted);font-size:12px}.empty-hero .hint-row{margin-top:14px;font-size:12px;opacity:.75}.empty-hero .hint-row+.hint-row{margin-top:6px}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background:#0506098c;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px);display:flex;align-items:center;justify-content:center;z-index:100;animation:fadeIn .14s ease-out}:root[data-theme=light] .modal-backdrop{background:#0f172a4d}.modal{width:min(820px,92vw);max-height:82vh;display:flex;flex-direction:column;background:var(--panel);border:1px solid var(--line);border-radius:12px;box-shadow:var(--shadow-2),0 0 0 1px #7dd3fc1a;overflow:hidden;animation:popIn .18s cubic-bezier(.22,1,.36,1)}.modal-head{display:flex;align-items:center;justify-content:space-between;padding:12px 16px;border-bottom:1px solid var(--line);background:var(--bg-soft)}.modal-title{display:flex;align-items:center;gap:10px;min-width:0}.modal-title .status-dot{display:inline-block;width:8px;height:8px;border-radius:50%}.modal-title .status-dot.inflight{background:var(--inflight);animation:pulse var(--pulse-live) infinite}.modal-title .status-dot.done{background:var(--ok)}.modal-title .status-dot.err{background:var(--err)}.modal-tool-name{font-weight:600;font-size:14px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.modal-tool-id{color:var(--muted);font-size:11px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.modal-actions{display:flex;align-items:center;gap:8px}.modal-dur{color:var(--muted);font-size:12px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.modal-body{padding:16px;overflow:auto;display:flex;flex-direction:column;gap:16px}.modal-section h4{margin:0 0 6px;font-size:11px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted);font-weight:600;display:flex;align-items:center;gap:8px}.modal-section .err-tag{font-size:9px;font-weight:700;padding:1px 6px;border-radius:4px;color:var(--err);background:#fca5a51a;border:1px solid rgba(252,165,165,.3)}.modal-note{margin:0;padding:8px 12px;border:1px solid var(--line);border-radius:8px;background:var(--bg);color:var(--muted);font-size:11px;line-height:1.5}.modal-section pre{margin:0;padding:12px;background:var(--bg);border:1px solid var(--line);border-radius:8px;color:var(--text);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:1.5;white-space:pre-wrap;word-break:break-word;max-height:320px;overflow:auto}@keyframes fadeIn{0%{opacity:0}}@keyframes popIn{0%{opacity:0;transform:translateY(4px) scale(.985)}to{opacity:1;transform:none}}.modal.clear-confirm{width:min(440px,92vw)}.clear-confirm .cc-actions{display:flex;justify-content:flex-end;gap:8px}.session-summary{width:min(720px,92vw)}.session-summary .ss-hero{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.6fr);gap:22px;padding:18px 18px 20px;background:linear-gradient(180deg,rgba(134,239,172,.05),transparent);border-bottom:1px solid var(--line)}.session-summary .ss-hero-left{display:flex;flex-direction:column;gap:8px;min-width:0}.session-summary .ss-cost-label{font-size:10px;letter-spacing:.1em;text-transform:uppercase;color:var(--muted)}.session-summary .ss-cost{font-size:34px;font-weight:700;color:var(--ok);font-variant-numeric:tabular-nums;letter-spacing:-.02em;line-height:1}.session-summary .ss-models{display:flex;gap:6px;flex-wrap:wrap}.session-summary .ss-hero-right{display:flex;flex-direction:column;justify-content:center;gap:10px;min-width:0}.cost-bar.cost-bar-lg{height:14px;border-radius:7px}.session-summary .ss-cost-legend{display:grid;grid-template-columns:1fr 1fr;gap:6px 16px;font-size:11px;color:var(--muted);font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.session-summary .ssl{display:inline-flex;align-items:baseline;gap:5px}.session-summary .ssl b{color:var(--text);font-weight:600;font-variant-numeric:tabular-nums}.session-summary .ssl:before{content:"";display:inline-block;width:8px;height:8px;border-radius:2px;margin-right:1px}.session-summary .ssl-in:before{background:#5e9fed}.session-summary .ssl-out:before{background:#c679ec}.session-summary .ssl-cr:before{background:#5cd699}.session-summary .ssl-cw:before{background:#f2b25a}.session-summary .ss-stats{display:grid;grid-template-columns:repeat(6,minmax(0,1fr));gap:6px;padding:14px 18px;border-bottom:1px solid var(--line)}.session-summary .ss-stat{display:flex;flex-direction:column;gap:2px;padding:8px 10px;background:var(--bg-soft);border:1px solid var(--line);border-radius:8px}.session-summary .ss-stat-value{font-size:18px;font-weight:600;color:var(--text);font-variant-numeric:tabular-nums;letter-spacing:-.01em;line-height:1.1}.session-summary .ss-stat-label{font-size:10px;letter-spacing:.08em;text-transform:uppercase;color:var(--muted)}.session-summary .ss-stat.tone-err .ss-stat-value{color:var(--err)}@media(max-width:640px){.session-summary .ss-hero{grid-template-columns:1fr}.session-summary .ss-stats{grid-template-columns:repeat(3,minmax(0,1fr))}}.session-summary .ss-top-tools{display:flex;flex-direction:column;gap:6px}.session-summary .ss-tt{display:grid;grid-template-columns:130px 1fr 36px;gap:10px;align-items:center}.session-summary .ss-tt-name{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;color:var(--text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.session-summary .ss-tt-bar{height:6px;background:var(--line);border-radius:3px;overflow:hidden}.session-summary .ss-tt-bar-fill{display:block;height:100%;background:linear-gradient(90deg,var(--accent),var(--inflight));border-radius:3px}.session-summary .ss-tt-count{text-align:right;font-variant-numeric:tabular-nums;font-size:11px;color:var(--muted)}.session-summary .ss-prompt{font-size:12px;line-height:1.55;color:var(--text);padding:10px 12px;background:var(--bg-soft);border:1px solid var(--line);border-left:3px solid var(--accent);border-radius:4px;white-space:pre-wrap;word-break:break-word;max-height:200px;overflow:auto}.empty-hero{position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);text-align:center;pointer-events:none;color:var(--muted);-webkit-user-select:none;user-select:none;max-width:520px}.empty-hero .orbit-stack{position:relative;width:260px;height:260px;margin:0 auto 28px}.empty-hero .orbit{position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;border:1px dashed rgba(125,211,252,.18)}.empty-hero .orbit.r1{top:0;right:0;bottom:0;left:0;animation:spin 22s linear infinite}.empty-hero .orbit.r2{top:30px;right:30px;bottom:30px;left:30px;animation:spin 14s linear infinite reverse;border-color:#f0abfc33}.empty-hero .orbit.r3{top:60px;right:60px;bottom:60px;left:60px;animation:spin 9s linear infinite;border-color:#86efac38}.empty-hero .orbit .dot{position:absolute;width:14px;height:14px;border-radius:50%;top:-7px;left:50%;margin-left:-7px}.empty-hero .orbit.r1 .dot{background:var(--accent);box-shadow:0 0 22px var(--accent)}.empty-hero .orbit.r2 .dot{background:var(--inflight);box-shadow:0 0 22px var(--inflight);width:12px;height:12px;margin-left:-6px;top:-6px}.empty-hero .orbit.r3 .dot{background:var(--ok);box-shadow:0 0 22px var(--ok);width:10px;height:10px;margin-left:-5px;top:-5px}.empty-hero .orbit .dot.b{top:auto;bottom:-7px}.empty-hero .orbit.r2 .dot.b{bottom:-6px}.empty-hero .orbit.r3 .dot.b{bottom:-5px}.empty-hero .core{position:absolute;top:50%;left:50%;width:56px;height:56px;margin:-28px 0 0 -28px;border-radius:50%;background:radial-gradient(circle at 30% 30%,#f0abfc,#7dd3fc 55%,#14161b);box-shadow:0 0 28px #f0abfc8c,0 0 64px #7dd3fc59;animation:corepulse 2.6s ease-in-out infinite}.empty-hero .core:after{content:"";position:absolute;top:-14px;right:-14px;bottom:-14px;left:-14px;border-radius:50%;border:1px solid rgba(255,255,255,.06);animation:corewave 2.6s ease-out infinite}@keyframes corepulse{0%,to{transform:scale(1);filter:brightness(1)}50%{transform:scale(1.08);filter:brightness(1.15)}}@keyframes corewave{0%{transform:scale(.85);opacity:.6}to{transform:scale(1.6);opacity:0}}.empty-hero h2{color:var(--text);font-size:18px;font-weight:600;margin:0 0 8px;letter-spacing:.01em}.empty-hero p{margin:0;font-size:13px;line-height:1.65}.empty-hero code{background:var(--bg-soft);border:1px solid var(--line);padding:2px 7px;border-radius:5px;color:var(--text);font-size:12px}@keyframes spin{to{transform:rotate(360deg)}}:root[data-theme=light] .topbar .status .pill.live{border-color:#15803d73;background:#e8f2eb}:root[data-theme=light] .topbar .status .pill.paused{border-color:#b4530980;background:#f8eee6}:root[data-theme=light] .topbar .status .pill.dead{border-color:#b91c1c80;background:#f8e8e8}:root[data-theme=light] .agent-node.state-active{border-color:#7e22cea6;box-shadow:0 0 0 1px #7e22ce4d,0 8px 22px #7e22ce2e}:root[data-theme=light] .agent-node.state-done{border-color:var(--ok)}:root[data-theme=light] .agent-node.state-err{border-color:var(--err)}:root[data-theme=light] .state-pill.state-active{border-color:#7e22ce73;background:#7e22ce1a}:root[data-theme=light] .state-pill.state-active:before{box-shadow:0 0 5px #7e22ce8c}:root[data-theme=light] .state-pill.state-done{border-color:#15803d73;background:#15803d1a;color:#166534}:root[data-theme=light] .state-pill.state-err{border-color:#b91c1c80;background:#b91c1c1a}:root[data-theme=light] .modal-section .err-tag{background:#b91c1c1a;border-color:#b91c1c73}:root[data-theme=light] .empty-hero .orbit{border-color:#0369a14d}:root[data-theme=light] .empty-hero .orbit.r2{border-color:#7e22ce4d}:root[data-theme=light] .empty-hero .orbit.r3{border-color:#15803d52}:root[data-theme=light] .empty-hero .core{background:radial-gradient(circle at 30% 30%,#c084fc,#0ea5e9 55%,#1e293b);box-shadow:0 0 28px #7e22ce66,0 0 64px #0369a140}:root[data-theme=light] .conn-banner{background:linear-gradient(90deg,rgba(185,28,28,.14),transparent);border-bottom-color:#b91c1c73}:root[data-theme=light] .search-clear{color:var(--muted)}:root[data-theme=light] .react-flow__edge-path{stroke:#0369a166}:root[data-theme=light] .react-flow__minimap-node{stroke:#0f172a40}.usage-panel{position:fixed;top:60px;right:368px;width:280px;max-height:calc(100vh - 76px);overflow-y:auto;background:var(--panel);border:1px solid var(--line);border-radius:10px;box-shadow:var(--shadow-2);z-index:20;padding:0 0 12px}.up-header{display:flex;align-items:center;gap:8px;padding:10px var(--panel-inset) 8px;border-bottom:1px solid var(--line-soft);position:sticky;top:0;background:var(--panel);z-index:1}.up-header h2{margin:0;flex:1}.up-header-right{display:flex;align-items:center;gap:4px}.up-rate{font-size:11px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-variant-numeric:tabular-nums;color:var(--inflight);padding:2px 6px;border-radius:999px;background:#f0abfc1f}.up-close{line-height:1;padding:2px 6px;color:var(--muted)}.up-total{display:flex;align-items:baseline;gap:8px;padding:14px var(--panel-inset) 6px}.up-total-value{font-size:26px;font-weight:700;font-variant-numeric:tabular-nums;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--ok);line-height:1}.up-total-label{font-size:11px;color:var(--muted)}.usage-panel .cost-bar{margin:4px 14px 10px;width:auto;border-radius:3px}.up-tokens-row{display:flex;flex-wrap:wrap;gap:10px 16px;padding:6px var(--panel-inset) 10px}.up-tok{display:flex;align-items:baseline;gap:5px;font-size:12px;font-variant-numeric:tabular-nums;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.up-k{font-size:10px;color:var(--muted);font-family:inherit}.up-section{padding:0 14px;margin-top:4px;border-top:1px solid var(--line-soft)}.up-section-title{display:flex;align-items:baseline;gap:8px;margin:8px 0 6px;font-size:11px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.04em}.up-section-age{margin-left:auto;font-size:10px;font-weight:400;color:var(--text-dim);text-transform:none;letter-spacing:0;white-space:nowrap}.up-table{width:100%;border-collapse:collapse;font-size:12px}.up-table th{text-align:left;color:var(--muted);font-weight:500;font-size:10px;padding:0 0 4px;border-bottom:1px solid var(--line-soft)}.up-table th:not(:first-child){text-align:right}.up-table td{padding:4px 0;vertical-align:middle}.up-model-name{color:var(--text);font-weight:500;max-width:120px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.up-num{text-align:right;font-variant-numeric:tabular-nums;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;color:var(--muted);font-size:11px}.up-cost-val{color:var(--ok)}.up-sessions{display:flex;flex-direction:column;gap:4px}.up-session-row{display:flex;align-items:center;gap:7px;font-size:12px;padding:3px 0}.up-session-label{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--text)}.up-session-tokens{font-variant-numeric:tabular-nums;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;color:var(--muted)}.up-session-cost{font-variant-numeric:tabular-nums;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;color:var(--ok);min-width:36px;text-align:right}.up-unpriced{color:var(--muted);font-style:italic}.up-hint{padding:8px 14px 4px;font-size:11px;color:var(--muted);line-height:1.5}.up-empty{padding:20px 14px;font-size:12px;color:var(--muted);text-align:center;line-height:1.6}.app:not(:has(.detail)) .usage-panel{right:8px}.up-quota-section{padding-top:10px;border-top:none}.up-refresh-btn{padding:1px 7px;color:var(--muted);line-height:1.4}.up-quota-bars{display:flex;flex-direction:column;gap:10px}.qb-row{display:flex;flex-direction:column;gap:3px}.qb-meta{display:flex;justify-content:space-between;align-items:baseline;font-size:11px}.qb-label{color:var(--muted)}.qb-pct{font-variant-numeric:tabular-nums;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;font-weight:600}.qb-track{position:relative;height:6px;border-radius:3px;background:var(--line);overflow:hidden}.qb-fill{height:100%;border-radius:3px;transition:width .4s ease}.qb-pace-marker{position:absolute;top:0;bottom:0;width:2px;margin-left:-1px;border-radius:1px;box-shadow:0 0 0 1px var(--panel);transition:left .4s ease;z-index:2}.qb-reset-row{display:flex;justify-content:space-between;align-items:baseline;gap:4px;min-height:14px}.qb-reset{font-size:10px;color:var(--text-dim)}.qb-pace{font-size:10px;font-weight:500;text-align:right;flex-shrink:0}.qb-limit-badge{margin-left:4px;font-size:10px}.up-plan-badge{margin-left:6px;padding:1px 5px;border:1px solid var(--line-soft);border-radius:3px;font-size:9px;font-weight:500;color:var(--text-dim);text-transform:none;letter-spacing:0;vertical-align:1px}.up-quota-na{display:flex;flex-direction:column;gap:3px;font-size:11px;color:var(--muted)}.up-quota-hint{color:var(--text-dim)}.up-quota-hint code{background:var(--line);color:var(--text);padding:0 3px;border-radius:3px;font-size:10px}.up-quota-loading{font-size:11px;color:var(--text-dim)}.up-quota-sub{font-size:10px;color:var(--text-dim);margin-top:4px}.up-credits{color:var(--accent)}.up-reset-credits{color:var(--ok)}:root[data-theme=light] .up-rate{background:#7e22ce1a}.uh-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;background:#0000008c;display:flex;align-items:center;justify-content:center;z-index:100;padding:24px;animation:fadeIn .14s ease-out}.uh-modal{background:var(--panel);border:1px solid var(--line);border-radius:12px;box-shadow:0 20px 50px #00000080;width:min(760px,100%);max-height:84vh;overflow:auto;padding:16px 18px 20px;color:var(--text);animation:popIn .18s cubic-bezier(.22,1,.36,1)}.uh-head{display:flex;align-items:center;gap:12px;margin-bottom:14px}.uh-titlewrap{display:flex;flex-direction:column;gap:2px;margin-right:auto}.uh-title{font-size:14px;font-weight:600}.uh-sub{font-size:10px;color:var(--text-dim);font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.uh-range{display:inline-flex;gap:2px;background:var(--bg-soft);border:1px solid var(--line);border-radius:999px;padding:2px}.uh-range-btn{font:inherit;font-size:10px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace;padding:2px 9px;border:none;border-radius:999px;color:var(--muted);background:transparent;cursor:pointer;transition:background .12s,color .12s,transform .14s cubic-bezier(.23,1,.32,1)}.uh-range-btn:hover{color:var(--text)}.uh-range-btn:active{transform:scale(.97)}.uh-range-btn.on{background:var(--accent-dim);color:var(--text)}.uh-reload{width:24px;height:24px;padding:0}.uh-reload:disabled{opacity:var(--dim-off);cursor:default}.uh-close{width:24px;height:24px;font-size:16px;line-height:1;border:none;background:transparent;color:var(--muted);cursor:pointer;border-radius:6px;transition:background .12s,color .12s,transform .14s cubic-bezier(.23,1,.32,1)}.uh-close:hover{color:var(--text);background:var(--ctl-fill)}.uh-close:active{transform:scale(.94)}.uh-status{padding:40px 0;text-align:center;color:var(--muted);font-size:12px}.uh-status.uh-err{color:var(--err);max-width:46ch;margin:0 auto;line-height:1.5}.uh-retry{margin-top:14px}.uh-retry:disabled{opacity:var(--dim-off);cursor:default}.uh-stale{opacity:var(--dim-stale);transition:opacity .12s}.uh-totals{display:grid;grid-template-columns:repeat(4,1fr);gap:8px;margin-bottom:14px}.uh-stat{display:flex;flex-direction:column;gap:2px;padding:8px 10px;background:var(--bg-soft);border:1px solid var(--line-soft);border-radius:8px}.uh-stat-val{font-size:14px;font-weight:600;font-variant-numeric:tabular-nums}.uh-stat-val.accent{color:var(--ok)}.uh-stat-label{font-size:9px;color:var(--muted);text-transform:uppercase;letter-spacing:.06em}.uh-agents{margin-bottom:12px}.uh-agent-bar{display:flex;height:6px;border-radius:3px;background:var(--line);overflow:hidden;margin-bottom:7px}.uh-agent-seg{height:100%}.uh-agent-keys{display:flex;flex-wrap:wrap;gap:12px;font-size:11px;color:var(--muted)}.uh-agent-key{display:inline-flex;align-items:center;gap:5px}.uh-agent-cost{color:var(--text);font-variant-numeric:tabular-nums}.uh-agent-share{color:var(--text-dim);font-variant-numeric:tabular-nums}.uh-chart{display:flex;align-items:flex-end;gap:1px;height:168px;margin-bottom:10px;padding-bottom:16px;border-bottom:1px solid var(--line-soft)}.uh-bar-col{display:flex;flex-direction:column;align-items:center;justify-content:flex-end;height:100%;position:relative;background:none;border:none;padding:0;cursor:pointer;min-width:0;transition:transform .14s cubic-bezier(.23,1,.32,1)}.uh-bar-col:hover .uh-bar{filter:brightness(1.15)}.uh-bar-col:active{transform:scale(.97)}.uh-bar-col.sel .uh-bar{outline:1px solid var(--accent);outline-offset:1px}.uh-bar{width:78%;min-height:1px;display:flex;flex-direction:column;border-radius:2px 2px 0 0;overflow:hidden;transition:height .3s ease}.uh-bar-seg{width:100%}.uh-bar-label{position:absolute;bottom:-15px;font-size:9px;color:var(--text-dim);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;white-space:nowrap;transform:rotate(0);overflow:hidden;max-width:100%;text-overflow:ellipsis}.uh-legend{display:flex;flex-wrap:wrap;gap:10px;margin-bottom:12px;font-size:11px;color:var(--muted)}.uh-legend-item{display:inline-flex;align-items:center;gap:5px}.uh-legend-dot{width:8px;height:8px;border-radius:2px;display:inline-block;flex-shrink:0}.uh-legend-cost{color:var(--text);font-variant-numeric:tabular-nums}.uh-detail{background:var(--bg-soft);border:1px solid var(--line-soft);border-radius:10px;padding:12px 14px}.uh-detail-head{display:flex;align-items:baseline;gap:10px;margin-bottom:10px}.uh-detail-date{font-size:12px;font-weight:600}.uh-detail-cost{font-size:12px;color:var(--ok);font-variant-numeric:tabular-nums}.uh-detail-agents{margin-left:auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:10px;color:var(--text-dim);font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.uh-detail-mini{display:grid;grid-template-columns:repeat(4,1fr);gap:6px;margin-bottom:12px}.uh-ministat{display:flex;flex-direction:column;gap:1px}.uh-ministat-val{font-size:12px;font-variant-numeric:tabular-nums}.uh-ministat-label{font-size:9px;color:var(--muted);text-transform:uppercase;letter-spacing:.05em}.uh-detail-models{display:flex;flex-direction:column;gap:5px}.uh-model-row{display:grid;grid-template-columns:130px 1fr auto;align-items:center;gap:8px}.uh-model-name{display:inline-flex;align-items:center;gap:5px;font-size:11px;min-width:0}.uh-model-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.uh-model-bar{height:6px;border-radius:3px;background:var(--line);overflow:hidden}.uh-model-bar-fill{display:block;height:100%;border-radius:3px}.uh-model-cost{font-size:11px;color:var(--text);font-variant-numeric:tabular-nums}:root[data-theme=light] .uh-backdrop{background:#0f172a4d}.accounts-panel{grid-column:1;grid-row:2 / -1;background:var(--panel);border-right:1px solid var(--line);display:flex;flex-direction:column;min-height:0;overflow-y:auto}.ap-header{display:flex;align-items:center;gap:8px;padding:12px var(--panel-inset) 10px;border-bottom:1px solid var(--line);flex-shrink:0}.ap-header h2{margin:0;letter-spacing:.02em}.ap-header-right{margin-left:auto;display:flex;align-items:center;gap:4px}.ap-refresh{padding:1px 6px}.ap-refresh:disabled{opacity:var(--dim-off);cursor:default}.ap-account{padding:9px var(--panel-inset) 8px;border-bottom:1px solid var(--line-soft)}.ap-account.active{background:color-mix(in srgb,var(--accent) 6%,transparent)}.ap-account.disabled{opacity:var(--dim-off)}.ap-account-head{display:flex;align-items:center;gap:6px;margin-bottom:6px}.ap-num{font-size:10px;color:var(--muted);min-width:9px}.ap-alias{font-size:11px;font-weight:600;color:var(--text);min-width:0;max-width:40%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.ap-email{font-size:10px;color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;min-width:0;flex:1}.ap-badge-active{font-size:10px;color:var(--accent);flex-shrink:0}.ap-switch{padding:1px 7px;flex-shrink:0}.ap-lane{display:grid;grid-template-columns:30px 1fr 32px;grid-template-areas:"label track pct" ". reset reset";align-items:center;gap:2px 6px;margin-bottom:3px}.ap-lane-label{grid-area:label;font-size:10px;color:var(--muted)}.ap-lane-track{grid-area:track;height:4px;border-radius:2px;background:var(--line-soft);overflow:hidden}.ap-lane-fill{height:100%;border-radius:2px}.ap-lane-pct{grid-area:pct;font-size:10px;text-align:right}.ap-lane-reset{grid-area:reset;font-size:9px;color:var(--text-dim)}.ap-lane-reset:empty{display:none}.ap-meta{display:flex;align-items:baseline;gap:8px;margin-top:5px;font-size:9px;color:var(--muted)}.ap-err,.ap-stale{color:var(--warn)}.ap-age{margin-left:auto;white-space:nowrap;cursor:help}.ap-empty{display:flex;flex-direction:column;gap:4px;padding:12px var(--panel-inset);font-size:11px;color:var(--muted)}.ap-hint{font-size:10px;line-height:1.5;color:var(--muted)}.ap-empty .ap-cmd{display:block;margin:6px 0 2px;padding:7px 9px;border-radius:5px;background:color-mix(in srgb,var(--accent) 7%,transparent);color:var(--text);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:10px;line-height:1.5;white-space:pre-wrap;overflow-wrap:anywhere;-webkit-user-select:all;user-select:all}.ap-empty .ap-hint code{padding:1px 4px;border-radius:3px;background:color-mix(in srgb,var(--accent) 7%,transparent);font-size:10px}.ap-failure{display:flex;align-items:flex-start;gap:6px;margin:8px var(--panel-inset) 0;padding:6px 8px;border-radius:4px;background:color-mix(in srgb,var(--err) 12%,transparent);color:var(--err);font-size:10px;word-break:break-word}.ap-failure-text{flex:1;min-width:0}.ap-failure-x{flex:none;margin:-2px -2px 0 0;padding:0 3px;border:0;background:none;color:inherit;opacity:.6;font-size:12px;line-height:1.2;cursor:pointer;transition:opacity .12s,transform .14s cubic-bezier(.23,1,.32,1)}.ap-failure-x:hover{opacity:1}.ap-failure-x:active{transform:scale(.94)}.ap-auto{padding:12px var(--panel-inset) 11px;border-top:1px solid var(--line)}.ap-auto-head{display:flex;align-items:center;gap:10px;min-height:24px}.ap-auto-ctl{margin-left:auto;display:flex;align-items:center;gap:8px;flex-shrink:0}.ap-auto-title{font-size:11px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.04em}.ap-auto-state{display:inline-flex;align-items:center;gap:5px;padding:2px 8px 2px 7px;border:1px solid var(--ctl-edge);border-radius:999px;background:transparent;font:inherit;font-size:10px;color:var(--muted);line-height:1.5}.ap-dot{width:5px;height:5px;border-radius:50%;background:currentColor;opacity:.55;flex-shrink:0}button.ap-auto-state{cursor:pointer;transition:border-color .12s,color .12s,transform .14s cubic-bezier(.23,1,.32,1)}button.ap-auto-state:hover:not(:disabled){border-color:var(--accent);color:var(--accent)}button.ap-auto-state:active:not(:disabled){transform:scale(.97)}button.ap-auto-state:focus-visible{outline:2px solid var(--accent);outline-offset:1px}button.ap-auto-state:disabled{cursor:default;opacity:var(--dim-off)}.ap-auto-state.live{border-color:var(--accent);color:var(--accent)}.ap-pulse{position:relative;width:5px;height:5px;border-radius:50%;background:currentColor;flex-shrink:0}.ap-pulse:after{content:"";position:absolute;top:0;right:0;bottom:0;left:0;border-radius:50%;border:1px solid currentColor;animation:ap-ping 2.6s cubic-bezier(.22,.61,.36,1) infinite}@keyframes ap-ping{0%{transform:scale(1);opacity:.7}50%{transform:scale(3.2);opacity:0}to{transform:scale(3.2);opacity:0}}@media(prefers-reduced-motion:reduce){.ap-pulse:after{animation:none;opacity:.35;transform:scale(2.2)}}.ap-auto-note{margin:9px 0 0;font-size:9px;line-height:1.6;color:var(--muted)}.ap-auto-note .ap-pulse{display:inline-block;margin-right:5px;vertical-align:1px;color:var(--accent)}.ap-auto-note code{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;color:var(--text);white-space:nowrap}.ap-auto-now{font-size:10px;color:var(--muted);font-variant-numeric:tabular-nums}.ap-auto-now:after{content:"/";margin-left:8px;color:var(--muted);opacity:.45}.ap-auto-now.near{color:var(--warn)}.ap-field{position:relative;display:inline-block}.ap-field:after{content:"";position:absolute;right:7px;top:50%;width:5px;height:5px;margin-top:-3px;border-right:1.2px solid currentColor;border-bottom:1.2px solid currentColor;transform:rotate(45deg);opacity:.5;pointer-events:none}.ap-field select{-moz-appearance:none;appearance:none;-webkit-appearance:none;background:var(--ctl-fill);color:var(--text);border:1px solid var(--ctl-edge);border-radius:5px;padding:2px 19px 2px 7px;font:inherit;font-size:11px;line-height:1.5;text-align:right;cursor:pointer;transition:border-color .12s,color .12s,transform .14s cubic-bezier(.23,1,.32,1)}.ap-field select:hover:not(:disabled){border-color:var(--accent);color:var(--accent)}.ap-field select:active:not(:disabled){transform:scale(.97)}.ap-manage .ap-field select{text-align:left}.ap-field select:focus-visible{outline:2px solid var(--accent);outline-offset:1px}.ap-field select:disabled{cursor:default;opacity:var(--dim-off)}.ap-field:has(select:hover:not(:disabled)):after{color:var(--accent);opacity:1}.ap-auto-foot{display:flex;align-items:baseline;gap:8px;margin-top:8px;padding-top:8px;border-top:1px solid var(--line-soft)}.ap-auto-result{font-size:10px;line-height:1.5;color:var(--muted);min-width:0}.ap-rotate{background:none;border:none;padding:0;font:inherit;font-size:9px;color:var(--muted);cursor:pointer;text-decoration:underline dotted;text-underline-offset:2px;transition:color .12s,transform .14s cubic-bezier(.23,1,.32,1)}.ap-rotate:hover:not(:disabled){color:var(--accent)}.ap-rotate:active:not(:disabled){transform:scale(.97)}.ap-rotate:disabled{cursor:default;opacity:var(--dim-off)}.ap-footnote{margin:0;padding:9px 14px 2px;border-top:1px solid var(--line-soft);font-size:9px;line-height:1.5;color:var(--muted);cursor:help}.canvas-wrap.bubbling .react-flow__node{transition:transform .42s cubic-bezier(.22,.61,.36,1)}.canvas-wrap.bubbling .react-flow__node.react-flow__node-sessionGroup{transition:transform .42s cubic-bezier(.22,.61,.36,1),width .42s cubic-bezier(.22,.61,.36,1),height .42s cubic-bezier(.22,.61,.36,1)}@media(prefers-reduced-motion:reduce){.canvas-wrap.bubbling .react-flow__node,.canvas-wrap.bubbling .react-flow__node.react-flow__node-sessionGroup{transition:none}}.canvas-wrap.bubbling .react-flow__node.dragging,.canvas-wrap.dragging-any .react-flow__node,.canvas-wrap.dragging-any .react-flow__node.react-flow__node-sessionGroup{transition:none}.canvas-wrap.dragging-any .cluster-card{transition:opacity .2s ease}@media(prefers-reduced-motion:reduce){.react-flow__node{transition:none;animation:fadeIn .14s ease both}.react-flow__node.rf-exiting .agent-node,.react-flow__edge.rf-edge-exiting .react-flow__edge-path{animation:canvas-fade-out .6s linear forwards}.react-flow__edge.animated .react-flow__edge-path,.react-flow__edge.rf-edge-selected .react-flow__edge-path,.tool-conn.status-inflight{animation:none}.cluster-card{transition:opacity .2s ease}.ctx-donut{transition:filter .12s ease}.ctx-donut:hover{transform:none}.tool-burst,.tool-burst.sub,.tool-burst.status-done,.tool-burst.status-err,.tool-burst.sub.status-done,.tool-burst.sub.status-err{animation:fadeIn .14s ease both}.tool-burst.fading,.tool-burst.sub.fading{animation:canvas-fade-out .6s linear forwards}.tool-burst .tb-spin,.tool-burst .tb-mark,.tool-burst.status-inflight .tb-emoji,.state-pill.state-active:before{animation:none}.tool-burst.clickable{transition:box-shadow .12s ease,opacity .18s ease,filter .18s ease}.tool-burst.clickable:hover{translate:none}.empty-hero .orbit.r1,.empty-hero .orbit.r2,.empty-hero .orbit.r3,.empty-hero .core,.empty-hero .core:after{animation:none}@keyframes canvas-fade-out{to{opacity:0}}}.ap-add{line-height:1;padding:2px 8px 4px;color:var(--accent)}.ap-more{margin-left:4px;display:inline-grid;place-items:center;min-width:24px;min-height:24px;padding:0 2px;border:1px solid transparent;border-radius:6px;background:none;color:var(--text-dim);font-size:13px;line-height:1;cursor:pointer}.ap-account:hover .ap-more,.ap-more:hover,.ap-more:focus-visible,.ap-more.on{color:var(--text)}.ap-more:hover,.ap-more.on{border-color:var(--ctl-edge)}.ap-manage{display:flex;flex-direction:column;gap:8px;margin-top:8px;padding-top:8px;border-top:1px dashed var(--line-soft)}.ap-manage-name,.ap-manage-acts{display:flex;align-items:center;gap:8px}.ap-manage-input{flex:1}.ap-manage-acts .ap-manage-btn.danger{margin-left:auto;min-width:62px}.ap-manage-hint{color:var(--text-dim);font-size:10px;min-width:0}.ap-manage-hint.ap-manage-swap{color:var(--accent)}.ap-manage-input{min-width:0;padding:3px 7px;border:1px solid var(--ctl-edge);border-radius:6px;background:var(--ctl-fill);color:var(--text);font:inherit;font-size:11px;transition:border-color .12s,background .12s}.ap-manage-input:hover{border-color:var(--accent)}.ap-manage-input:focus-visible{outline:2px solid var(--accent);outline-offset:1px}.ap-manage-btn{padding:3px 9px;border:1px solid var(--ctl-edge);border-radius:999px;background:var(--ctl-fill);color:var(--text);font:inherit;font-size:10px;cursor:pointer;transition:border-color .12s,color .12s,background .12s,transform .14s cubic-bezier(.23,1,.32,1)}.ap-manage-btn:hover:not(:disabled){border-color:var(--accent);background:color-mix(in srgb,var(--text) 12%,transparent)}.ap-manage-btn:active:not(:disabled){transform:scale(.97)}.ap-manage-btn:disabled{opacity:var(--dim-off);cursor:default}.ap-manage-btn.danger{color:var(--err);border-color:color-mix(in srgb,var(--err) 65%,transparent)}.ap-manage-btn.danger:hover:not(:disabled){border-color:var(--err)}.ap-manage-btn.danger.armed{color:var(--bg);background:var(--err);border-color:var(--err);font-weight:600}.ap-share{display:flex;flex-direction:column;gap:5px}.ap-share-blob{display:block;max-height:66px;overflow:auto;overflow-wrap:anywhere;padding:6px 8px;border:1px solid var(--line);border-radius:6px;background:var(--bg-soft);color:var(--muted);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:9px;line-height:1.4;-webkit-user-select:all;user-select:all}.ap-share-foot{display:flex;align-items:center;gap:8px}.aa-modal{width:min(560px,92vw)}.aa-body{gap:18px;display:flex;flex-direction:column}.aa-tabs{display:inline-flex;gap:4px}.aa-tab{padding:4px 12px;border:1px solid var(--ctl-edge);border-radius:999px;background:none;color:var(--muted);font:inherit;font-size:12px;cursor:pointer;transition:color .12s,border-color .12s,background .12s,transform .14s cubic-bezier(.23,1,.32,1)}.aa-tab:hover{color:var(--text)}.aa-tab:active{transform:scale(.97)}.aa-tab.on{color:var(--text);border-color:var(--accent);background:color-mix(in srgb,var(--accent) 12%,transparent)}.aa-step{display:flex;flex-direction:column;gap:8px}.aa-step h4{margin:0;color:var(--muted);font-size:10px;font-weight:600;letter-spacing:.06em;text-transform:uppercase}.aa-note{margin:0;color:var(--muted);font-size:12px;line-height:1.5}.aa-err{margin:0;color:var(--err);font-size:12px;line-height:1.5}.aa-link{overflow-wrap:anywhere;padding:8px 10px;border:1px solid var(--ctl-edge);border-radius:8px;background:var(--ctl-fill);color:var(--accent);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;line-height:1.5;text-decoration:none;-webkit-user-select:all;user-select:all}.aa-link:hover{border-color:var(--accent);text-decoration:underline}.aa-field{display:flex;align-items:center;gap:8px}.aa-field input{flex:1;min-width:0;padding:7px 11px;border:1px solid var(--ctl-edge);border-radius:8px;background:var(--bg-soft);color:var(--text);font:inherit;font-size:13px;font-family:ui-monospace,SFMono-Regular,Menlo,monospace}.aa-field input::placeholder{color:var(--text-dim)}.aa-field input:focus-visible{outline:2px solid var(--accent);outline-offset:1px}.aa-field input:disabled{opacity:var(--dim-off)}.aa-primer .aa-note{max-width:46ch}.aa-actions{display:flex;gap:8px;align-items:center;margin-top:2px}.aa-done{position:relative;display:flex;flex-direction:column;align-items:center;gap:10px;padding:6px 0 2px;text-align:center;animation:aa-done-in .22s cubic-bezier(.23,1,.32,1) both}.aa-done h4{margin:0;color:var(--text);font-size:13px;font-weight:600;letter-spacing:0;text-transform:none}.aa-done .aa-note{max-width:44ch}@keyframes aa-done-in{0%{opacity:0;transform:scale(.97) translateY(4px)}to{opacity:1;transform:none}}.aa-mark{width:44px;height:44px;overflow:visible}.aa-mark-ring,.aa-mark-tick{fill:none;stroke:var(--ok);stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}.aa-mark-ring{opacity:.45;stroke-dasharray:126;stroke-dashoffset:126;transform:rotate(-90deg);transform-origin:50% 50%;animation:aa-draw .38s cubic-bezier(.23,1,.32,1) 40ms forwards}.aa-mark-tick{stroke-dasharray:30;stroke-dashoffset:30;animation:aa-draw .26s cubic-bezier(.23,1,.32,1) .2s forwards}@keyframes aa-draw{to{stroke-dashoffset:0}}.confetti{position:fixed;width:0;height:0;z-index:101;pointer-events:none}.confetti-bit{position:absolute;top:0;left:0;width:6px;height:9px;margin:-4px 0 0 -3px;border-radius:1.5px;background:var(--accent);opacity:0;animation:aa-burst-move .9s cubic-bezier(.16,.9,.3,1) both,aa-burst-fade .9s linear both}.confetti-bit.round{width:6px;height:6px;border-radius:50%}.confetti-bit[data-hue="1"]{background:var(--ok)}.confetti-bit[data-hue="2"]{background:var(--warn)}.confetti-bit[data-hue="3"]{background:color-mix(in srgb,var(--accent) 55%,var(--ok))}@keyframes aa-burst-move{0%{transform:translateZ(0) scale(calc(var(--s, 1) * .6)) rotate(0)}70%{transform:translate3d(var(--dx),var(--dy),0) scale(var(--s, 1)) rotate(var(--rot))}to{transform:translate3d(calc(var(--dx) * 1.08),calc(var(--dy) * .82 + 16px),0) scale(calc(var(--s, 1) * .9)) rotate(var(--rot))}}@keyframes aa-burst-fade{0%{opacity:0}10%{opacity:1}62%{opacity:1}to{opacity:0}}@media(prefers-reduced-motion:reduce){.aa-done{animation:aa-done-fade .16s ease both}.aa-mark-ring,.aa-mark-tick{animation:none;stroke-dashoffset:0}@keyframes aa-done-fade{0%{opacity:0}to{opacity:1}}}.cat-filter-bar{transition:opacity .18s ease}.cat-filter-bar.occluded{opacity:.2}.cat-filter-bar.occluded:focus-within{opacity:1}@media(hover:hover)and (pointer:fine){.cat-filter-bar.occluded:hover{opacity:1}}.ap-manage{animation:ap-manage-in .18s cubic-bezier(.23,1,.32,1) both}@keyframes ap-manage-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}.ap-more{transition:color .12s,border-color .12s,transform .14s cubic-bezier(.23,1,.32,1)}.ap-more:active{transform:scale(.94)}.ap-manage-btn.danger.armed{position:relative;overflow:hidden}.ap-manage-btn.danger.armed:after{content:"";position:absolute;left:0;right:0;bottom:0;height:2px;background:color-mix(in srgb,var(--bg) 70%,transparent);transform-origin:left center;animation:ap-disarm 4s linear forwards}@keyframes ap-disarm{0%{transform:scaleX(1)}to{transform:scaleX(0)}}.ap-share{animation:ap-manage-in .18s cubic-bezier(.23,1,.32,1) both}.ap-share-blob{-webkit-user-select:all;user-select:all;max-height:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:var(--text-dim)}.ap-share-foot .ap-manage-btn{color:var(--accent);border-color:var(--accent);background:color-mix(in srgb,var(--accent) 10%,transparent)}.ap-share-foot .ap-manage-btn:hover:not(:disabled){background:color-mix(in srgb,var(--accent) 18%,transparent)}.ap-share.expired .ap-share-blob{opacity:var(--dim-stale)}.ap-share-warn,.ap-share-expiry.soon{color:var(--warn)}.ap-share-expiry.gone{color:var(--err)}@media(prefers-reduced-motion:reduce){.ap-manage,.ap-share{animation:none}.ap-manage-btn.danger.armed:after{animation:none;transform:scaleX(0)}button.btn:active:not(:disabled),.ap-manage-btn:active:not(:disabled),.ap-more:active,.cat-filter:active,.detail-close:active,.ctx-modal-close:active,.uh-close:active,.uh-range-btn:active,.selected-ribbon .selected-close:active,.ver-banner .ver-cmd:active,.ver-banner .ver-auto:active,.ver-banner .ver-close:active,.topbar .brand button.v:active,.search-clear:active,.ver-banner .ver-act:active:not(:disabled),.detail-reopen:active,.ctx-donut:active,.session-list .sl-row:active,button.tool.clickable:active,.uh-bar-col:active,.ap-failure-x:active,button.ap-auto-state:active:not(:disabled),.ap-field select:active:not(:disabled),.ap-rotate:active:not(:disabled),.aa-tab:active{transform:none}.selected-ribbon:active:not(:has(.selected-close:active)){transform:none}.tool-burst.clickable:active{scale:none}}.ap-fix{margin-left:6px;padding:1px 8px;border:1px solid color-mix(in srgb,var(--warn) 85%,transparent);border-radius:999px;background:color-mix(in srgb,var(--warn) 12%,transparent);color:var(--warn);font:inherit;font-size:10px;cursor:pointer;transition:background .12s,border-color .12s,transform .14s cubic-bezier(.23,1,.32,1)}.ap-fix:hover{background:color-mix(in srgb,var(--warn) 22%,transparent);border-color:var(--warn)}.ap-fix:active{transform:scale(.97)}@media(prefers-reduced-motion:reduce){.ap-fix:active{transform:none}}.ap-empty .ap-fix{align-self:flex-start;margin:5px 0 0}.ap-empty .ap-fix:disabled{opacity:var(--dim-off);cursor:default}@media(prefers-reduced-motion:reduce){.ctx-window-fill,.qb-fill,.qb-pace-marker,.uh-bar{transition:none}.modal,.ctx-modal,.uh-modal{animation:fadeIn .14s ease-out}}
|
package/dist/web/index.html
CHANGED
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
document.documentElement.setAttribute("data-theme", stored === "light" ? "light" : "dark");
|
|
41
41
|
})();
|
|
42
42
|
</script>
|
|
43
|
-
<script type="module" crossorigin src="/assets/index-
|
|
44
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
43
|
+
<script type="module" crossorigin src="/assets/index-Cek9RbkJ.js"></script>
|
|
44
|
+
<link rel="stylesheet" crossorigin href="/assets/index-lLi5vZlE.css">
|
|
45
45
|
</head>
|
|
46
46
|
<body>
|
|
47
47
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-dag",
|
|
3
|
-
"version": "1.35.
|
|
3
|
+
"version": "1.35.41",
|
|
4
4
|
"description": "Live deck of Claude Code and Codex agents — watch tool calls, token spend and every Claude Code subagent on one calm canvas. Also available as npx ccdeck and npx agent-dag.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
// The command line, parsed: everything the deck recognises, and everything it
|
|
2
|
+
// does not.
|
|
3
|
+
//
|
|
4
|
+
// Its own module rather than a function inside bin/deck.js, for one reason —
|
|
5
|
+
// importing bin/deck.js RUNS a deck. That file installs hooks, binds a port and
|
|
6
|
+
// opens a browser at module scope, so there was no way to ask what `--prot`
|
|
7
|
+
// parses to without starting a server to find out. Nothing here does any of
|
|
8
|
+
// that: strings in, a plain object out, no I/O, no process, no terminal.
|
|
9
|
+
//
|
|
10
|
+
// bin/deck.js is the only caller. The parser is the whole of the module's
|
|
11
|
+
// surface; the tables it matches against stay inside it.
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Parse `process.argv.slice(2)`.
|
|
15
|
+
*
|
|
16
|
+
* Returns the flags that were set, plus `unknown` — every token the loop did
|
|
17
|
+
* not recognise, in the order it met them. That list is the point of this
|
|
18
|
+
* module: the loop used to have no `else`, so `ccdeck --prot 4500` booted on
|
|
19
|
+
* 4317 and said nothing, and a typo was indistinguishable from a flag that
|
|
20
|
+
* worked.
|
|
21
|
+
*
|
|
22
|
+
* The three flags that TAKE a value (`--port`, `--workspace`, `--history`)
|
|
23
|
+
* consume it with `args[++i]`, so the value is never re-examined as a token of
|
|
24
|
+
* its own and cannot land in `unknown` — `--port 4500` says nothing about
|
|
25
|
+
* `4500`, and `--workspace ~/some dir` nothing about the path. That is the way
|
|
26
|
+
* an unknown-flag warning usually goes wrong, and it is asserted rather than
|
|
27
|
+
* assumed; see src/web/__tests__/argv-480.test.ts.
|
|
28
|
+
*
|
|
29
|
+
* A bare word is `unknown` too, and deliberately: the deck takes no positional
|
|
30
|
+
* arguments at all, so `ccdeck ~/proj` is the same mistake as `ccdeck --workpace
|
|
31
|
+
* ~/proj` — something the deck read and then did nothing with. It is also how
|
|
32
|
+
* an unquoted path with a space in it becomes visible, which is a failure this
|
|
33
|
+
* repo already knew about and could not previously report: `--workspace
|
|
34
|
+
* C:\Users\John Smith\proj` reaches the parser as two arguments, and the second
|
|
35
|
+
* one used to be dropped in silence (see launchNpx in bin/agent-dag.js).
|
|
36
|
+
*/
|
|
37
|
+
export function parseArgs(args) {
|
|
38
|
+
const out = { unknown: [] };
|
|
39
|
+
for (let i = 0; i < args.length; i++) {
|
|
40
|
+
const a = args[i];
|
|
41
|
+
if (a === "-h" || a === "--help") out.help = true;
|
|
42
|
+
else if (a === "-v" || a === "--version") out.version = true;
|
|
43
|
+
else if (a === "-p" || a === "--port") out.port = args[++i];
|
|
44
|
+
else if (a === "--no-open") out.noOpen = true;
|
|
45
|
+
else if (a === "--uninstall") out.uninstall = true;
|
|
46
|
+
else if (a === "--workspace") out.workspace = args[++i];
|
|
47
|
+
else if (a === "--scope") out.scope = true;
|
|
48
|
+
else if (a === "--all") out.all = true; // legacy no-op (now default)
|
|
49
|
+
else if (a === "--no-persist") out.noPersist = true;
|
|
50
|
+
else if (a === "--history") out.history = args[++i];
|
|
51
|
+
else if (a === "--codex") out.codex = true;
|
|
52
|
+
else if (a === "--no-codex") out.noCodex = true;
|
|
53
|
+
else if (a === "--claude") out.claude = true;
|
|
54
|
+
else if (a === "--no-claude") out.noClaude = true;
|
|
55
|
+
else out.unknown.push(a);
|
|
56
|
+
}
|
|
57
|
+
return out;
|
|
58
|
+
}
|
package/src/server/index.mjs
CHANGED
|
@@ -14,6 +14,7 @@ import { CODEX_HOME, CODEX_SESSIONS_DIR, STOP, walkRolloutDays } from "./codex-d
|
|
|
14
14
|
import { PRODUCT } from "./brand.mjs";
|
|
15
15
|
import { invokedName, renameNotice } from "./invoked-as.mjs";
|
|
16
16
|
import { appendLogLine, codexCwdInWorkspace, writesCodexLog } from "./log-writer.mjs";
|
|
17
|
+
import { startSystemMetrics, systemSnapshot } from "./system-metrics.mjs";
|
|
17
18
|
|
|
18
19
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
19
20
|
const PKG_ROOT = resolve(__dirname, "..", "..");
|
|
@@ -3050,6 +3051,9 @@ export async function startServer({ port = 4317, host = "127.0.0.1", persist = n
|
|
|
3050
3051
|
if (req.method === "POST" && url.pathname === "/api/restart") return guard(handleRestart(req, res), res);
|
|
3051
3052
|
if (req.method === "GET" && url.pathname === "/api/quota") return guard(handleQuota(req, res), res);
|
|
3052
3053
|
if (req.method === "GET" && url.pathname === "/api/codex-usage") return guard(handleCodexUsage(req, res), res);
|
|
3054
|
+
// Machine state, not session state: sampled on the server's own timer and
|
|
3055
|
+
// deliberately kept out of the event stream. See src/server/system-metrics.mjs.
|
|
3056
|
+
if (req.method === "GET" && url.pathname === "/api/system") return send(res, 200, systemSnapshot());
|
|
3053
3057
|
if (req.method === "GET" && url.pathname === "/api/codex-quota") return guard(handleCodexQuota(req, res), res);
|
|
3054
3058
|
if (req.method === "GET" && url.pathname === "/api/ccusage") return guard(handleCcusage(req, res), res);
|
|
3055
3059
|
if (req.method === "GET" && url.pathname === "/api/claude-accounts") return guard(handleClaudeAccounts(req, res), res);
|
|
@@ -3086,6 +3090,8 @@ export async function startServer({ port = 4317, host = "127.0.0.1", persist = n
|
|
|
3086
3090
|
await tryListen(server, candidate, host);
|
|
3087
3091
|
// Codex has no working hooks on Windows — tail its rollout files instead.
|
|
3088
3092
|
if (codex) startCodexWatcher(workspace);
|
|
3093
|
+
// Both timers are unref'd, so this never holds the process open.
|
|
3094
|
+
startSystemMetrics();
|
|
3089
3095
|
// Auto-switch resumes only if the user previously turned it on; the
|
|
3090
3096
|
// module reads its own persisted flag and does nothing otherwise.
|
|
3091
3097
|
cswapAutoModule().then(m => m.initCswapAuto()).catch(() => {});
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
// Machine-wide CPU and memory, sampled on our own timer so every open tab reads
|
|
2
|
+
// the same numbers.
|
|
3
|
+
//
|
|
4
|
+
// WHY THE SERVER SAMPLES INSTEAD OF ANSWERING ON DEMAND. CPU utilisation is not
|
|
5
|
+
// a value you can read; it is a ratio between two readings. `os.cpus()` returns
|
|
6
|
+
// cumulative tick counters, so a percentage only exists relative to a previous
|
|
7
|
+
// sample. If the sample were taken when a request arrived, two browser tabs
|
|
8
|
+
// polling half a second apart would compute their deltas from different
|
|
9
|
+
// baselines and print different percentages for the same machine. One timer in
|
|
10
|
+
// one process is the only arrangement where that cannot happen — and it is what
|
|
11
|
+
// lets `/api/system` hand back a real 60-second history rather than whatever a
|
|
12
|
+
// single tab has managed to collect since it was opened.
|
|
13
|
+
//
|
|
14
|
+
// WHY THIS NEVER TOUCHES pushEvent. Every event that goes through the deck's
|
|
15
|
+
// stream is persisted to events.jsonl and held in the 2000-entry ring buffer. A
|
|
16
|
+
// three-second sampler would put 1200 entries an hour into both, evicting real
|
|
17
|
+
// tool calls from the replay a reconnecting tab receives, and making an ambient
|
|
18
|
+
// readout the loudest producer in the application. So this is a plain poll
|
|
19
|
+
// endpoint, exactly like /api/quota and /api/codex-usage already are.
|
|
20
|
+
import { spawn } from "node:child_process";
|
|
21
|
+
import { readFile } from "node:fs/promises";
|
|
22
|
+
import os from "node:os";
|
|
23
|
+
|
|
24
|
+
/** CPU is the metric with spikes, so it is sampled often enough to catch one. */
|
|
25
|
+
const CPU_INTERVAL_MS = 3_000;
|
|
26
|
+
/** Memory moves on the scale of minutes. Sampling it at the CPU cadence would
|
|
27
|
+
* print the same number twenty times and, on macOS, cost a subprocess to do
|
|
28
|
+
* it — see readMemory. */
|
|
29
|
+
const MEM_INTERVAL_MS = 30_000;
|
|
30
|
+
/** 20 samples x 3s = the 60 seconds the sparkline draws. */
|
|
31
|
+
const HISTORY = 20;
|
|
32
|
+
|
|
33
|
+
let cpuTimer = null;
|
|
34
|
+
let memTimer = null;
|
|
35
|
+
let prevTicks = null;
|
|
36
|
+
/** Newest last. Seeded empty; the first tick produces no percentage because a
|
|
37
|
+
* delta needs two readings. */
|
|
38
|
+
const cpuHistory = [];
|
|
39
|
+
let memory = null;
|
|
40
|
+
let memInFlight = false;
|
|
41
|
+
|
|
42
|
+
/** Total and idle jiffies across every core, as one pair. */
|
|
43
|
+
function readTicks() {
|
|
44
|
+
let idle = 0;
|
|
45
|
+
let total = 0;
|
|
46
|
+
for (const cpu of os.cpus()) {
|
|
47
|
+
for (const [kind, ms] of Object.entries(cpu.times)) {
|
|
48
|
+
total += ms;
|
|
49
|
+
if (kind === "idle") idle += ms;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return { idle, total };
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Busy percentage across all cores since the previous reading, 0-100.
|
|
57
|
+
*
|
|
58
|
+
* Aggregate rather than per-core, and normalised rather than macOS's
|
|
59
|
+
* 0-to-cores*100 convention, because it has to mean the same thing on all three
|
|
60
|
+
* platforms and because a bar needs an end. The cost is that it saturates: a
|
|
61
|
+
* machine at load 12 and a machine at load 18 both read 100. `loadavg` is what
|
|
62
|
+
* carries that difference, which is why it rides along below on the platforms
|
|
63
|
+
* that report it.
|
|
64
|
+
*/
|
|
65
|
+
function cpuPercent() {
|
|
66
|
+
const now = readTicks();
|
|
67
|
+
if (!prevTicks) { prevTicks = now; return null; }
|
|
68
|
+
const dTotal = now.total - prevTicks.total;
|
|
69
|
+
const dIdle = now.idle - prevTicks.idle;
|
|
70
|
+
prevTicks = now;
|
|
71
|
+
// A tick counter that did not move says nothing; it does not say "idle".
|
|
72
|
+
if (dTotal <= 0) return null;
|
|
73
|
+
const pct = (1 - dIdle / dTotal) * 100;
|
|
74
|
+
return Math.max(0, Math.min(100, Math.round(pct * 10) / 10));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** Run a command and resolve its stdout, or null. Never rejects, never inherits
|
|
78
|
+
* a shell, and is killed rather than allowed to hang the sampler. */
|
|
79
|
+
function run(file, args, timeoutMs = 2_000) {
|
|
80
|
+
return new Promise(resolve => {
|
|
81
|
+
let child;
|
|
82
|
+
try { child = spawn(file, args, { windowsHide: true }); }
|
|
83
|
+
catch { return resolve(null); }
|
|
84
|
+
let out = "";
|
|
85
|
+
const timer = setTimeout(() => { try { child.kill(); } catch {} resolve(null); }, timeoutMs);
|
|
86
|
+
child.stdout?.on("data", d => { out += d; });
|
|
87
|
+
child.on("error", () => { clearTimeout(timer); resolve(null); });
|
|
88
|
+
child.on("close", code => { clearTimeout(timer); resolve(code === 0 ? out : null); });
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Bytes of memory a new process could actually get, per platform.
|
|
94
|
+
*
|
|
95
|
+
* `os.freemem()` is the obvious call and it is the wrong one on two of the three
|
|
96
|
+
* platforms, because "free" and "available" are different questions. Pages
|
|
97
|
+
* holding cached files or inactive anonymous memory are not free, but the kernel
|
|
98
|
+
* will hand them over the moment something asks. Reporting them as used is what
|
|
99
|
+
* makes the naive `(total - free) / total` read 99.5% on an idle 32 GB Mac — a
|
|
100
|
+
* number that would send the reader straight to Activity Monitor, which is the
|
|
101
|
+
* one outcome this readout exists to prevent.
|
|
102
|
+
*
|
|
103
|
+
* linux /proc/meminfo MemAvailable — the kernel's own answer, a file read
|
|
104
|
+
* win32 os.freemem() already reports available physical memory
|
|
105
|
+
* darwin vm_stat, because nothing in Node exposes the page classes
|
|
106
|
+
*
|
|
107
|
+
* Only darwin costs a subprocess, and only at MEM_INTERVAL_MS.
|
|
108
|
+
*/
|
|
109
|
+
/**
|
|
110
|
+
* Available bytes out of `/proc/meminfo` text, or null when the field is absent.
|
|
111
|
+
*
|
|
112
|
+
* Pure and exported for the same reason codexHome() takes a platform: a Linux
|
|
113
|
+
* answer has to be checkable from a Mac, and the only alternative is trusting
|
|
114
|
+
* that a regex nobody has run is right.
|
|
115
|
+
*/
|
|
116
|
+
export function availableFromMeminfo(text) {
|
|
117
|
+
const m = /^MemAvailable:\s+(\d+)\s*kB/m.exec(String(text ?? ""));
|
|
118
|
+
return m ? Number(m[1]) * 1024 : null;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Available bytes out of `vm_stat` output, or null when it does not parse.
|
|
123
|
+
*
|
|
124
|
+
* Everything the kernel can hand over without swapping: genuinely free pages,
|
|
125
|
+
* read-ahead it can drop, inactive anonymous pages, and purgeable caches. This
|
|
126
|
+
* is the number `os.freemem()` is missing — it reports only the first of the
|
|
127
|
+
* four, which is why the naive formula reads ~99% on an idle 32 GB Mac.
|
|
128
|
+
*/
|
|
129
|
+
export function availableFromVmStat(text, total) {
|
|
130
|
+
const out = String(text ?? "");
|
|
131
|
+
const pageSize = Number(/page size of (\d+) bytes/.exec(out)?.[1]) || 4096;
|
|
132
|
+
const pages = name => {
|
|
133
|
+
const m = new RegExp(`^Pages ${name}:\\s+(\\d+)`, "m").exec(out);
|
|
134
|
+
return m ? Number(m[1]) : 0;
|
|
135
|
+
};
|
|
136
|
+
const reclaimable = pages("free") + pages("speculative")
|
|
137
|
+
+ pages("inactive") + pages("purgeable");
|
|
138
|
+
if (reclaimable <= 0) return null;
|
|
139
|
+
const avail = reclaimable * pageSize;
|
|
140
|
+
return total != null && avail > total ? null : avail;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
async function readAvailable(platform = process.platform) {
|
|
144
|
+
const total = os.totalmem();
|
|
145
|
+
|
|
146
|
+
if (platform === "linux") {
|
|
147
|
+
try {
|
|
148
|
+
const parsed = availableFromMeminfo(await readFile("/proc/meminfo", "utf8"));
|
|
149
|
+
if (parsed != null) return parsed;
|
|
150
|
+
} catch { /* fall through to freemem */ }
|
|
151
|
+
return os.freemem();
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (platform === "darwin") {
|
|
155
|
+
const out = await run("vm_stat", []);
|
|
156
|
+
const parsed = out ? availableFromVmStat(out, total) : null;
|
|
157
|
+
return parsed ?? os.freemem();
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return os.freemem();
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async function sampleMemory() {
|
|
164
|
+
if (memInFlight) return;
|
|
165
|
+
memInFlight = true;
|
|
166
|
+
try {
|
|
167
|
+
const total = os.totalmem();
|
|
168
|
+
const available = await readAvailable();
|
|
169
|
+
memory = {
|
|
170
|
+
total,
|
|
171
|
+
available,
|
|
172
|
+
usedPct: Math.max(0, Math.min(100, Math.round(((total - available) / total) * 1000) / 10)),
|
|
173
|
+
};
|
|
174
|
+
} catch { /* keep the previous reading rather than blanking the meter */ }
|
|
175
|
+
finally { memInFlight = false; }
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function sampleCpu() {
|
|
179
|
+
const pct = cpuPercent();
|
|
180
|
+
if (pct == null) return;
|
|
181
|
+
cpuHistory.push(pct);
|
|
182
|
+
while (cpuHistory.length > HISTORY) cpuHistory.shift();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Begin sampling. Idempotent, and both timers are unref'd so this can never be
|
|
187
|
+
* the reason the process stays alive.
|
|
188
|
+
*/
|
|
189
|
+
export function startSystemMetrics() {
|
|
190
|
+
if (cpuTimer) return;
|
|
191
|
+
prevTicks = readTicks(); // baseline, so the first tick has a delta
|
|
192
|
+
sampleMemory();
|
|
193
|
+
cpuTimer = setInterval(sampleCpu, CPU_INTERVAL_MS);
|
|
194
|
+
memTimer = setInterval(sampleMemory, MEM_INTERVAL_MS);
|
|
195
|
+
cpuTimer.unref?.();
|
|
196
|
+
memTimer.unref?.();
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export function stopSystemMetrics() {
|
|
200
|
+
if (cpuTimer) clearInterval(cpuTimer);
|
|
201
|
+
if (memTimer) clearInterval(memTimer);
|
|
202
|
+
cpuTimer = memTimer = null;
|
|
203
|
+
prevTicks = null;
|
|
204
|
+
cpuHistory.length = 0;
|
|
205
|
+
memory = null;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* What /api/system answers.
|
|
210
|
+
*
|
|
211
|
+
* `cpu` is null until two samples exist — the meter draws its track and no fill
|
|
212
|
+
* rather than printing a zero it has not measured. `loadavg` is omitted on
|
|
213
|
+
* Windows, where the API returns [0, 0, 0]: three zeros are not a reading, and
|
|
214
|
+
* showing them as one would be the same lie in a different place.
|
|
215
|
+
*/
|
|
216
|
+
export function systemSnapshot() {
|
|
217
|
+
const cpu = cpuHistory.length ? cpuHistory[cpuHistory.length - 1] : null;
|
|
218
|
+
const load = os.loadavg();
|
|
219
|
+
const hasLoad = process.platform !== "win32" && load.some(n => n > 0);
|
|
220
|
+
return {
|
|
221
|
+
ok: true,
|
|
222
|
+
cpu,
|
|
223
|
+
cpuHistory: [...cpuHistory],
|
|
224
|
+
cores: os.cpus().length,
|
|
225
|
+
memory,
|
|
226
|
+
loadavg: hasLoad ? load.map(n => Math.round(n * 100) / 100) : null,
|
|
227
|
+
intervalMs: CPU_INTERVAL_MS,
|
|
228
|
+
sampledAt: Date.now(),
|
|
229
|
+
};
|
|
230
|
+
}
|