agent-teams-dashboard 0.3.0 → 0.3.2

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.
@@ -0,0 +1 @@
1
+ :root{--bg-primary: #1a1a2e;--bg-secondary: #16213e;--bg-sidebar: #0f0f1a;--bg-sidebar-2: #111122;--bg-card: #16213e;--bg-hover: #1f2b47;--bg-active: #253350;--border-primary: #2a2a3e;--border-subtle: #222236;--text-primary: #e0e0e0;--text-secondary: #aaa;--text-muted: #777;--accent-blue: #58a6ff;--accent-green: #00ff88;--accent-yellow: #ffd700;--accent-red: #ff4444;--accent-purple: #bc8cff;--accent-cyan: #00d4ff;--font-mono: "JetBrains Mono", "Fira Code", Consolas, monospace;--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;--radius-sm: 4px;--radius-md: 6px;--radius-lg: 8px;--transition-fast: .15s ease}*,*:before,*:after{margin:0;padding:0;box-sizing:border-box}body{font-family:var(--font-mono);font-size:14px;line-height:1.5;color:var(--text-primary);background:var(--bg-primary);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.app-container{display:flex;height:100vh;overflow:hidden}.resize-handle{width:4px;cursor:col-resize;background:transparent;flex-shrink:0;position:relative;z-index:10;transition:background var(--transition-fast)}.resize-handle:hover,.resize-handle:active{background:var(--accent-cyan)}.teams-panel{background:var(--bg-sidebar);display:flex;flex-direction:column;overflow:hidden;flex-shrink:0}.teams-panel__header{padding:14px 12px;border-bottom:1px solid var(--border-primary)}.teams-panel__title{font-size:13px;font-weight:700;color:var(--text-primary);letter-spacing:.04em;text-transform:uppercase}.teams-panel__conn-dot{font-size:10px}.sidebar-mode-toggle{display:flex;background:var(--bg-secondary);border:1px solid var(--border-primary);border-radius:var(--radius-md);padding:2px;gap:2px}.sidebar-mode-toggle__btn{padding:4px 10px;border:none;background:transparent;color:var(--text-muted);font-family:var(--font-mono);font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.04em;cursor:pointer;border-radius:var(--radius-sm);transition:all var(--transition-fast);line-height:1}.sidebar-mode-toggle__btn:hover{color:var(--text-primary);background:var(--bg-hover)}.sidebar-mode-toggle__btn--active{background:var(--bg-active);color:var(--accent-cyan);box-shadow:0 0 0 1px #00d4ff4d}.teams-panel__nav{flex:1;overflow-y:auto;padding:6px}.teams-panel__nav-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 10px;border:none;background:transparent;color:var(--text-secondary);font-family:var(--font-mono);font-size:12px;cursor:pointer;border-radius:var(--radius-sm);transition:all var(--transition-fast);text-align:left}.teams-panel__nav-item:hover{background:var(--bg-hover);color:var(--text-primary)}.teams-panel__nav-item--active{background:var(--bg-active);color:var(--accent-cyan)}.teams-panel__nav-icon{font-size:14px}.teams-panel__divider{height:1px;background:var(--border-subtle);margin:6px 4px}.teams-panel__team{display:flex;flex-direction:column;gap:3px;width:100%;padding:8px 10px;margin-bottom:2px;border:none;background:transparent;color:var(--text-primary);font-family:var(--font-mono);font-size:14px;cursor:pointer;border-radius:var(--radius-sm);border-left:3px solid transparent;transition:all var(--transition-fast);text-align:left}.teams-panel__team:hover{background:var(--bg-hover)}.teams-panel__team--active{background:var(--bg-active);border-left-color:var(--accent-cyan)}.teams-panel__team-row{display:flex;align-items:center;gap:6px}.teams-panel__team-dot{font-size:10px;flex-shrink:0;line-height:1}.teams-panel__team-name{flex:1;min-width:0}.teams-panel__team-progress{display:flex;align-items:center;gap:6px;padding-left:16px}.teams-panel__team-bar{flex:1;height:3px;background:var(--border-primary);border-radius:2px;overflow:hidden}.teams-panel__team-bar-fill{height:100%;background:var(--accent-green);border-radius:2px;transition:width .3s ease}.teams-panel__team-pct{flex-shrink:0;white-space:nowrap}.teams-panel__footer{padding:10px 12px;border-top:1px solid var(--border-primary)}.teams-panel__footer-stats{display:flex;gap:10px}.agents-panel{background:var(--bg-sidebar-2);display:flex;flex-direction:column;overflow:hidden;flex-shrink:0}.agents-panel__header{padding:14px 12px;border-bottom:1px solid var(--border-primary);display:flex;align-items:center;justify-content:space-between;gap:8px}.agents-panel__title{font-size:13px;font-weight:700;color:var(--text-primary);min-width:0}.agents-panel__task-summary{flex-shrink:0;white-space:nowrap}.agents-panel__empty{flex:1;display:flex;align-items:center;justify-content:center}.agents-panel__actions{padding:8px;border-bottom:1px solid var(--border-subtle)}.agents-panel__tasks-btn{display:flex;align-items:center;gap:6px;width:100%;padding:6px 10px;border:1px solid var(--border-primary);background:transparent;color:var(--text-secondary);font-family:var(--font-mono);font-size:12px;cursor:pointer;border-radius:var(--radius-sm);transition:all var(--transition-fast)}.agents-panel__tasks-btn:hover{background:var(--bg-hover);color:var(--text-primary);border-color:var(--text-muted)}.agents-panel__tasks-btn--active{background:var(--bg-active);color:var(--accent-cyan);border-color:var(--accent-cyan)}.agents-panel__list{flex:1;overflow-y:auto;padding:6px}.agents-panel__agent{margin-bottom:2px}.agents-panel__agent-btn{display:flex;align-items:center;gap:6px;width:100%;padding:7px 10px;border:none;background:transparent;color:var(--text-primary);font-family:var(--font-mono);font-size:14px;cursor:pointer;border-radius:var(--radius-sm);transition:all var(--transition-fast);text-align:left;border-left:3px solid transparent}.agents-panel__agent-btn:hover{background:var(--bg-hover)}.agents-panel__agent-btn--active{background:var(--bg-active);border-left-color:var(--accent-cyan);color:var(--accent-cyan)}.agents-panel__agent-dot{font-size:10px;flex-shrink:0;line-height:1}.agents-panel__agent-name{flex:1;min-width:0}.agents-panel__agent-type{flex-shrink:0}.agents-panel__agent-meta{display:flex;align-items:center;gap:8px;padding:2px 10px 4px 26px}.agents-panel__session-toggle{border:none;background:transparent;color:var(--text-muted);font-family:var(--font-mono);font-size:13px;cursor:pointer;padding:0;transition:color var(--transition-fast)}.agents-panel__session-toggle:hover{color:var(--text-secondary)}.agents-panel__sessions{padding:2px 10px 6px 26px}.agents-panel__session-id{font-size:13px;color:var(--accent-purple);font-family:var(--font-mono)}.agents-panel__session-time{font-size:13px;color:var(--text-muted)}.agents-panel__session-count{font-size:12px;color:var(--text-muted);background:var(--bg-hover);padding:0 4px;border-radius:3px}.main-panel{flex:1;overflow:hidden;display:flex;flex-direction:column}.main-panel>.overview-grid,.main-panel>.task-board__columns,.main-panel--padded{padding:16px;overflow-y:auto}.placeholder{display:flex;align-items:center;justify-content:center;height:100%;color:var(--text-muted);font-size:14px}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border-primary);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}*{scrollbar-width:thin;scrollbar-color:var(--border-primary) transparent}.text-primary{color:var(--text-primary)}.text-secondary{color:var(--text-secondary)}.text-muted{color:var(--text-muted)}.text-blue{color:var(--accent-blue)}.text-green{color:var(--accent-green)}.text-yellow{color:var(--accent-yellow)}.text-red{color:var(--accent-red)}.text-purple{color:var(--accent-purple)}.text-cyan{color:var(--accent-cyan)}.bg-card{background:var(--bg-card)}.bg-hover{background:var(--bg-hover)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-md{border-radius:var(--radius-md)}.rounded-lg{border-radius:var(--radius-lg)}.flex{display:flex}.flex-col{flex-direction:column}.flex-1{flex:1}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-1{gap:4px}.gap-2{gap:8px}.gap-3{gap:12px}.gap-4{gap:16px}.p-1{padding:4px}.p-2{padding:8px}.p-3{padding:12px}.p-4{padding:16px}.px-2{padding-left:8px;padding-right:8px}.px-3{padding-left:12px;padding-right:12px}.py-1{padding-top:4px;padding-bottom:4px}.py-2{padding-top:8px;padding-bottom:8px}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.font-bold{font-weight:600}.text-sm{font-size:14px}.text-xs{font-size:13px}.border{border:1px solid var(--border-primary)}.border-b{border-bottom:1px solid var(--border-primary)}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;user-select:none}.transition{transition:all var(--transition-fast)}.panel-title{font-size:16px;font-weight:600;color:var(--text-primary);margin-bottom:16px}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;gap:12px;text-align:center}.empty-state__icon{font-size:48px}.empty-state__title{font-size:16px;font-weight:600;color:var(--text-secondary)}.empty-state__text{max-width:400px;line-height:1.6}.overview-panel{padding:16px;overflow-y:auto;height:100%}.overview-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px}.overview-card{background:var(--bg-card);border:1px solid var(--border-primary);border-left:3px solid var(--text-muted);border-radius:var(--radius-md);padding:16px;transition:all var(--transition-fast)}.overview-card:hover{border-color:var(--accent-cyan);border-left-color:inherit;background:var(--bg-hover)}.overview-card--active{border-left-color:var(--accent-green)}.overview-card--idle{border-left-color:var(--accent-yellow)}.overview-card--done{border-left-color:var(--accent-cyan)}.overview-card--inactive{border-left-color:var(--text-muted)}.overview-card__header{display:flex;justify-content:space-between;align-items:center;margin-bottom:4px}.overview-card__meta{margin-bottom:12px}.overview-card__progress{display:flex;align-items:center;gap:8px;margin-bottom:8px}.progress-bar{flex:1;height:4px;background:var(--border-primary);border-radius:2px;overflow:hidden}.progress-bar__fill{height:100%;background:var(--accent-green);border-radius:2px;transition:width .3s ease}.overview-card__footer{text-align:right}.pulse-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--accent-green);animation:pulse 2s ease-in-out infinite;flex-shrink:0}@keyframes pulse{0%,to{opacity:1;box-shadow:0 0 #0f86}50%{opacity:.7;box-shadow:0 0 0 6px #0f80}}.task-board{padding:16px;overflow-y:auto;height:100%}.task-board__columns{display:flex;gap:12px}.task-board__column{flex:1;min-width:0}.task-board__column-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;margin-bottom:8px;border-bottom:2px solid var(--border-primary);font-weight:600;font-size:12px;color:var(--text-secondary)}.task-card{background:var(--bg-card);border:1px solid var(--border-primary);border-radius:var(--radius-md);padding:12px;margin-bottom:8px;border-left:3px solid var(--text-muted)}.task-card--in-progress{border-left-color:var(--accent-yellow)}.task-card--completed{border-left-color:var(--accent-green)}.task-card--pending{border-left-color:var(--text-muted)}.task-card__subject{font-size:12px;margin-bottom:4px;color:var(--text-primary)}.task-card__desc{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;margin-bottom:8px;line-height:1.4}.task-card__meta{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.task-card__owner{display:inline-block;padding:2px 6px;background:#00d4ff26;color:var(--accent-cyan);border-radius:var(--radius-sm);font-size:11px}.task-card__blocked{color:var(--accent-yellow)}.chat-panel{display:flex;flex-direction:column;height:100%;position:relative}.chat-panel__header{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 16px;border-bottom:1px solid var(--border-primary);background:var(--bg-secondary);flex-shrink:0}.chat-panel__header-left{display:flex;align-items:center;gap:8px;min-width:0}.chat-panel__header-right{display:flex;align-items:center;gap:12px;flex-shrink:0}.chat-panel__agent-name{font-size:14px;font-weight:700;color:var(--accent-cyan);font-family:var(--font-mono)}.chat-panel__session-tag{font-size:11px;padding:2px 6px;background:#bc8cff26;color:var(--accent-purple);border-radius:var(--radius-sm);font-family:var(--font-mono)}.chat-panel__team{white-space:nowrap}.chat-panel__feed{flex:1;overflow-y:auto;padding:8px 0}.chat-panel__empty{display:flex;align-items:center;justify-content:center;height:100%}.chat-panel__scroll-btn{position:absolute;bottom:12px;right:16px;padding:6px 12px;background:var(--bg-active);border:1px solid var(--accent-cyan);color:var(--accent-cyan);font-family:var(--font-mono);font-size:11px;border-radius:var(--radius-sm);cursor:pointer;transition:all var(--transition-fast);z-index:10}.chat-panel__scroll-btn:hover{background:var(--bg-hover)}.chat-msg{padding:6px 16px;border-left:3px solid transparent;transition:background var(--transition-fast)}.chat-msg:hover{background:#ffffff05}.chat-msg--user{border-left-color:var(--accent-green);background:#00ff8808}.chat-msg--assistant{border-left-color:var(--accent-cyan)}.chat-msg--tool-use{border-left-color:var(--accent-yellow);background:#ffd70008}.chat-msg--tool-result{border-left-color:var(--text-secondary);background:#aaaaaa08}.chat-msg__meta{display:flex;align-items:center;gap:8px;margin-bottom:4px}.chat-msg__role{font-size:12px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;font-family:var(--font-mono)}.chat-msg--user .chat-msg__role{color:var(--accent-green)}.chat-msg--assistant .chat-msg__role{color:var(--accent-cyan)}.chat-msg--tool-use .chat-msg__role{color:var(--accent-yellow)}.chat-msg--tool-result .chat-msg__role{color:var(--text-secondary)}.chat-msg__time{font-size:12px;color:var(--text-secondary);font-family:var(--font-mono)}.chat-msg__body{font-size:14px;line-height:1.6;word-break:break-word}.msg-prose{color:var(--text-primary);white-space:pre-wrap}.chat-msg--assistant .msg-prose{color:var(--text-primary)}.msg-code{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-sm);padding:8px 10px;font-size:13px;white-space:pre-wrap;overflow-x:auto;color:var(--text-primary);margin-top:2px}.msg-expand-btn{border:none;background:transparent;color:var(--text-muted);font-family:var(--font-mono);font-size:11px;cursor:pointer;padding:2px 0;margin-top:4px;transition:color var(--transition-fast)}.msg-expand-btn:hover{color:var(--text-secondary)}.msg-tool-use{margin-top:2px}.msg-tool-header{display:flex;align-items:center;gap:6px;border:none;background:transparent;cursor:pointer;padding:3px 0;font-family:var(--font-mono)}.msg-tool-name{display:inline-block;padding:2px 8px;background:#ffd7001f;border:1px solid rgba(255,215,0,.3);color:var(--accent-yellow);border-radius:var(--radius-sm);font-size:13px;font-weight:600;font-family:var(--font-mono)}.msg-tool-toggle{font-size:11px;color:var(--text-muted)}.msg-tool-body{background:var(--bg-secondary);border:1px solid rgba(255,215,0,.15);border-radius:var(--radius-sm);padding:8px 10px;font-size:13px;white-space:pre-wrap;overflow-x:auto;color:var(--text-secondary);margin-top:4px;max-height:300px;overflow-y:auto}.msg-tool-result{margin-top:2px}.msg-error-badge{display:inline-block;padding:1px 5px;background:#ff444426;color:var(--accent-red);border-radius:var(--radius-sm);font-size:12px;font-weight:700;margin-bottom:4px;font-family:var(--font-mono)}.msg-result-body{font-size:13px;white-space:pre-wrap;overflow-x:auto;color:var(--text-secondary);line-height:1.5;max-height:400px;overflow-y:auto}.msg-tool-result--error .msg-result-body{color:#ff4444b3}.agents-panel__session{display:flex;align-items:center;gap:8px;padding:3px 8px;border-left:1px solid var(--border-subtle);margin-left:4px;width:100%;border-radius:0 var(--radius-sm) var(--radius-sm) 0;background:transparent;cursor:pointer;font-family:var(--font-mono);transition:background var(--transition-fast);border-top:none;border-right:none;border-bottom:none}.agents-panel__session:hover{background:var(--bg-hover)}.agents-panel__session--active{background:var(--bg-active);border-left-color:var(--accent-purple)}.agent-panel{display:flex;flex-direction:column;height:100%}.agent-panel__header{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid var(--border-primary)}.agent-panel__header .panel-title{margin-bottom:0}.status-badge{display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;font-weight:600}.status-badge--active{background:#00ff8826;color:var(--accent-green)}.status-badge--idle{background:#ffd70026;color:var(--accent-yellow)}.status-badge--done{background:#00d4ff26;color:var(--accent-cyan)}.status-badge--unknown{background:#5555554d;color:var(--text-muted)}.agent-panel__tasks{padding:8px 12px;margin-bottom:12px;background:var(--bg-card);border-radius:var(--radius-md);border:1px solid var(--border-primary)}.agent-panel__task-item{display:flex;align-items:center;gap:8px;padding:4px 0;font-size:12px}.task-status-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}.task-status-dot--pending{background:var(--text-muted)}.task-status-dot--in_progress{background:var(--accent-yellow)}.task-status-dot--completed{background:var(--accent-green)}.agent-panel__feed{flex:1;overflow-y:auto;padding:4px}.activity-entry{padding:8px 12px;margin-bottom:4px;border-radius:var(--radius-sm);font-size:12px}.activity-entry--user{border-left:3px solid var(--accent-green);background:#00ff880d}.activity-entry--assistant{color:var(--accent-cyan)}.activity-entry--tool-use{background:#ffd7000d}.activity-entry--tool-result{color:var(--text-muted)}.activity-entry__header{display:flex;justify-content:space-between;align-items:center;margin-bottom:4px}.activity-entry__role{color:var(--text-muted);text-transform:uppercase;letter-spacing:.05em}.activity-entry__body{word-break:break-word}.activity-entry__code{background:var(--bg-secondary);padding:8px;border-radius:var(--radius-sm);overflow-x:auto;font-size:11px;white-space:pre-wrap;margin-top:4px}.activity-entry__tool-use{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.activity-entry__tool-badge{display:inline-block;padding:2px 6px;background:#ffd70026;color:var(--accent-yellow);border-radius:var(--radius-sm);font-size:11px;white-space:nowrap}.activity-entry__tool-input{font-size:11px;word-break:break-all}.activity-entry__tool-result{font-size:11px;line-height:1.4}
package/dist/index.html CHANGED
@@ -4,8 +4,8 @@
4
4
  <meta charset="UTF-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>Agent Teams Dashboard</title>
7
- <script type="module" crossorigin src="/assets/index-C2fnhLSE.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-BqtV8ETR.css">
7
+ <script type="module" crossorigin src="/assets/index-CEXrdfKk.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-CsK61Xi-.css">
9
9
  </head>
10
10
  <body>
11
11
  <div id="root"></div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "agent-teams-dashboard",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "Real-time monitoring dashboard for Claude Code agent teams",
5
5
  "type": "module",
6
6
  "author": "pingshian0131",
@@ -1,4 +1,4 @@
1
- import { readdir, readFile, stat } from 'node:fs/promises';
1
+ import { readdir, readFile, stat, open } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
3
  import { homedir } from 'node:os';
4
4
  import { EventEmitter } from 'node:events';
@@ -13,6 +13,7 @@ const tasks = new Map();
13
13
  const agentEntries = new Map();
14
14
  const agentOffsets = new Map();
15
15
  const teamFileMtimes = new Map(); // team name -> latest mtime (ms)
16
+ const knownProjectDirs = new Set(); // all project dir names under ~/.claude/projects/
16
17
  export const onChange = new EventEmitter();
17
18
  // --- Helpers ---
18
19
  async function safeReaddir(dir) {
@@ -141,6 +142,10 @@ async function refreshAllTasks() {
141
142
  // Scan both subagent JSONL (agent-*.jsonl) and team session JSONL (UUID.jsonl with teamName)
142
143
  export async function scanAgentJsonl() {
143
144
  const projectDirs = await safeReaddir(PROJECTS_DIR);
145
+ // Track all known project dirs for name resolution
146
+ for (const d of projectDirs) {
147
+ knownProjectDirs.add(d);
148
+ }
144
149
  for (const projDir of projectDirs) {
145
150
  const projPath = join(PROJECTS_DIR, projDir);
146
151
  const entries = await safeReaddir(projPath);
@@ -148,7 +153,7 @@ export async function scanAgentJsonl() {
148
153
  const entryPath = join(projPath, entry);
149
154
  // Team session JSONL: UUID.jsonl files at project root level
150
155
  if (entry.endsWith('.jsonl')) {
151
- await readNewEntries(entryPath, true);
156
+ await readNewEntries(entryPath, true, projDir);
152
157
  continue;
153
158
  }
154
159
  // Subagent JSONL: agent-*.jsonl under session/subagents/
@@ -157,12 +162,12 @@ export async function scanAgentJsonl() {
157
162
  for (const file of files) {
158
163
  if (!file.startsWith('agent-') || !file.endsWith('.jsonl'))
159
164
  continue;
160
- await readNewEntries(join(subagentsDir, file), false);
165
+ await readNewEntries(join(subagentsDir, file), false, projDir);
161
166
  }
162
167
  }
163
168
  }
164
169
  }
165
- async function readNewEntries(filePath, isSessionFile) {
170
+ async function readNewEntries(filePath, isSessionFile, projectDir) {
166
171
  const fileStat = await safeFileStat(filePath);
167
172
  if (!fileStat)
168
173
  return;
@@ -170,26 +175,52 @@ async function readNewEntries(filePath, isSessionFile) {
170
175
  const fileSize = fileStat.size;
171
176
  if (fileSize <= currentOffset)
172
177
  return;
173
- const raw = await safeReadFile(filePath);
174
- if (!raw)
178
+ // Read only the new bytes from currentOffset to avoid byte/char offset mismatch
179
+ let newContent;
180
+ try {
181
+ const fh = await open(filePath, 'r');
182
+ try {
183
+ const buf = Buffer.alloc(fileSize - currentOffset);
184
+ await fh.read(buf, 0, buf.length, currentOffset);
185
+ newContent = buf.toString('utf-8');
186
+ }
187
+ finally {
188
+ await fh.close();
189
+ }
190
+ }
191
+ catch {
175
192
  return;
176
- const newContent = raw.slice(currentOffset);
193
+ }
177
194
  agentOffsets.set(filePath, fileSize);
178
195
  const lines = newContent.split('\n').filter(Boolean);
179
196
  for (const line of lines) {
180
197
  try {
181
198
  const parsed = JSON.parse(line);
182
- // For session files, only process entries that belong to a team agent
199
+ // For session files, process team entries AND regular conversation entries
183
200
  if (isSessionFile) {
184
201
  const teamName = parsed.teamName;
185
- const agentName = parsed.agentName;
186
- if (!teamName || !agentName)
202
+ // Skip non-message entries (file-history-snapshot, progress, queue-operation, system)
203
+ if (!parsed.type || (parsed.type !== 'user' && parsed.type !== 'assistant'))
187
204
  continue;
188
- // Use team agentId format: name@team
189
- const fullAgentId = `${agentName}@${teamName}`;
205
+ let fullAgentId;
206
+ let slug;
207
+ if (teamName) {
208
+ // Team session: use name@team format
209
+ const agentName = parsed.agentName || 'team-lead';
210
+ fullAgentId = `${agentName}@${teamName}`;
211
+ slug = agentName;
212
+ }
213
+ else {
214
+ // Regular conversation: use sessionId as agentId
215
+ const sessionId = parsed.sessionId ?? '';
216
+ if (!sessionId)
217
+ continue;
218
+ fullAgentId = `session:${sessionId}`;
219
+ slug = parsed.slug || sessionId.slice(0, 8);
220
+ }
190
221
  const entry = {
191
222
  agentId: fullAgentId,
192
- slug: agentName,
223
+ slug,
193
224
  sessionId: parsed.sessionId ?? '',
194
225
  type: parsed.type ?? 'assistant',
195
226
  message: {
@@ -202,6 +233,7 @@ async function readNewEntries(filePath, isSessionFile) {
202
233
  model: parsed.message?.model,
203
234
  },
204
235
  timestamp: parsed.timestamp ?? '',
236
+ projectDir,
205
237
  };
206
238
  let arr = agentEntries.get(fullAgentId);
207
239
  if (!arr) {
@@ -212,6 +244,12 @@ async function readNewEntries(filePath, isSessionFile) {
212
244
  if (arr.length > MAX_ENTRIES_PER_AGENT) {
213
245
  arr.splice(0, arr.length - MAX_ENTRIES_PER_AGENT);
214
246
  }
247
+ // Update slug from assistant entries (they carry the slug)
248
+ if (parsed.slug && arr.length > 0) {
249
+ for (const e of arr) {
250
+ e.slug = parsed.slug;
251
+ }
252
+ }
215
253
  continue;
216
254
  }
217
255
  // Subagent JSONL: use agentId from the file
@@ -230,6 +268,7 @@ async function readNewEntries(filePath, isSessionFile) {
230
268
  model: parsed.message?.model,
231
269
  },
232
270
  timestamp: parsed.timestamp ?? '',
271
+ projectDir,
233
272
  };
234
273
  if (!entry.agentId)
235
274
  continue;
@@ -294,6 +333,119 @@ function buildTeamOverview(teamName) {
294
333
  }
295
334
  return { config, tasks: teamTasks, taskStats, agentSlugs, lastActivity };
296
335
  }
336
+ /**
337
+ * Encode a filesystem path to the Claude project dir format.
338
+ * /Users/ping → -Users-ping
339
+ */
340
+ function encodePathPrefix(fsPath) {
341
+ return '-' + fsPath.replace(/\//g, '-').replace(/^-/, '');
342
+ }
343
+ // The home directory prefix in encoded form, used to strip from project dir names.
344
+ // Uses HOST_HOME env var (set in Docker) or falls back to os.homedir().
345
+ const HOME_PREFIX = encodePathPrefix(process.env.HOST_HOME || homedir());
346
+ /**
347
+ * Use the set of all known project dirs to resolve ambiguous dashes.
348
+ * If "-Users-ping-projects" exists as a project dir, then in
349
+ * "-Users-ping-projects-agent-teams-dashboard", the "projects" portion
350
+ * is a directory (path separator), not part of a directory name.
351
+ *
352
+ * Returns the last path segment (the actual project directory name).
353
+ */
354
+ function resolveProjectName(projectDir, allProjectDirs) {
355
+ if (projectDir === HOME_PREFIX)
356
+ return '~';
357
+ const prefixWithDash = HOME_PREFIX + '-';
358
+ if (!projectDir.startsWith(prefixWithDash))
359
+ return projectDir;
360
+ const remainder = projectDir.slice(prefixWithDash.length);
361
+ // Try to find the longest known parent directory prefix.
362
+ // A known dir is a valid parent only if:
363
+ // 1. It's a strict prefix of projectDir (not equal to it)
364
+ // 2. No OTHER known dir starts with it + the next dash-segment
365
+ // (which would mean the continuation is part of the dir name, not a child)
366
+ let bestSplit = 0;
367
+ const parts = remainder.split('-');
368
+ let accumulated = HOME_PREFIX;
369
+ for (let i = 0; i < parts.length - 1; i++) {
370
+ accumulated += '-' + parts[i];
371
+ if (!allProjectDirs.has(accumulated) || accumulated === projectDir)
372
+ continue;
373
+ // Check: is there another known dir that starts with accumulated + '-' + nextPart?
374
+ // If so, accumulated might not be a true parent — the next segment could be part
375
+ // of a longer directory name at the same level.
376
+ const nextAccumulated = accumulated + '-' + parts[i + 1];
377
+ // When nextAccumulated === projectDir, accumulated could be a real parent
378
+ // (e.g. panamera-python3 → worktree3) or a false parent (e.g. erp-shipment → 2).
379
+ // Heuristic: accumulated is a real parent if other known dirs also have it as prefix.
380
+ if (nextAccumulated === projectDir) {
381
+ const accPrefix = accumulated + '-';
382
+ const hasOtherChildren = Array.from(allProjectDirs).some(d => d !== projectDir && d.startsWith(accPrefix));
383
+ if (hasOtherChildren) {
384
+ bestSplit = i + 1;
385
+ }
386
+ continue;
387
+ }
388
+ const isFalseParent = allProjectDirs.has(nextAccumulated) &&
389
+ projectDir.startsWith(nextAccumulated);
390
+ if (!isFalseParent) {
391
+ bestSplit = i + 1;
392
+ }
393
+ }
394
+ if (bestSplit > 0) {
395
+ return parts.slice(bestSplit).join('-');
396
+ }
397
+ return remainder;
398
+ }
399
+ function buildProjectOverviews() {
400
+ // Group all agent entries by projectDir
401
+ const projectMap = new Map();
402
+ for (const [agentId, entries] of agentEntries) {
403
+ for (const entry of entries) {
404
+ if (!entry.projectDir)
405
+ continue;
406
+ let agentMap = projectMap.get(entry.projectDir);
407
+ if (!agentMap) {
408
+ agentMap = new Map();
409
+ projectMap.set(entry.projectDir, agentMap);
410
+ }
411
+ let agentData = agentMap.get(agentId);
412
+ if (!agentData) {
413
+ agentData = { slug: entry.slug, entries: [] };
414
+ agentMap.set(agentId, agentData);
415
+ }
416
+ agentData.entries.push(entry);
417
+ if (entry.slug)
418
+ agentData.slug = entry.slug;
419
+ }
420
+ }
421
+ const projects = [];
422
+ for (const [projectDir, agentMap] of projectMap) {
423
+ let lastActivity = '';
424
+ const agents = [];
425
+ for (const [agentId, data] of agentMap) {
426
+ const lastTs = data.entries.length > 0
427
+ ? data.entries[data.entries.length - 1].timestamp
428
+ : '';
429
+ agents.push({
430
+ agentId,
431
+ slug: data.slug || agentId,
432
+ entryCount: data.entries.length,
433
+ lastTimestamp: lastTs,
434
+ });
435
+ if (lastTs > lastActivity)
436
+ lastActivity = lastTs;
437
+ }
438
+ agents.sort((a, b) => b.lastTimestamp.localeCompare(a.lastTimestamp));
439
+ projects.push({
440
+ projectDir,
441
+ projectName: resolveProjectName(projectDir, knownProjectDirs),
442
+ agents,
443
+ lastActivity,
444
+ });
445
+ }
446
+ projects.sort((a, b) => b.lastActivity.localeCompare(a.lastActivity));
447
+ return projects;
448
+ }
297
449
  export function getSnapshot() {
298
450
  const teamOverviews = [];
299
451
  const matchedAgentIds = new Set();
@@ -326,7 +478,7 @@ export function getSnapshot() {
326
478
  activity[agentId] = entries;
327
479
  }
328
480
  }
329
- return { teams: teamOverviews, unmatchedAgents, agentActivity: activity };
481
+ return { teams: teamOverviews, unmatchedAgents, agentActivity: activity, projects: buildProjectOverviews() };
330
482
  }
331
483
  // --- Query ---
332
484
  export function getAgentActivity(agentId) {
@@ -1 +0,0 @@
1
- :root{--bg-primary: #1a1a2e;--bg-secondary: #16213e;--bg-sidebar: #0f0f1a;--bg-sidebar-2: #111122;--bg-card: #16213e;--bg-hover: #1f2b47;--bg-active: #253350;--border-primary: #2a2a3e;--border-subtle: #222236;--text-primary: #e0e0e0;--text-secondary: #888;--text-muted: #555;--accent-blue: #58a6ff;--accent-green: #00ff88;--accent-yellow: #ffd700;--accent-red: #ff4444;--accent-purple: #bc8cff;--accent-cyan: #00d4ff;--font-mono: "JetBrains Mono", "Fira Code", Consolas, monospace;--font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;--radius-sm: 4px;--radius-md: 6px;--radius-lg: 8px;--transition-fast: .15s ease}*,*:before,*:after{margin:0;padding:0;box-sizing:border-box}body{font-family:var(--font-mono);font-size:13px;line-height:1.5;color:var(--text-primary);background:var(--bg-primary);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.app-container{display:flex;height:100vh;overflow:hidden}.teams-panel{width:200px;min-width:200px;background:var(--bg-sidebar);border-right:1px solid var(--border-primary);display:flex;flex-direction:column;overflow:hidden}.teams-panel__header{padding:14px 12px;border-bottom:1px solid var(--border-primary)}.teams-panel__title{font-size:13px;font-weight:700;color:var(--text-primary);letter-spacing:.04em;text-transform:uppercase}.teams-panel__conn-dot{font-size:10px}.teams-panel__nav{flex:1;overflow-y:auto;padding:6px}.teams-panel__nav-item{display:flex;align-items:center;gap:8px;width:100%;padding:8px 10px;border:none;background:transparent;color:var(--text-secondary);font-family:var(--font-mono);font-size:12px;cursor:pointer;border-radius:var(--radius-sm);transition:all var(--transition-fast);text-align:left}.teams-panel__nav-item:hover{background:var(--bg-hover);color:var(--text-primary)}.teams-panel__nav-item--active{background:var(--bg-active);color:var(--accent-cyan)}.teams-panel__nav-icon{font-size:14px}.teams-panel__divider{height:1px;background:var(--border-subtle);margin:6px 4px}.teams-panel__team{display:flex;flex-direction:column;gap:4px;width:100%;padding:8px 10px;margin-bottom:2px;border:none;background:transparent;color:var(--text-primary);font-family:var(--font-mono);font-size:12px;cursor:pointer;border-radius:var(--radius-sm);border-left:3px solid transparent;transition:all var(--transition-fast);text-align:left}.teams-panel__team:hover{background:var(--bg-hover)}.teams-panel__team--active{background:var(--bg-active);border-left-color:var(--accent-cyan)}.teams-panel__team-row{display:flex;align-items:center;gap:6px}.teams-panel__team-dot{font-size:10px;flex-shrink:0;line-height:1}.teams-panel__team-name{flex:1;min-width:0}.teams-panel__team-progress{display:flex;align-items:center;gap:6px;padding-left:16px}.teams-panel__team-bar{flex:1;height:3px;background:var(--border-primary);border-radius:2px;overflow:hidden}.teams-panel__team-bar-fill{height:100%;background:var(--accent-green);border-radius:2px;transition:width .3s ease}.teams-panel__team-pct{flex-shrink:0;white-space:nowrap}.teams-panel__footer{padding:10px 12px;border-top:1px solid var(--border-primary)}.teams-panel__footer-stats{display:flex;gap:10px}.agents-panel{width:260px;min-width:260px;background:var(--bg-sidebar-2);border-right:1px solid var(--border-primary);display:flex;flex-direction:column;overflow:hidden}.agents-panel__header{padding:14px 12px;border-bottom:1px solid var(--border-primary);display:flex;align-items:center;justify-content:space-between;gap:8px}.agents-panel__title{font-size:13px;font-weight:700;color:var(--text-primary);min-width:0}.agents-panel__task-summary{flex-shrink:0;white-space:nowrap}.agents-panel__empty{flex:1;display:flex;align-items:center;justify-content:center}.agents-panel__actions{padding:8px;border-bottom:1px solid var(--border-subtle)}.agents-panel__tasks-btn{display:flex;align-items:center;gap:6px;width:100%;padding:6px 10px;border:1px solid var(--border-primary);background:transparent;color:var(--text-secondary);font-family:var(--font-mono);font-size:12px;cursor:pointer;border-radius:var(--radius-sm);transition:all var(--transition-fast)}.agents-panel__tasks-btn:hover{background:var(--bg-hover);color:var(--text-primary);border-color:var(--text-muted)}.agents-panel__tasks-btn--active{background:var(--bg-active);color:var(--accent-cyan);border-color:var(--accent-cyan)}.agents-panel__list{flex:1;overflow-y:auto;padding:6px}.agents-panel__agent{margin-bottom:2px}.agents-panel__agent-btn{display:flex;align-items:center;gap:6px;width:100%;padding:7px 10px;border:none;background:transparent;color:var(--text-primary);font-family:var(--font-mono);font-size:12px;cursor:pointer;border-radius:var(--radius-sm);transition:all var(--transition-fast);text-align:left;border-left:3px solid transparent}.agents-panel__agent-btn:hover{background:var(--bg-hover)}.agents-panel__agent-btn--active{background:var(--bg-active);border-left-color:var(--accent-cyan);color:var(--accent-cyan)}.agents-panel__agent-dot{font-size:10px;flex-shrink:0;line-height:1}.agents-panel__agent-name{flex:1;min-width:0}.agents-panel__agent-type{flex-shrink:0}.agents-panel__agent-meta{display:flex;align-items:center;gap:8px;padding:2px 10px 4px 26px}.agents-panel__session-toggle{border:none;background:transparent;color:var(--text-muted);font-family:var(--font-mono);font-size:11px;cursor:pointer;padding:0;transition:color var(--transition-fast)}.agents-panel__session-toggle:hover{color:var(--text-secondary)}.agents-panel__sessions{padding:2px 10px 6px 26px}.agents-panel__session-id{font-size:11px;color:var(--accent-purple);font-family:var(--font-mono)}.agents-panel__session-time{font-size:11px;color:var(--text-muted)}.agents-panel__session-count{font-size:10px;color:var(--text-muted);background:var(--bg-hover);padding:0 4px;border-radius:3px}.main-panel{flex:1;overflow:hidden;display:flex;flex-direction:column}.main-panel>.overview-grid,.main-panel>.task-board__columns,.main-panel--padded{padding:16px;overflow-y:auto}.placeholder{display:flex;align-items:center;justify-content:center;height:100%;color:var(--text-muted);font-size:14px}::-webkit-scrollbar{width:6px;height:6px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border-primary);border-radius:3px}::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}*{scrollbar-width:thin;scrollbar-color:var(--border-primary) transparent}.text-primary{color:var(--text-primary)}.text-secondary{color:var(--text-secondary)}.text-muted{color:var(--text-muted)}.text-blue{color:var(--accent-blue)}.text-green{color:var(--accent-green)}.text-yellow{color:var(--accent-yellow)}.text-red{color:var(--accent-red)}.text-purple{color:var(--accent-purple)}.text-cyan{color:var(--accent-cyan)}.bg-card{background:var(--bg-card)}.bg-hover{background:var(--bg-hover)}.rounded-sm{border-radius:var(--radius-sm)}.rounded-md{border-radius:var(--radius-md)}.rounded-lg{border-radius:var(--radius-lg)}.flex{display:flex}.flex-col{flex-direction:column}.flex-1{flex:1}.items-center{align-items:center}.justify-between{justify-content:space-between}.gap-1{gap:4px}.gap-2{gap:8px}.gap-3{gap:12px}.gap-4{gap:16px}.p-1{padding:4px}.p-2{padding:8px}.p-3{padding:12px}.p-4{padding:16px}.px-2{padding-left:8px;padding-right:8px}.px-3{padding-left:12px;padding-right:12px}.py-1{padding-top:4px;padding-bottom:4px}.py-2{padding-top:8px;padding-bottom:8px}.truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.font-bold{font-weight:600}.text-sm{font-size:12px}.text-xs{font-size:11px}.border{border:1px solid var(--border-primary)}.border-b{border-bottom:1px solid var(--border-primary)}.cursor-pointer{cursor:pointer}.select-none{-webkit-user-select:none;user-select:none}.transition{transition:all var(--transition-fast)}.panel-title{font-size:16px;font-weight:600;color:var(--text-primary);margin-bottom:16px}.empty-state{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;gap:12px;text-align:center}.empty-state__icon{font-size:48px}.empty-state__title{font-size:16px;font-weight:600;color:var(--text-secondary)}.empty-state__text{max-width:400px;line-height:1.6}.overview-panel{padding:16px;overflow-y:auto;height:100%}.overview-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:12px}.overview-card{background:var(--bg-card);border:1px solid var(--border-primary);border-left:3px solid var(--text-muted);border-radius:var(--radius-md);padding:16px;transition:all var(--transition-fast)}.overview-card:hover{border-color:var(--accent-cyan);border-left-color:inherit;background:var(--bg-hover)}.overview-card--active{border-left-color:var(--accent-green)}.overview-card--idle{border-left-color:var(--accent-yellow)}.overview-card--done{border-left-color:var(--accent-cyan)}.overview-card--inactive{border-left-color:var(--text-muted)}.overview-card__header{display:flex;justify-content:space-between;align-items:center;margin-bottom:4px}.overview-card__meta{margin-bottom:12px}.overview-card__progress{display:flex;align-items:center;gap:8px;margin-bottom:8px}.progress-bar{flex:1;height:4px;background:var(--border-primary);border-radius:2px;overflow:hidden}.progress-bar__fill{height:100%;background:var(--accent-green);border-radius:2px;transition:width .3s ease}.overview-card__footer{text-align:right}.pulse-dot{display:inline-block;width:8px;height:8px;border-radius:50%;background:var(--accent-green);animation:pulse 2s ease-in-out infinite;flex-shrink:0}@keyframes pulse{0%,to{opacity:1;box-shadow:0 0 #0f86}50%{opacity:.7;box-shadow:0 0 0 6px #0f80}}.task-board{padding:16px;overflow-y:auto;height:100%}.task-board__columns{display:flex;gap:12px}.task-board__column{flex:1;min-width:0}.task-board__column-header{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;margin-bottom:8px;border-bottom:2px solid var(--border-primary);font-weight:600;font-size:12px;color:var(--text-secondary)}.task-card{background:var(--bg-card);border:1px solid var(--border-primary);border-radius:var(--radius-md);padding:12px;margin-bottom:8px;border-left:3px solid var(--text-muted)}.task-card--in-progress{border-left-color:var(--accent-yellow)}.task-card--completed{border-left-color:var(--accent-green)}.task-card--pending{border-left-color:var(--text-muted)}.task-card__subject{font-size:12px;margin-bottom:4px;color:var(--text-primary)}.task-card__desc{display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;margin-bottom:8px;line-height:1.4}.task-card__meta{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.task-card__owner{display:inline-block;padding:2px 6px;background:#00d4ff26;color:var(--accent-cyan);border-radius:var(--radius-sm);font-size:11px}.task-card__blocked{color:var(--accent-yellow)}.chat-panel{display:flex;flex-direction:column;height:100%;position:relative}.chat-panel__header{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 16px;border-bottom:1px solid var(--border-primary);background:var(--bg-secondary);flex-shrink:0}.chat-panel__header-left{display:flex;align-items:center;gap:8px;min-width:0}.chat-panel__header-right{display:flex;align-items:center;gap:12px;flex-shrink:0}.chat-panel__agent-name{font-size:14px;font-weight:700;color:var(--accent-cyan);font-family:var(--font-mono)}.chat-panel__session-tag{font-size:11px;padding:2px 6px;background:#bc8cff26;color:var(--accent-purple);border-radius:var(--radius-sm);font-family:var(--font-mono)}.chat-panel__team{white-space:nowrap}.chat-panel__feed{flex:1;overflow-y:auto;padding:8px 0}.chat-panel__empty{display:flex;align-items:center;justify-content:center;height:100%}.chat-panel__scroll-btn{position:absolute;bottom:12px;right:16px;padding:6px 12px;background:var(--bg-active);border:1px solid var(--accent-cyan);color:var(--accent-cyan);font-family:var(--font-mono);font-size:11px;border-radius:var(--radius-sm);cursor:pointer;transition:all var(--transition-fast);z-index:10}.chat-panel__scroll-btn:hover{background:var(--bg-hover)}.chat-msg{padding:6px 16px;border-left:3px solid transparent;transition:background var(--transition-fast)}.chat-msg:hover{background:#ffffff05}.chat-msg--user{border-left-color:var(--accent-green);background:#00ff8808}.chat-msg--assistant{border-left-color:var(--accent-cyan)}.chat-msg--tool-use{border-left-color:var(--accent-yellow);background:#ffd70008}.chat-msg--tool-result{border-left-color:var(--text-muted)}.chat-msg__meta{display:flex;align-items:center;gap:8px;margin-bottom:4px}.chat-msg__role{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;font-family:var(--font-mono)}.chat-msg--user .chat-msg__role{color:var(--accent-green)}.chat-msg--assistant .chat-msg__role{color:var(--accent-cyan)}.chat-msg--tool-use .chat-msg__role{color:var(--accent-yellow)}.chat-msg--tool-result .chat-msg__role{color:var(--text-muted)}.chat-msg__time{font-size:10px;color:var(--text-muted);font-family:var(--font-mono)}.chat-msg__body{font-size:12px;line-height:1.6;word-break:break-word}.msg-prose{color:var(--text-primary);white-space:pre-wrap}.chat-msg--assistant .msg-prose{color:var(--text-primary)}.msg-code{background:var(--bg-secondary);border:1px solid var(--border-subtle);border-radius:var(--radius-sm);padding:8px 10px;font-size:11px;white-space:pre-wrap;overflow-x:auto;color:var(--text-primary);margin-top:2px}.msg-expand-btn{border:none;background:transparent;color:var(--text-muted);font-family:var(--font-mono);font-size:11px;cursor:pointer;padding:2px 0;margin-top:4px;transition:color var(--transition-fast)}.msg-expand-btn:hover{color:var(--text-secondary)}.msg-tool-use{margin-top:2px}.msg-tool-header{display:flex;align-items:center;gap:6px;border:none;background:transparent;cursor:pointer;padding:3px 0;font-family:var(--font-mono)}.msg-tool-name{display:inline-block;padding:2px 8px;background:#ffd7001f;border:1px solid rgba(255,215,0,.3);color:var(--accent-yellow);border-radius:var(--radius-sm);font-size:11px;font-weight:600;font-family:var(--font-mono)}.msg-tool-toggle{font-size:11px;color:var(--text-muted)}.msg-tool-body{background:var(--bg-secondary);border:1px solid rgba(255,215,0,.15);border-radius:var(--radius-sm);padding:8px 10px;font-size:11px;white-space:pre-wrap;overflow-x:auto;color:var(--text-secondary);margin-top:4px;max-height:300px;overflow-y:auto}.msg-tool-result{margin-top:2px}.msg-error-badge{display:inline-block;padding:1px 5px;background:#ff444426;color:var(--accent-red);border-radius:var(--radius-sm);font-size:10px;font-weight:700;margin-bottom:4px;font-family:var(--font-mono)}.msg-result-body{font-size:11px;white-space:pre-wrap;overflow-x:auto;color:var(--text-muted);line-height:1.5;max-height:200px;overflow-y:auto}.msg-tool-result--error .msg-result-body{color:#ff4444b3}.agents-panel__session{display:flex;align-items:center;gap:8px;padding:3px 8px;border-left:1px solid var(--border-subtle);margin-left:4px;width:100%;border-radius:0 var(--radius-sm) var(--radius-sm) 0;background:transparent;cursor:pointer;font-family:var(--font-mono);transition:background var(--transition-fast);border-top:none;border-right:none;border-bottom:none}.agents-panel__session:hover{background:var(--bg-hover)}.agents-panel__session--active{background:var(--bg-active);border-left-color:var(--accent-purple)}.agent-panel{display:flex;flex-direction:column;height:100%}.agent-panel__header{display:flex;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:12px;padding-bottom:12px;border-bottom:1px solid var(--border-primary)}.agent-panel__header .panel-title{margin-bottom:0}.status-badge{display:inline-block;padding:2px 8px;border-radius:10px;font-size:11px;font-weight:600}.status-badge--active{background:#00ff8826;color:var(--accent-green)}.status-badge--idle{background:#ffd70026;color:var(--accent-yellow)}.status-badge--done{background:#00d4ff26;color:var(--accent-cyan)}.status-badge--unknown{background:#5555554d;color:var(--text-muted)}.agent-panel__tasks{padding:8px 12px;margin-bottom:12px;background:var(--bg-card);border-radius:var(--radius-md);border:1px solid var(--border-primary)}.agent-panel__task-item{display:flex;align-items:center;gap:8px;padding:4px 0;font-size:12px}.task-status-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0}.task-status-dot--pending{background:var(--text-muted)}.task-status-dot--in_progress{background:var(--accent-yellow)}.task-status-dot--completed{background:var(--accent-green)}.agent-panel__feed{flex:1;overflow-y:auto;padding:4px}.activity-entry{padding:8px 12px;margin-bottom:4px;border-radius:var(--radius-sm);font-size:12px}.activity-entry--user{border-left:3px solid var(--accent-green);background:#00ff880d}.activity-entry--assistant{color:var(--accent-cyan)}.activity-entry--tool-use{background:#ffd7000d}.activity-entry--tool-result{color:var(--text-muted)}.activity-entry__header{display:flex;justify-content:space-between;align-items:center;margin-bottom:4px}.activity-entry__role{color:var(--text-muted);text-transform:uppercase;letter-spacing:.05em}.activity-entry__body{word-break:break-word}.activity-entry__code{background:var(--bg-secondary);padding:8px;border-radius:var(--radius-sm);overflow-x:auto;font-size:11px;white-space:pre-wrap;margin-top:4px}.activity-entry__tool-use{display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}.activity-entry__tool-badge{display:inline-block;padding:2px 6px;background:#ffd70026;color:var(--accent-yellow);border-radius:var(--radius-sm);font-size:11px;white-space:nowrap}.activity-entry__tool-input{font-size:11px;word-break:break-all}.activity-entry__tool-result{font-size:11px;line-height:1.4}