agent-teams-dashboard 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/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-Ddn7oByj.js"></script>
8
- <link rel="stylesheet" crossorigin href="/assets/index-DyZplrwc.css">
7
+ <script type="module" crossorigin src="/assets/index-C2fnhLSE.js"></script>
8
+ <link rel="stylesheet" crossorigin href="/assets/index-BqtV8ETR.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.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Real-time monitoring dashboard for Claude Code agent teams",
5
5
  "type": "module",
6
6
  "author": "pingshian0131",
@@ -138,24 +138,31 @@ async function refreshAllTasks() {
138
138
  }
139
139
  }
140
140
  // --- Agent JSONL scanning ---
141
+ // Scan both subagent JSONL (agent-*.jsonl) and team session JSONL (UUID.jsonl with teamName)
141
142
  export async function scanAgentJsonl() {
142
143
  const projectDirs = await safeReaddir(PROJECTS_DIR);
143
144
  for (const projDir of projectDirs) {
144
145
  const projPath = join(PROJECTS_DIR, projDir);
145
- const sessionDirs = await safeReaddir(projPath);
146
- for (const sessionDir of sessionDirs) {
147
- const subagentsDir = join(projPath, sessionDir, 'subagents');
146
+ const entries = await safeReaddir(projPath);
147
+ for (const entry of entries) {
148
+ const entryPath = join(projPath, entry);
149
+ // Team session JSONL: UUID.jsonl files at project root level
150
+ if (entry.endsWith('.jsonl')) {
151
+ await readNewEntries(entryPath, true);
152
+ continue;
153
+ }
154
+ // Subagent JSONL: agent-*.jsonl under session/subagents/
155
+ const subagentsDir = join(entryPath, 'subagents');
148
156
  const files = await safeReaddir(subagentsDir);
149
157
  for (const file of files) {
150
158
  if (!file.startsWith('agent-') || !file.endsWith('.jsonl'))
151
159
  continue;
152
- const filePath = join(subagentsDir, file);
153
- await readNewEntries(filePath);
160
+ await readNewEntries(join(subagentsDir, file), false);
154
161
  }
155
162
  }
156
163
  }
157
164
  }
158
- async function readNewEntries(filePath) {
165
+ async function readNewEntries(filePath, isSessionFile) {
159
166
  const fileStat = await safeFileStat(filePath);
160
167
  if (!fileStat)
161
168
  return;
@@ -166,13 +173,48 @@ async function readNewEntries(filePath) {
166
173
  const raw = await safeReadFile(filePath);
167
174
  if (!raw)
168
175
  return;
169
- // Read only from the offset position
170
176
  const newContent = raw.slice(currentOffset);
171
177
  agentOffsets.set(filePath, fileSize);
172
178
  const lines = newContent.split('\n').filter(Boolean);
173
179
  for (const line of lines) {
174
180
  try {
175
181
  const parsed = JSON.parse(line);
182
+ // For session files, only process entries that belong to a team agent
183
+ if (isSessionFile) {
184
+ const teamName = parsed.teamName;
185
+ const agentName = parsed.agentName;
186
+ if (!teamName || !agentName)
187
+ continue;
188
+ // Use team agentId format: name@team
189
+ const fullAgentId = `${agentName}@${teamName}`;
190
+ const entry = {
191
+ agentId: fullAgentId,
192
+ slug: agentName,
193
+ sessionId: parsed.sessionId ?? '',
194
+ type: parsed.type ?? 'assistant',
195
+ message: {
196
+ role: parsed.message?.role ?? '',
197
+ content: Array.isArray(parsed.message?.content)
198
+ ? parsed.message.content
199
+ : typeof parsed.message?.content === 'string'
200
+ ? [{ type: 'text', text: parsed.message.content }]
201
+ : [],
202
+ model: parsed.message?.model,
203
+ },
204
+ timestamp: parsed.timestamp ?? '',
205
+ };
206
+ let arr = agentEntries.get(fullAgentId);
207
+ if (!arr) {
208
+ arr = [];
209
+ agentEntries.set(fullAgentId, arr);
210
+ }
211
+ arr.push(entry);
212
+ if (arr.length > MAX_ENTRIES_PER_AGENT) {
213
+ arr.splice(0, arr.length - MAX_ENTRIES_PER_AGENT);
214
+ }
215
+ continue;
216
+ }
217
+ // Subagent JSONL: use agentId from the file
176
218
  const entry = {
177
219
  agentId: parsed.agentId ?? '',
178
220
  slug: parsed.slug ?? '',
@@ -191,16 +233,14 @@ async function readNewEntries(filePath) {
191
233
  };
192
234
  if (!entry.agentId)
193
235
  continue;
194
- let entries = agentEntries.get(entry.agentId);
195
- if (!entries) {
196
- entries = [];
197
- agentEntries.set(entry.agentId, entries);
236
+ let arr = agentEntries.get(entry.agentId);
237
+ if (!arr) {
238
+ arr = [];
239
+ agentEntries.set(entry.agentId, arr);
198
240
  }
199
- entries.push(entry);
200
- // Trim to max entries
201
- if (entries.length > MAX_ENTRIES_PER_AGENT) {
202
- const excess = entries.length - MAX_ENTRIES_PER_AGENT;
203
- entries.splice(0, excess);
241
+ arr.push(entry);
242
+ if (arr.length > MAX_ENTRIES_PER_AGENT) {
243
+ arr.splice(0, arr.length - MAX_ENTRIES_PER_AGENT);
204
244
  }
205
245
  }
206
246
  catch {
@@ -257,12 +297,20 @@ function buildTeamOverview(teamName) {
257
297
  export function getSnapshot() {
258
298
  const teamOverviews = [];
259
299
  const matchedAgentIds = new Set();
300
+ // Map full agentId (name@team) -> resolved entries
301
+ const activity = {};
260
302
  for (const teamName of teams.keys()) {
261
303
  const overview = buildTeamOverview(teamName);
262
304
  teamOverviews.push(overview);
263
305
  for (const member of overview.config.members) {
264
306
  matchedAgentIds.add(member.agentId);
265
- matchedAgentIds.add(member.agentId.split('@')[0]);
307
+ const shortId = member.agentId.split('@')[0];
308
+ matchedAgentIds.add(shortId);
309
+ // Resolve: try full agentId first, then short hash
310
+ const entries = agentEntries.get(member.agentId) ?? agentEntries.get(shortId);
311
+ if (entries && entries.length > 0) {
312
+ activity[member.agentId] = entries;
313
+ }
266
314
  }
267
315
  }
268
316
  // Find unmatched agents
@@ -275,9 +323,10 @@ export function getSnapshot() {
275
323
  slug: last.slug,
276
324
  sessionId: last.sessionId,
277
325
  });
326
+ activity[agentId] = entries;
278
327
  }
279
328
  }
280
- return { teams: teamOverviews, unmatchedAgents };
329
+ return { teams: teamOverviews, unmatchedAgents, agentActivity: activity };
281
330
  }
282
331
  // --- Query ---
283
332
  export function getAgentActivity(agentId) {