Files
clawmates/Agent dashboard package/Clawmates Agent Command Center.dc.html
T
Omar SobhandClaude Opus 4.8 11a1f22daa
ci / gates (push) Failing after 13s
ci / rust (push) Has been skipped
ci / sandbox-k8s (push) Has been skipped
ci / frontend (push) Has been skipped
ci / e2e (push) Has been skipped
Agents page: reorganize into the Agent Command Center (per-agent live metrics)
Replace the single centered "anatomy profile" + resizable chat split with an
operator command center: compact 62px identity strip → 5-tile per-agent metrics
band → three independently-scrolling LIVE · BRAIN · SURFACE columns. Chat moves to
the computer's Chat app; the right computer pullout (DevicePanel) is untouched.

- backend: cm-api/routes/world.rs emits per-agent `telemetry{agentId,tokensPerMin,
  costPerHr,loops,doorsPending}` in the SSE loop, from 4 batched GROUP BY queries
  (usage_events tokens/min + credits/hr, active routines, pending approvals) — all
  real, no migration. taxonomy `telemetry` gains optional agentId; stateKey now
  keys it per-agent so slices don't clobber.
- frontend: new ClawCommandCenter + anatomy-cards (shared cards extracted from
  Dashboard); useAgentTelemetry(agentId) feeds the metric band (Doors amber>0/
  green=0); LIVE column streams the agent's task.update / reasoning.delta /
  tool.call (replaces the mocked VitalsCard heatmap with a live activity chart).
- Dashboard: left region → full-height ClawCommandCenter; chat launcher opens the
  computer Chat app; removed the dead anatomy cluster + unused imports.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
2026-06-26 11:34:12 -07:00

593 lines
52 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="./support.js"></script>
</head>
<body>
<x-dc>
<helmet>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; background: #08080a; }
body { font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; }
@keyframes cm-blink { 0%,100% { opacity: 1; } 50% { opacity: .25; } }
@keyframes cm-halo { 0% { transform: scale(.7); opacity: .5; } 100% { transform: scale(1.9); opacity: 0; } }
@keyframes cm-type { 0%,100% { opacity: 1; } 50% { opacity: 0; } }
@keyframes cm-bar { 0%,100% { transform: scaleY(.4); } 50% { transform: scaleY(1); } }
@keyframes cm-fade { from { opacity: 0; transform: translateY(4px); } to { opacity: 1; transform: none; } }
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-thumb { background: rgba(255,255,255,.09); border-radius: 4px; }
::-webkit-scrollbar-track { background: transparent; }
</style>
</helmet>
<div style="width:100%; height:100vh; min-height:680px; background:#08080a; display:flex; flex-direction:column; color:#f3f3f5; overflow:hidden;">
<!-- TOP BAR -->
<div style="height:54px; flex:none; display:flex; align-items:center; gap:14px; padding:0 18px; border-bottom:1px solid rgba(255,255,255,.06); background:linear-gradient(180deg,#0d0d10,#0a0a0c);">
<div style="display:flex; align-items:center; gap:10px;">
<svg width="22" height="22" viewBox="0 0 22 22" fill="none">
<path d="M11 3 L18.5 17 L3.5 17 Z" stroke="#ff6f61" stroke-width="1.3" stroke-linejoin="round" opacity="0.55"></path>
<circle cx="11" cy="3.5" r="2.4" fill="#ff6f61"></circle><circle cx="18" cy="17" r="2.4" fill="#ff6f61"></circle><circle cx="4" cy="17" r="2.4" fill="#ff6f61"></circle>
</svg>
<span style="font-size:15px; font-weight:700; letter-spacing:-.01em;">Clawmates</span>
</div>
<div style="width:1px; height:22px; background:rgba(255,255,255,.08);"></div>
<div style="display:flex; align-items:center; gap:8px; font-family:'JetBrains Mono',monospace; font-size:12px;">
<span style="color:#6a6a72;">Large World</span>
<span style="color:#3a3a40;">/</span>
<span style="color:#9a9aa2;">Agents</span>
<span style="color:#3a3a40;">/</span>
<span style="color:#fff; background:rgba(255,111,97,.14); border:1px solid rgba(255,111,97,.3); padding:3px 8px; border-radius:6px;">{{ selName }}</span>
</div>
<div style="flex:1;"></div>
<div style="display:flex; align-items:center; gap:7px; font-family:'JetBrains Mono',monospace; font-size:11px; color:#5ec8d8; padding:5px 10px; border:1px solid rgba(94,200,216,.25); border-radius:7px; background:rgba(94,200,216,.06);">
<span style="width:7px; height:7px; border-radius:50%; background:#5ec8d8; {{ blinkAnim }}"></span>{{ selStatusLabel }}
</div>
<div style="display:flex; align-items:center; gap:5px; font-family:'JetBrains Mono',monospace; font-size:11px; color:#8a8a92;">
<span style="color:#e8b465;"></span> {{ selTok }} tok/min
</div>
<div style="width:32px; height:32px; border-radius:8px; background:linear-gradient(135deg,#ff8a7a,#ff5f57); display:flex; align-items:center; justify-content:center; font-size:13px; font-weight:700; color:#2a0d0a;">O</div>
</div>
<!-- BODY -->
<div style="flex:1; display:flex; min-height:0;">
<!-- ICON RAIL -->
<div style="width:54px; flex:none; border-right:1px solid rgba(255,255,255,.06); background:#0a0a0c; display:flex; flex-direction:column; align-items:center; padding:12px 0; gap:6px;">
<div style="width:42px; height:46px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:4px; border-radius:9px; color:#5a5a62; cursor:pointer;">
<svg width="19" height="19" viewBox="0 0 20 20"><circle cx="10" cy="10" r="7.5" stroke="currentColor" stroke-width="1.4" fill="none"></circle><circle cx="10" cy="10" r="2.4" fill="currentColor"></circle></svg>
<span style="font-family:'JetBrains Mono',monospace; font-size:7px; letter-spacing:.05em;">WORLD</span>
</div>
<div style="position:relative; width:42px; height:46px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:4px; border-radius:9px; color:#ff6f61; background:rgba(255,111,97,.1); cursor:pointer;">
<span style="position:absolute; left:0; top:7px; bottom:7px; width:3px; border-radius:0 3px 3px 0; background:#ff6f61;"></span>
<svg width="19" height="19" viewBox="0 0 20 20"><rect x="4" y="4" width="12" height="12" rx="3.5" stroke="currentColor" stroke-width="1.4" fill="none"></rect><circle cx="10" cy="10" r="2.2" fill="currentColor"></circle></svg>
<span style="font-family:'JetBrains Mono',monospace; font-size:7px; letter-spacing:.05em;">AGENT</span>
</div>
<div style="width:42px; height:46px; display:flex; flex-direction:column; align-items:center; justify-content:center; gap:4px; border-radius:9px; color:#5a5a62; cursor:pointer;">
<svg width="19" height="19" viewBox="0 0 20 20"><rect x="3.5" y="4" width="13" height="5" rx="1.4" stroke="currentColor" stroke-width="1.3" fill="none"></rect><rect x="3.5" y="11" width="13" height="5" rx="1.4" stroke="currentColor" stroke-width="1.3" fill="none"></rect></svg>
<span style="font-family:'JetBrains Mono',monospace; font-size:7px; letter-spacing:.05em;">INFRA</span>
</div>
<div style="flex:1;"></div>
<div style="width:30px; height:30px; border-radius:8px; border:1px dashed rgba(255,255,255,.16); display:flex; align-items:center; justify-content:center; color:#ff6f61; font-size:18px; font-weight:300; cursor:pointer;">+</div>
</div>
<!-- AGENT LIST -->
<div style="width:222px; flex:none; border-right:1px solid rgba(255,255,255,.06); background:#0b0b0e; display:flex; flex-direction:column; min-height:0;">
<div style="padding:14px 14px 10px;">
<div style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.12em; color:#5a5a62;">2 AGENTS · LIVE</div>
<div style="font-size:17px; font-weight:700; margin-top:3px;">Agents</div>
</div>
<div style="flex:1; overflow-y:auto; padding:6px;">
<div style="display:flex; flex-direction:column; gap:3px;">
<sc-for list="{{ agents }}" as="a" hint-placeholder-count="2">
<div style="display:flex; align-items:flex-start; gap:10px; padding:9px 10px; border-radius:10px; cursor:pointer; position:relative; background:{{ a.rowBg }}; border:1px solid {{ a.rowBorder }};" onClick="{{ a.onSelect }}">
<sc-if value="{{ a.selected }}" hint-placeholder-val="{{ true }}"><span style="position:absolute; left:0; top:9px; bottom:9px; width:3px; border-radius:0 3px 3px 0; background:#ff6f61;"></span></sc-if>
<div style="position:relative; width:32px; height:32px; flex:none;">
<div style="width:32px; height:32px; border-radius:9px; background:{{ a.grad }}; display:flex; align-items:center; justify-content:center; font-size:13px; font-weight:700; color:{{ a.ink }};">{{ a.initial }}</div>
<span style="position:absolute; right:-2px; bottom:-2px; width:10px; height:10px; border-radius:50%; background:{{ a.statusColor }}; border:2px solid #0b0b0e;"></span>
</div>
<div style="flex:1; min-width:0;">
<div style="font-size:13px; font-weight:600; color:{{ a.labelColor }};">{{ a.name }}</div>
<div style="font-family:'JetBrains Mono',monospace; font-size:9px; color:{{ a.roleColor }};">{{ a.role }}</div>
<div style="font-family:'JetBrains Mono',monospace; font-size:9px; color:{{ a.statusColor }}; margin-top:4px; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;">{{ a.action }}</div>
</div>
</div>
</sc-for>
</div>
</div>
<div style="flex:none; padding:10px 12px; border-top:1px solid rgba(255,255,255,.06);">
<div style="display:flex; align-items:center; justify-content:center; gap:7px; height:32px; border-radius:8px; border:1px solid rgba(94,200,216,.3); color:#5ec8d8; font-size:12px; font-weight:600; cursor:pointer;">⊕ Add to team</div>
</div>
</div>
<!-- COMMAND CENTER -->
<div data-screen-label="Agent Command Center" style="flex:1; min-width:0; display:flex; flex-direction:column; min-height:0; background:radial-gradient(130% 100% at 30% 0%, #100e13 0%, #08080a 60%);">
<!-- IDENTITY HEADER STRIP -->
<div style="flex:none; display:flex; align-items:center; gap:16px; padding:16px 20px 14px; border-bottom:1px solid rgba(255,255,255,.06);">
<div style="position:relative; width:62px; height:62px; flex:none;">
<div style="position:absolute; inset:-5px; border-radius:50%; border:1.5px solid rgba(255,111,97,.4);"></div>
<div style="position:absolute; inset:0; border-radius:50%; background:rgba(255,111,97,.3); {{ haloAnim }}"></div>
<div style="position:relative; width:62px; height:62px; border-radius:50%; background:{{ selGrad }}; display:flex; align-items:center; justify-content:center; font-size:24px; font-weight:700; color:{{ selInk }}; box-shadow:0 0 30px rgba(255,111,97,.4);">{{ selInitial }}</div>
</div>
<div style="min-width:0;">
<div style="font-size:24px; font-weight:700; letter-spacing:-.02em; line-height:1.1;">{{ selName }}</div>
<div style="font-family:'JetBrains Mono',monospace; font-size:11px; color:#6a6a72; margin-top:3px;">{{ selRole }} · {{ selSpec }}</div>
</div>
<div style="flex:1;"></div>
<div style="display:flex; align-items:center; gap:8px; padding:7px 11px; border-radius:9px; background:#101014; border:1px solid rgba(255,255,255,.08);">
<span style="width:7px; height:7px; border-radius:50%; background:#ff6f61;"></span>
<span style="font-family:'JetBrains Mono',monospace; font-size:11px; color:#cfcfd5;">{{ selModel }}</span>
</div>
<div style="display:flex; align-items:center; gap:7px; padding:8px 13px; border-radius:9px; background:linear-gradient(135deg,#ff8a7a,#ff5f57); color:#2a0d0a; font-size:12px; font-weight:700; cursor:pointer;">Edit brain →</div>
<div style="width:34px; height:34px; border-radius:9px; border:1px solid rgba(255,255,255,.1); display:flex; align-items:center; justify-content:center; color:#9a9aa2; cursor:pointer;"><svg width="16" height="16" viewBox="0 0 18 18"><circle cx="9" cy="9" r="2.4" fill="currentColor"></circle><path d="M9 1.5v2.2M9 14.3v2.2M1.5 9h2.2M14.3 9h2.2M3.6 3.6l1.6 1.6M12.8 12.8l1.6 1.6M14.4 3.6l-1.6 1.6M5.2 12.8l-1.6 1.6" stroke="currentColor" stroke-width="1.4"></path></svg></div>
</div>
<!-- METRICS BAND -->
<div style="flex:none; display:flex; gap:12px; padding:14px 20px;">
<div style="flex:1.4; border-radius:11px; background:#0d0d10; border:1px solid rgba(94,200,216,.22); padding:11px 14px; display:flex; align-items:center; gap:12px;">
<div style="min-width:0;">
<div style="font-family:'JetBrains Mono',monospace; font-size:9px; letter-spacing:.1em; color:#6a6a72;">THROUGHPUT</div>
<div style="display:flex; align-items:baseline; gap:5px; margin-top:4px;"><span style="font-size:22px; font-weight:700; color:#5ec8d8; letter-spacing:-.01em;">{{ selTok }}</span><span style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#6a6a72;">tok/min</span></div>
</div>
<span style="flex:1;"></span>
<span style="display:flex; align-items:flex-end; gap:2px; height:30px;">
<span style="width:3px; background:#2c5a64; height:40%; border-radius:1px;"></span>
<span style="width:3px; background:#3a7e8c; height:68%; border-radius:1px;"></span>
<span style="width:3px; background:#4aa3b8; height:52%; border-radius:1px; transform-origin:bottom; {{ barAnim }}"></span>
<span style="width:3px; background:#5ec8d8; height:88%; border-radius:1px; transform-origin:bottom; {{ barAnim2 }}"></span>
<span style="width:3px; background:#4aa3b8; height:64%; border-radius:1px;"></span>
<span style="width:3px; background:#3a7e8c; height:46%; border-radius:1px;"></span>
<span style="width:3px; background:#5ec8d8; height:76%; border-radius:1px;"></span>
</span>
</div>
<div style="flex:1; border-radius:11px; background:#0d0d10; border:1px solid rgba(255,255,255,.06); padding:11px 14px;">
<div style="font-family:'JetBrains Mono',monospace; font-size:9px; letter-spacing:.1em; color:#6a6a72;">SPEND</div>
<div style="display:flex; align-items:baseline; gap:5px; margin-top:4px;"><span style="font-size:22px; font-weight:700; color:#e8b465; letter-spacing:-.01em;">{{ selSpend }}</span><span style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#6a6a72;">/hr</span></div>
</div>
<div style="flex:1; border-radius:11px; background:#0d0d10; border:1px solid rgba(255,255,255,.06); padding:11px 14px;">
<div style="font-family:'JetBrains Mono',monospace; font-size:9px; letter-spacing:.1em; color:#6a6a72;">LOOPS</div>
<div style="display:flex; align-items:baseline; gap:5px; margin-top:4px;"><span style="font-size:22px; font-weight:700; color:#5fd08a; letter-spacing:-.01em;">{{ selLoops }}</span><span style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#6a6a72;">running</span></div>
</div>
<div style="flex:1; border-radius:11px; background:#0d0d10; border:1px solid rgba(255,255,255,.06); padding:11px 14px;">
<div style="font-family:'JetBrains Mono',monospace; font-size:9px; letter-spacing:.1em; color:#6a6a72;">MEMORY</div>
<div style="display:flex; align-items:baseline; gap:5px; margin-top:4px;"><span style="font-size:22px; font-weight:700; color:#cfcfd5; letter-spacing:-.01em;">{{ selMem }}</span><span style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#6a6a72;">notes</span></div>
</div>
<div style="flex:1; border-radius:11px; background:#0d0d10; border:1px solid {{ doorsBorder }}; padding:11px 14px;">
<div style="font-family:'JetBrains Mono',monospace; font-size:9px; letter-spacing:.1em; color:{{ doorsLabelColor }};">DOORS</div>
<div style="display:flex; align-items:baseline; gap:5px; margin-top:4px;"><span style="font-size:22px; font-weight:700; color:{{ doorsValColor }}; letter-spacing:-.01em;">{{ doorsLive }}</span><span style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#6a6a72;">pending</span></div>
</div>
</div>
<!-- THREE COLUMNS -->
<div style="flex:1; min-height:0; display:flex; gap:14px; padding:0 20px 16px;">
<!-- LIVE COLUMN -->
<div style="flex:1.15; min-width:0; display:flex; flex-direction:column; gap:12px; overflow-y:auto;">
<div style="flex:none; border-radius:13px; border:1px solid rgba(94,200,216,.24); background:linear-gradient(180deg,#0c1416,#0b0e0f); overflow:hidden;">
<div style="display:flex; align-items:center; gap:8px; padding:11px 14px; border-bottom:1px solid rgba(255,255,255,.05);">
<span style="width:7px; height:7px; border-radius:50%; background:#5ec8d8; {{ blinkAnim }}"></span>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.12em; color:#5ec8d8;">WORKING ON NOW</span>
<span style="flex:1;"></span>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#6a6a72;">{{ taskElapsed }}</span>
</div>
<div style="padding:13px 14px;">
<div style="font-size:15px; font-weight:600; margin-bottom:8px; line-height:1.35;">{{ taskTitle }} <span style="font-family:'JetBrains Mono',monospace; color:#ff8a7a;">{{ taskCode }}</span></div>
<div style="display:flex; flex-direction:column; gap:5px; font-family:'JetBrains Mono',monospace; font-size:11px; line-height:1.6;">
<sc-for list="{{ taskSteps }}" as="st" hint-placeholder-count="3">
<div style="color:#7a7a82;"><span style="color:{{ st.iconColor }};">{{ st.icon }}</span> {{ st.text }} <span style="color:#5a5a62;">{{ st.meta }}</span><sc-if value="{{ st.caret }}" hint-placeholder-val="{{ false }}"><span style="display:inline-block; width:6px; height:12px; background:#5ec8d8; margin-left:2px; vertical-align:-2px; {{ caretAnim }}"></span></sc-if></div>
</sc-for>
</div>
</div>
</div>
<div style="flex:1; min-height:160px; border-radius:13px; border:1px solid rgba(255,255,255,.08); background:#070708; overflow:hidden; display:flex; flex-direction:column;">
<div style="flex:none; display:flex; align-items:center; gap:8px; padding:10px 13px; border-bottom:1px solid rgba(255,255,255,.06);">
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.12em; color:#5fd08a;">▌ REASONING STREAM</span>
<span style="flex:1;"></span>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#5a5a62;">{{ selModelShort }} · {{ reasoningTime }}</span>
</div>
<div style="flex:1; min-height:0; overflow-y:auto; padding:12px 14px; font-family:'JetBrains Mono',monospace; font-size:11px; line-height:1.7;">
<sc-for list="{{ reasoning }}" as="r" hint-placeholder-count="4">
<div style="color:#9a9aa2; margin-bottom:7px;"><span style="color:{{ r.tagColor }};">{{ r.tag }}</span> {{ r.text }}<sc-if value="{{ r.caret }}" hint-placeholder-val="{{ false }}"><span style="display:inline-block; width:6px; height:12px; background:#5fd08a; margin-left:3px; vertical-align:-2px; {{ caretAnim }}"></span></sc-if></div>
</sc-for>
</div>
</div>
<div style="flex:none; border-radius:13px; border:1px solid rgba(255,255,255,.07); background:#0d0d10; padding:13px 14px;">
<div style="display:flex; align-items:center; gap:8px; margin-bottom:11px;">
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.12em; color:#5fd08a;">● ACTIVITY · LIVE</span>
<span style="flex:1;"></span>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#6a6a72;">{{ selCommits }} commits · {{ selHot }} hot</span>
</div>
<div style="display:flex; align-items:flex-end; gap:3px; height:46px;">
<span style="flex:1; background:#1e3a2a; border-radius:2px; height:30%;"></span>
<span style="flex:1; background:#2e6e44; border-radius:2px; height:55%;"></span>
<span style="flex:1; background:#3a9457; border-radius:2px; height:42%;"></span>
<span style="flex:1; background:#46c46a; border-radius:2px; height:78%;"></span>
<span style="flex:1; background:#e8b465; border-radius:2px; height:62%; transform-origin:bottom; {{ barAnim }}"></span>
<span style="flex:1; background:#2e6e44; border-radius:2px; height:48%;"></span>
<span style="flex:1; background:#3a9457; border-radius:2px; height:70%;"></span>
<span style="flex:1; background:#46c46a; border-radius:2px; height:90%; transform-origin:bottom; {{ barAnim2 }}"></span>
<span style="flex:1; background:#2e6e44; border-radius:2px; height:36%;"></span>
<span style="flex:1; background:#3a9457; border-radius:2px; height:58%;"></span>
<span style="flex:1; background:#1e3a2a; border-radius:2px; height:44%;"></span>
<span style="flex:1; background:#46c46a; border-radius:2px; height:66%;"></span>
</div>
</div>
</div>
<!-- BRAIN COLUMN -->
<div style="flex:1; min-width:0; display:flex; flex-direction:column; gap:12px; overflow-y:auto;">
<div style="flex:none; border-radius:13px; background:#0d0d10; border:1px solid rgba(255,111,97,.22); overflow:hidden;">
<div style="display:flex; align-items:center; gap:8px; padding:12px 13px; cursor:pointer;" onClick="{{ togglePrompt }}">
<span style="width:18px; height:18px; border-radius:5px; background:rgba(255,111,97,.16); display:flex; align-items:center; justify-content:center;"><svg width="11" height="11" viewBox="0 0 16 16"><path d="M4 2h6l2 2v10H4z" fill="none" stroke="#ff6f61" stroke-width="1.3" stroke-linejoin="round"></path><path d="M6 6h4M6 9h4" stroke="#ff6f61" stroke-width="1.2"></path></svg></span>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.08em; color:#ff8a7a;">SYSTEM PROMPT</span>
<span style="flex:1;"></span>
<span style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#5a5a62;">{{ promptChars }} ch</span>
<span style="font-family:'JetBrains Mono',monospace; font-size:11px; color:#ff8a7a;">{{ promptChevron }}</span>
</div>
<sc-if value="{{ promptOpen }}" hint-placeholder-val="{{ false }}">
<div style="padding:0 14px 13px; animation:cm-fade .2s ease;">
<div style="max-height:148px; overflow-y:auto; padding:11px 12px; border-radius:9px; background:#08080a; border:1px solid rgba(255,255,255,.06); font-family:'JetBrains Mono',monospace; font-size:11px; line-height:1.7; color:#9a9aa2; white-space:pre-wrap;">{{ promptText }}</div>
</div>
</sc-if>
</div>
<div style="flex:none; border-radius:13px; background:#0d0d10; border:1px solid rgba(201,138,240,.22); padding:12px 13px;">
<div style="display:flex; align-items:center; gap:8px; margin-bottom:10px;">
<span style="width:18px; height:18px; border-radius:5px; background:rgba(201,138,240,.16); display:flex; align-items:center; justify-content:center;"><svg width="11" height="11" viewBox="0 0 18 18"><circle cx="9" cy="6" r="3.4" fill="#c98af0"></circle><path d="M3 16c0-3.3 2.7-6 6-6s6 2.7 6 6" fill="#c98af0"></path></svg></span>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.08em; color:#c98af0;">PERSONALITY</span>
</div>
<div style="display:flex; flex-wrap:wrap; gap:5px;">
<sc-for list="{{ personality }}" as="p" hint-placeholder-count="3">
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#cfcfd5; padding:4px 9px; border-radius:6px; background:rgba(201,138,240,.1); border:1px solid rgba(201,138,240,.18);">{{ p }}</span>
</sc-for>
</div>
</div>
<div style="flex:none; border-radius:13px; background:#0d0d10; border:1px solid rgba(255,111,97,.18); padding:12px 13px;">
<div style="display:flex; align-items:center; gap:8px; margin-bottom:10px;">
<span style="width:18px; height:18px; border-radius:5px; background:rgba(255,111,97,.16); display:flex; align-items:center; justify-content:center;"><svg width="11" height="11" viewBox="0 0 18 18"><path d="M10 1 L3 10 H8 L7 17 L15 7 H9 Z" fill="#ff6f61"></path></svg></span>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.08em; color:#ff8a7a;">SKILLS</span>
<span style="flex:1;"></span>
<span style="font-family:'JetBrains Mono',monospace; font-size:9px; color:#5a5a62;">{{ skillsCount }}</span>
</div>
<div style="display:flex; flex-wrap:wrap; gap:5px;">
<sc-for list="{{ skills }}" as="sk" hint-placeholder-count="4">
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#cfcfd5; padding:4px 9px; border-radius:6px; background:rgba(255,255,255,.05);">{{ sk }}</span>
</sc-for>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#8a8a92; padding:4px 9px; border-radius:6px; background:rgba(255,255,255,.03);">{{ skillsMore }}</span>
</div>
</div>
<div style="flex:none; border-radius:13px; background:#0d0d10; border:1px solid rgba(232,196,106,.2); padding:12px 13px;">
<div style="display:flex; align-items:center; gap:8px; margin-bottom:10px;">
<span style="width:18px; height:18px; border-radius:5px; background:rgba(232,196,106,.16); display:flex; align-items:center; justify-content:center;"><svg width="11" height="11" viewBox="0 0 18 18"><rect x="3" y="3" width="12" height="12" rx="2.5" fill="none" stroke="#e8b465" stroke-width="1.5"></rect><rect x="6.5" y="6.5" width="5" height="5" rx="1" fill="#e8b465"></rect></svg></span>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.08em; color:#e8b465;">CAPABILITIES</span>
</div>
<div style="display:flex; flex-wrap:wrap; gap:5px;">
<sc-for list="{{ capabilities }}" as="c" hint-placeholder-count="3">
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#cfcfd5; padding:4px 9px; border-radius:6px; background:rgba(255,255,255,.05);">{{ c }}</span>
</sc-for>
</div>
</div>
</div>
<!-- SURFACE COLUMN -->
<div style="flex:1; min-width:0; display:flex; flex-direction:column; gap:12px; overflow-y:auto;">
<div style="flex:none; border-radius:13px; background:#0d0d10; border:1px solid rgba(94,200,216,.22); padding:12px 13px;">
<div style="display:flex; align-items:center; gap:8px; margin-bottom:10px;">
<span style="width:18px; height:18px; border-radius:5px; background:rgba(94,200,216,.16); display:flex; align-items:center; justify-content:center;"><svg width="11" height="11" viewBox="0 0 18 18"><path d="M4 3v12M4 4h8l-2 3 2 3H4" fill="none" stroke="#5ec8d8" stroke-width="1.5" stroke-linejoin="round"></path></svg></span>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.08em; color:#5ec8d8;">TOOLS · DOORS</span>
</div>
<div style="display:flex; flex-direction:column; gap:6px; font-family:'JetBrains Mono',monospace; font-size:11px;">
<sc-for list="{{ tools }}" as="t" hint-placeholder-count="4">
<div style="display:flex; align-items:center;"><span style="flex:1; color:{{ t.nameColor }};">{{ t.name }}</span><span style="color:{{ t.stateColor }};">{{ t.state }}</span></div>
</sc-for>
</div>
<sc-if value="{{ showDoor }}" hint-placeholder-val="{{ true }}">
<div style="margin-top:11px; border-radius:10px; border:1px solid rgba(232,196,106,.4); background:linear-gradient(180deg,#1a1408,#12100a); overflow:hidden; animation:cm-fade .2s ease;">
<div style="height:3px; background:linear-gradient(90deg,#e8b465,#ff6f61);"></div>
<div style="padding:11px 12px;">
<div style="display:flex; align-items:center; gap:7px; margin-bottom:8px;">
<span style="font-family:'JetBrains Mono',monospace; font-size:9px; letter-spacing:.1em; color:#e8b465;">§15 DOOR · APPROVAL</span>
</div>
<div style="font-size:13px; font-weight:600; margin-bottom:3px;">{{ doorTitle }}</div>
<div style="font-family:'JetBrains Mono',monospace; font-size:10px; color:#8a8a92; line-height:1.6; margin-bottom:11px;">{{ doorDetail }}</div>
<div style="display:flex; gap:7px;">
<div style="flex:1; display:flex; align-items:center; justify-content:center; height:31px; border-radius:8px; background:linear-gradient(135deg,#ffb27a,#e8b465); color:#2a1d05; font-size:12px; font-weight:700; cursor:pointer;" onClick="{{ approveDoor }}">Approve</div>
<div style="flex:1; display:flex; align-items:center; justify-content:center; height:31px; border-radius:8px; border:1px solid rgba(255,255,255,.14); color:#cfcfd5; font-size:12px; font-weight:600; cursor:pointer;">Review</div>
<div style="width:34px; display:flex; align-items:center; justify-content:center; height:31px; border-radius:8px; border:1px solid rgba(255,255,255,.1); color:#8a8a92; cursor:pointer;" onClick="{{ approveDoor }}"></div>
</div>
</div>
</div>
</sc-if>
<sc-if value="{{ doorClear }}" hint-placeholder-val="{{ false }}">
<div style="margin-top:11px; display:flex; align-items:center; gap:7px; padding:9px 11px; border-radius:9px; background:rgba(95,208,138,.07); border:1px solid rgba(95,208,138,.22); font-family:'JetBrains Mono',monospace; font-size:10px; color:#5fd08a;">✓ no doors awaiting approval</div>
</sc-if>
</div>
<div style="flex:none; border-radius:13px; background:#0d0d10; border:1px solid rgba(95,208,138,.2); padding:12px 13px;">
<div style="display:flex; align-items:center; gap:8px; margin-bottom:10px;">
<span style="width:18px; height:18px; border-radius:5px; background:rgba(95,208,138,.16); display:flex; align-items:center; justify-content:center;"><svg width="11" height="11" viewBox="0 0 18 18"><rect x="3" y="3" width="12" height="12" rx="2" fill="none" stroke="#5fd08a" stroke-width="1.6"></rect><path d="M6 7h6M6 11h4" stroke="#5fd08a" stroke-width="1.4"></path></svg></span>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.08em; color:#5fd08a;">MEMORY</span>
</div>
<div style="display:flex; flex-direction:column; gap:6px; font-family:'JetBrains Mono',monospace; font-size:11px; color:#9a9aa2;">
<sc-for list="{{ memory }}" as="m" hint-placeholder-count="3">
<div style="display:flex;"><span style="flex:1;">{{ m.k }}</span><span style="color:#cfcfd5;">{{ m.v }}</span></div>
</sc-for>
</div>
</div>
<div style="flex:none; border-radius:13px; background:#0d0d10; border:1px solid rgba(111,208,192,.2); padding:12px 13px;">
<div style="display:flex; align-items:center; gap:8px; margin-bottom:10px;">
<span style="width:18px; height:18px; border-radius:5px; background:rgba(111,208,192,.16); display:flex; align-items:center; justify-content:center;"><svg width="11" height="11" viewBox="0 0 18 18"><path d="M9 2l5 2v4c0 4-2.5 6.5-5 8-2.5-1.5-5-4-5-8V4z" fill="none" stroke="#6fd0c0" stroke-width="1.5" stroke-linejoin="round"></path></svg></span>
<span style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.08em; color:#6fd0c0;">SAFETY · §15</span>
</div>
<div style="display:flex; flex-direction:column; gap:6px; font-family:'JetBrains Mono',monospace; font-size:11px; color:#9a9aa2;">
<sc-for list="{{ safety }}" as="sf" hint-placeholder-count="3">
<div style="display:flex;"><span style="flex:1;">{{ sf.k }}</span><span style="color:{{ sf.color }};">{{ sf.v }}</span></div>
</sc-for>
</div>
</div>
</div>
</div>
</div>
<!-- COMPUTER PULLOUT PANEL -->
<sc-if value="{{ showComputer }}" hint-placeholder-val="{{ true }}">
<div style="width:344px; flex:none; border-left:1px solid rgba(255,255,255,.06); background:#0b0b0e; display:flex; flex-direction:column; min-height:0; animation:cm-fade .25s ease;">
<div style="flex:none; display:flex; align-items:center; gap:9px; padding:13px 14px 11px; border-bottom:1px solid rgba(255,255,255,.06);">
<span style="width:7px; height:7px; border-radius:50%; background:#ff6f61;"></span>
<span style="font-size:13px; font-weight:700;">{{ selName }}'s Computer</span>
<span style="flex:1;"></span>
<div style="display:flex; align-items:center; gap:8px; color:#5a5a62;">
<svg width="15" height="15" viewBox="0 0 18 18" style="cursor:pointer; color:#ff6f61;"><path d="M3 4a1.5 1.5 0 011.5-1.5h9A1.5 1.5 0 0115 4v6a1.5 1.5 0 01-1.5 1.5H7l-4 3.5V4z" fill="none" stroke="currentColor" stroke-width="1.3" stroke-linejoin="round"></path></svg>
<svg width="15" height="15" viewBox="0 0 18 18" style="cursor:pointer;"><rect x="2" y="3" width="14" height="9" rx="1.4" fill="none" stroke="currentColor" stroke-width="1.3"></rect><path d="M6 15h6" stroke="currentColor" stroke-width="1.3"></path></svg>
<svg width="15" height="15" viewBox="0 0 18 18" style="cursor:pointer;"><rect x="4" y="2.5" width="10" height="13" rx="1.6" fill="none" stroke="currentColor" stroke-width="1.3"></rect></svg>
<svg width="15" height="15" viewBox="0 0 18 18" style="cursor:pointer;"><rect x="5.5" y="2" width="7" height="14" rx="1.6" fill="none" stroke="currentColor" stroke-width="1.3"></rect><path d="M8 13.5h2" stroke="currentColor" stroke-width="1.3"></path></svg>
<span style="width:1px; height:14px; background:rgba(255,255,255,.1);"></span>
<svg width="14" height="14" viewBox="0 0 16 16" style="cursor:pointer;"><path d="M3.5 3.5l9 9M12.5 3.5l-9 9" stroke="currentColor" stroke-width="1.4"></path></svg>
</div>
</div>
<div style="flex:none; display:flex; align-items:center; gap:7px; padding:9px 16px 0; font-family:'JetBrains Mono',monospace; font-size:10px; color:#5ec8d8;">
<span style="width:6px; height:6px; border-radius:50%; background:#5ec8d8; {{ blinkAnim }}"></span>sandbox live · no network
</div>
<div style="flex:1; overflow-y:auto; padding:16px;">
<div style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.12em; color:#5a5a62; margin-bottom:13px;">APPS</div>
<div style="display:grid; grid-template-columns:repeat(4,1fr); gap:14px 6px; margin-bottom:22px;">
<div style="display:flex; flex-direction:column; align-items:center; gap:6px; cursor:pointer;"><div style="width:48px; height:48px; border-radius:13px; background:#fff; display:flex; align-items:center; justify-content:center; box-shadow:0 3px 10px rgba(0,0,0,.4);"><svg width="26" height="26" viewBox="0 0 26 26"><circle cx="13" cy="13" r="11" fill="#fff" stroke="#e0e0e0"></circle><circle cx="13" cy="13" r="4.4" fill="#4a90e2"></circle><path d="M13 8.6 H24" stroke="#ea4335" stroke-width="3.6"></path><path d="M9.2 11 L4 3.4" stroke="#34a853" stroke-width="3.6"></path><path d="M13 17.4 L7.5 22.5" stroke="#fbbc05" stroke-width="3.6"></path></svg></div><span style="font-size:10px; color:#b5b5bd;">Browser</span></div>
<div style="display:flex; flex-direction:column; align-items:center; gap:6px; cursor:pointer;"><div style="width:48px; height:48px; border-radius:13px; background:#fff; display:flex; align-items:center; justify-content:center; box-shadow:0 3px 10px rgba(0,0,0,.4);"><svg width="22" height="22" viewBox="0 0 22 22"><rect x="9" y="2" width="4" height="11" rx="2" fill="#36c5f0"></rect><rect x="9" y="13" width="4" height="7" rx="2" fill="#2eb67d"></rect><rect x="2" y="9" width="11" height="4" rx="2" fill="#ecb22e"></rect><rect x="9" y="9" width="11" height="4" rx="2" fill="#e01e5a"></rect></svg></div><span style="font-size:10px; color:#b5b5bd;">Slack</span></div>
<div style="display:flex; flex-direction:column; align-items:center; gap:6px; cursor:pointer;"><div style="width:48px; height:48px; border-radius:13px; background:#070708; border:1px solid rgba(255,255,255,.1); display:flex; align-items:center; justify-content:center;"><svg width="22" height="22" viewBox="0 0 22 22"><rect x="2" y="3" width="18" height="15" rx="2" fill="none" stroke="#5fd08a" stroke-width="1.4"></rect><path d="M5 8l3 2.5-3 2.5M10.5 14h5" stroke="#5fd08a" stroke-width="1.4" fill="none"></path></svg></div><span style="font-size:10px; color:#b5b5bd;">Terminal</span></div>
<div style="display:flex; flex-direction:column; align-items:center; gap:6px; cursor:pointer;"><div style="width:48px; height:48px; border-radius:13px; background:linear-gradient(135deg,#c98af0,#7a4ad8); display:flex; align-items:center; justify-content:center; box-shadow:0 3px 10px rgba(0,0,0,.4);"><svg width="22" height="22" viewBox="0 0 22 22"><path d="M11 2 L18 8 L13 20 L6 16 L4 8 Z" fill="#fff" opacity=".92"></path><path d="M11 2 L13 20 M4 8 L13 20" stroke="#c98af0" stroke-width="1" fill="none"></path></svg></div><span style="font-size:10px; color:#b5b5bd;">Obsidian</span></div>
<div style="display:flex; flex-direction:column; align-items:center; gap:6px; cursor:pointer;"><div style="width:48px; height:48px; border-radius:13px; background:#070708; border:1px solid rgba(255,255,255,.1); display:flex; align-items:center; justify-content:center;"><svg width="22" height="22" viewBox="0 0 22 22"><path d="M3 5a2 2 0 012-2h12a2 2 0 012 2v8a2 2 0 01-2 2H8l-4 4v-4H5a2 2 0 01-2-2z" fill="none" stroke="#ff6f61" stroke-width="1.4" stroke-linejoin="round"></path></svg></div><span style="font-size:10px; color:#b5b5bd;">Chat</span></div>
<div style="display:flex; flex-direction:column; align-items:center; gap:6px;"><div style="width:48px; height:48px; border-radius:13px; border:1.5px dashed rgba(255,255,255,.18); display:flex; align-items:center; justify-content:center; color:#ff6f61; font-size:22px; font-weight:300; cursor:pointer;">+</div><span style="font-size:10px; color:#8a8a92;">Add Apps</span></div>
</div>
<div style="font-family:'JetBrains Mono',monospace; font-size:10px; letter-spacing:.12em; color:#5a5a62; margin-bottom:11px;">NOW RUNNING</div>
<sc-for list="{{ running }}" as="r" hint-placeholder-count="2">
<div style="padding:10px 11px; border-radius:10px; background:#101014; border:1px solid rgba(255,255,255,.06); margin-bottom:8px;">
<div style="display:flex; align-items:center; gap:7px; margin-bottom:6px;">
<span style="width:6px; height:6px; border-radius:50%; background:{{ r.dot }}; {{ r.dotAnim }}"></span>
<span style="font-size:12px; font-weight:600; color:#e6e6ea;">{{ r.name }}</span>
<span style="flex:1;"></span>
<span style="font-family:'JetBrains Mono',monospace; font-size:9px; color:{{ r.metaColor }};">{{ r.meta }}</span>
</div>
<sc-if value="{{ r.hasBar }}" hint-placeholder-val="{{ false }}">
<div style="height:4px; border-radius:2px; background:rgba(255,255,255,.08); overflow:hidden;"><div style="width:{{ r.bar }}; height:100%; background:linear-gradient(90deg,#5ec8d8,#4aa3b8);"></div></div>
</sc-if>
</div>
</sc-for>
</div>
<div style="flex:none; margin:0 12px 14px; padding:12px; border-radius:14px; background:#121216; border:1px solid rgba(255,255,255,.07); display:flex; justify-content:space-around;">
<div style="display:flex; flex-direction:column; align-items:center; gap:6px; cursor:pointer;"><div style="width:40px; height:40px; border-radius:11px; background:linear-gradient(135deg,#ff8a7a,#ff5f57); display:flex; align-items:center; justify-content:center;"><svg width="18" height="18" viewBox="0 0 18 18"><path d="M10 1 L3 10 H8 L7 17 L15 7 H9 Z" fill="#fff"></path></svg></div><span style="font-size:10px; color:#b5b5bd;">Skills</span></div>
<div style="display:flex; flex-direction:column; align-items:center; gap:6px; cursor:pointer;"><div style="width:40px; height:40px; border-radius:11px; background:linear-gradient(135deg,#ff8a7a,#ff5f57); display:flex; align-items:center; justify-content:center;"><svg width="18" height="18" viewBox="0 0 18 18"><path d="M2 5a1.5 1.5 0 011.5-1.5H7l1.5 1.5h6A1.5 1.5 0 0116 6.5v7A1.5 1.5 0 0114.5 15h-11A1.5 1.5 0 012 13.5z" fill="#fff"></path></svg></div><span style="font-size:10px; color:#b5b5bd;">Files</span></div>
<div style="display:flex; flex-direction:column; align-items:center; gap:6px; cursor:pointer;"><div style="width:40px; height:40px; border-radius:11px; background:linear-gradient(135deg,#ff8a7a,#ff5f57); display:flex; align-items:center; justify-content:center;"><svg width="18" height="18" viewBox="0 0 18 18"><path d="M9 2a5 5 0 00-5 5c0 4-1.5 5-1.5 5h13S14 11 14 7a5 5 0 00-5-5z" fill="#fff"></path><path d="M7.5 15a1.5 1.5 0 003 0" fill="#fff"></path></svg></div><span style="font-size:10px; color:#ff8a7a;">Routines</span></div>
<div style="display:flex; flex-direction:column; align-items:center; gap:6px; cursor:pointer;"><div style="width:40px; height:40px; border-radius:11px; background:linear-gradient(135deg,#ff8a7a,#ff5f57); display:flex; align-items:center; justify-content:center;"><svg width="18" height="18" viewBox="0 0 18 18"><circle cx="9" cy="9" r="2.6" fill="#fff"></circle><path d="M9 1.5v2M9 14.5v2M1.5 9h2M14.5 9h2M3.7 3.7l1.4 1.4M12.9 12.9l1.4 1.4M14.3 3.7l-1.4 1.4M5.1 12.9l-1.4 1.4" stroke="#fff" stroke-width="1.5"></path></svg></div><span style="font-size:10px; color:#b5b5bd;">Settings</span></div>
</div>
</div>
</sc-if>
</div>
<!-- STATUS BAR -->
<div style="height:28px; flex:none; display:flex; align-items:center; gap:18px; padding:0 16px; border-top:1px solid rgba(255,255,255,.06); background:#0a0a0c; font-family:'JetBrains Mono',monospace; font-size:10px; color:#5a5a62;">
<span style="color:#5fd08a;">● durable runner ok</span>
<span>checkpoint 3s ago</span>
<span style="flex:1;"></span>
<span>§15 sandbox: isolated</span>
<span style="color:{{ doorsValColor }};">{{ doorsStatusText }}</span>
</div>
</div>
</x-dc>
<script type="text/x-dc" data-dc-script data-props="{&quot;liveStream&quot;:{&quot;editor&quot;:&quot;boolean&quot;,&quot;default&quot;:true,&quot;tsType&quot;:&quot;boolean&quot;},&quot;showComputer&quot;:{&quot;editor&quot;:&quot;boolean&quot;,&quot;default&quot;:true,&quot;tsType&quot;:&quot;boolean&quot;},&quot;defaultPromptOpen&quot;:{&quot;editor&quot;:&quot;boolean&quot;,&quot;default&quot;:false,&quot;tsType&quot;:&quot;boolean&quot;}}">
class Component extends DCLogic {
state = { selected: 'morpheus', promptOpen: null, doorApproved: false };
renderVals() {
const s = this.state;
const live = this.props.liveStream ?? true;
const showComputer = this.props.showComputer ?? true;
const AGENTS = {
morpheus: {
name: 'Morpheus', role: 'Project Manager', spec: 'Rust 2024 Specialist',
initial: 'M', grad: 'linear-gradient(135deg,#ff8a7a,#ff5f57)', ink: '#2a0d0a',
model: 'Claude Sonnet 4.5', modelShort: 'claude-sonnet', status: 'working', statusColor: '#5ec8d8',
action: '▸ reviewing PR #214',
tok: '38.4k', spend: '$0.42', loops: 3, mem: '2,418', doors: 1,
commits: '9,105', hot: '11',
taskTitle: 'Review PR #214 — borrow-checker fix in', taskCode: 'cm-runtime', taskElapsed: 'task · 02:14 elapsed',
taskSteps: [
{ icon: '✓', iconColor: '#5fd08a', text: 'read cm-runtime/src/sandbox.rs', meta: '· 3 hunks' },
{ icon: '✓', iconColor: '#5fd08a', text: 'ran cargo clippy --workspace', meta: '· clean' },
{ icon: '▸', iconColor: '#5ec8d8', text: "checking lifetime on &'a mut Guard across await", meta: '', caret: true },
],
reasoningTime: '18:16:09',
reasoning: [
{ tag: 'think', tagColor: '#c98af0', text: 'The original holds the MutexGuard across .await — the std::sync::Mutex-across-await footgun my rules forbid.' },
{ tag: 'note', tagColor: '#9a9aa2', text: 'The fix clones under a scoped lock, dropping the guard before the await point. Sound.' },
{ tag: 'tool', tagColor: '#5ec8d8', text: 'github.review.comment → door check…' },
{ tag: 'door', tagColor: '#e8b465', text: 'post review on PR #214 needs approval', caret: true },
],
personality: ['Analytical', 'Concise', 'Skeptical', 'Direct'],
skillsCount: 7, skills: ['Web research', 'Summarize', 'Data viz', 'Code review'], skillsMore: '+3',
capabilities: ['File mgmt', 'Scheduling', 'Code exec'],
tools: [
{ name: 'Email', nameColor: '#cfcfd5', state: 'gated ✓', stateColor: '#5fd08a' },
{ name: 'Slack', nameColor: '#cfcfd5', state: 'gated ✓', stateColor: '#5fd08a' },
{ name: 'Browser', nameColor: '#cfcfd5', state: 'gated ✓', stateColor: '#5fd08a' },
{ name: 'Shell', nameColor: '#7a7a82', state: 'blocked ', stateColor: '#e8b465' },
],
memory: [
{ k: 'Long-term', v: '2,418 notes' },
{ k: 'Recent context', v: '18 msgs' },
{ k: 'Pinned facts', v: '4' },
],
safety: [
{ k: 'Sandbox', v: 'isolated', color: '#6fd0c0' },
{ k: 'Network', v: 'none', color: '#6fd0c0' },
{ k: 'Egress', v: 'gated', color: '#e8b465' },
],
doorTitle: 'Post code review on PR #214',
doorDetail: 'github.review.comment → external egress · drafts 1 comment',
running: [
{ name: 'Q3 competitor scan', dot: '#5ec8d8', blink: true, meta: 'loop · step 14', metaColor: '#5ec8d8', bar: '62%' },
{ name: 'Daily digest', dot: '#e8b465', blink: false, meta: 'cron · 08:00', metaColor: '#e8b465', bar: '' },
],
promptText: 'You are Morpheus, a senior engineering project manager for the Growth Team.\n\nYou review code with a focus on correctness, concurrency safety, and Rust 2024 idioms. You are concise and direct — flag the issue, propose the fix, cite the rule.\n\nNever hold a std::sync::Mutex guard across an .await point. Prefer scoped locks. Always run cargo clippy before approving.',
},
smith: {
name: 'Smith', role: 'Research Specialist', spec: 'Source Intelligence',
initial: 'S', grad: 'linear-gradient(135deg,#6fd0c0,#4aa3b8)', ink: '#06201f',
model: 'Claude Sonnet 4.5', modelShort: 'claude-sonnet', status: 'running', statusColor: '#5fd08a',
action: '▸ crawling 12 sources',
tok: '22.1k', spend: '$0.28', loops: 2, mem: '1,290', doors: 0,
commits: '4,602', hot: '6',
taskTitle: 'Crate audit — scan dependency tree in', taskCode: 'cargo audit', taskElapsed: 'task · 01:02 elapsed',
taskSteps: [
{ icon: '✓', iconColor: '#5fd08a', text: 'fetched advisory-db', meta: '· 184 crates' },
{ icon: '✓', iconColor: '#5fd08a', text: 'ran cargo audit --json', meta: '· 2 advisories' },
{ icon: '▸', iconColor: '#5ec8d8', text: 'summarizing RUSTSEC-2025-00xx (tokio)', meta: '', caret: true },
],
reasoningTime: '18:16:21',
reasoning: [
{ tag: 'search', tagColor: '#5ec8d8', text: 'crawling 12 sources for tokio CVE context and patched versions.' },
{ tag: 'note', tagColor: '#9a9aa2', text: 'Cross-referencing RUSTSEC + GHSA advisories; deduping by CVE id.' },
{ tag: 'tool', tagColor: '#5ec8d8', text: 'cargo.audit → running, no door required (read-only).' },
{ tag: 'result', tagColor: '#5fd08a', text: '2 advisories found · drafting summary for Morpheus', caret: true },
],
personality: ['Thorough', 'Curious', 'Literal'],
skillsCount: 6, skills: ['Web crawl', 'Summarize', 'Citations', 'Dedup'], skillsMore: '+2',
capabilities: ['Web fetch', 'Indexing', 'Export'],
tools: [
{ name: 'Browser', nameColor: '#cfcfd5', state: 'gated ✓', stateColor: '#5fd08a' },
{ name: 'Slack', nameColor: '#cfcfd5', state: 'gated ✓', stateColor: '#5fd08a' },
{ name: 'Email', nameColor: '#7a7a82', state: 'blocked ', stateColor: '#e8b465' },
{ name: 'Shell', nameColor: '#7a7a82', state: 'blocked ', stateColor: '#e8b465' },
],
memory: [
{ k: 'Long-term', v: '1,290 notes' },
{ k: 'Recent context', v: '11 msgs' },
{ k: 'Pinned facts', v: '2' },
],
safety: [
{ k: 'Sandbox', v: 'isolated', color: '#6fd0c0' },
{ k: 'Network', v: 'read-only', color: '#e8b465' },
{ k: 'Egress', v: 'none', color: '#6fd0c0' },
],
doorTitle: '', doorDetail: '',
running: [
{ name: 'Dependency watch', dot: '#5ec8d8', blink: true, meta: 'loop · step 7', metaColor: '#5ec8d8', bar: '48%' },
{ name: 'Nightly digest', dot: '#5fd08a', blink: false, meta: 'done · 02:00', metaColor: '#5fd08a', bar: '' },
],
promptText: 'You are Smith, a research specialist for the Growth Team.\n\nYou crawl, read, and synthesize sources into tightly-cited summaries. You never assert a fact without a source. You dedupe aggressively and prefer primary advisories (RUSTSEC, GHSA, NVD) over secondary reporting.\n\nYou are read-only by default — surface findings, do not act on them.',
},
};
const a = AGENTS[s.selected] || AGENTS.morpheus;
const order = ['morpheus', 'smith'];
const agents = order.map(id => {
const ag = AGENTS[id];
const sel = id === s.selected;
return {
id, name: ag.name, role: ag.role, initial: ag.initial, grad: ag.grad, ink: ag.ink,
action: ag.action, statusColor: ag.statusColor,
selected: sel,
rowBg: sel ? 'rgba(255,111,97,.1)' : 'transparent',
rowBorder: sel ? 'rgba(255,111,97,.25)' : 'transparent',
labelColor: sel ? '#ffffff' : '#eaeaee',
roleColor: sel ? '#ff8a7a' : '#6a6a72',
onSelect: () => this.setState({ selected: id, doorApproved: false }),
};
});
const defaultOpen = !!(this.props.defaultPromptOpen ?? false);
const promptOpen = s.promptOpen ?? defaultOpen;
const doorsLive = (a.doors > 0 && !s.doorApproved) ? a.doors : 0;
const showDoor = a.doors > 0 && !s.doorApproved;
const doorClear = a.doors === 0 || s.doorApproved;
const anim = (css) => live ? css : '';
return {
selName: a.name, selRole: a.role, selSpec: a.spec, selInitial: a.initial,
selGrad: a.grad, selInk: a.ink, selModel: a.model, selModelShort: a.modelShort,
selStatusLabel: a.status, selTok: a.tok, selSpend: a.spend, selLoops: a.loops, selMem: a.mem,
selCommits: a.commits, selHot: a.hot,
agents,
taskTitle: a.taskTitle, taskCode: a.taskCode, taskElapsed: a.taskElapsed, taskSteps: a.taskSteps,
reasoning: a.reasoning, reasoningTime: a.reasoningTime,
personality: a.personality,
skills: a.skills, skillsCount: a.skillsCount, skillsMore: a.skillsMore,
capabilities: a.capabilities,
tools: a.tools, memory: a.memory, safety: a.safety,
promptOpen, promptText: a.promptText,
promptChars: a.promptText.length.toLocaleString(),
promptChevron: promptOpen ? '▾' : '▸',
togglePrompt: () => this.setState({ promptOpen: !promptOpen }),
showDoor, doorClear, doorTitle: a.doorTitle, doorDetail: a.doorDetail,
approveDoor: () => this.setState({ doorApproved: true }),
doorsLive,
doorsBorder: doorsLive > 0 ? 'rgba(232,196,106,.3)' : 'rgba(255,255,255,.06)',
doorsLabelColor: doorsLive > 0 ? '#e8b465' : '#6a6a72',
doorsValColor: doorsLive > 0 ? '#e8b465' : '#5fd08a',
doorsStatusText: doorsLive > 0 ? (doorsLive + ' door awaiting approval') : 'no doors pending',
showComputer,
running: a.running.map(r => ({
name: r.name, meta: r.meta, metaColor: r.metaColor, dot: r.dot,
dotAnim: (live && r.blink) ? 'animation:cm-blink 1.4s infinite;' : '',
hasBar: !!r.bar, bar: r.bar,
})),
blinkAnim: anim('animation:cm-blink 1.4s infinite;'),
haloAnim: anim('animation:cm-halo 2s ease-out infinite;'),
caretAnim: anim('animation:cm-type 1s steps(1) infinite;'),
barAnim: anim('animation:cm-bar 1.6s ease-in-out infinite;'),
barAnim2: anim('animation:cm-bar 1.9s ease-in-out infinite;'),
};
}
}
</script>
</body>
</html>