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.
- package/README.md +3 -0
- package/README.zh-TW.md +3 -0
- package/dist/assets/index-CEXrdfKk.js +51 -0
- package/dist/assets/index-CsK61Xi-.css +1 -0
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/server-dist/server/teamsCache.js +166 -14
- package/dist/assets/index-BqtV8ETR.css +0 -1
- package/dist/assets/index-C2fnhLSE.js +0 -51
|
@@ -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-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
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,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
|
-
|
|
174
|
-
|
|
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
|
-
|
|
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,
|
|
199
|
+
// For session files, process team entries AND regular conversation entries
|
|
183
200
|
if (isSessionFile) {
|
|
184
201
|
const teamName = parsed.teamName;
|
|
185
|
-
|
|
186
|
-
if (!
|
|
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
|
-
|
|
189
|
-
|
|
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
|
|
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}
|