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-
|
|
8
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
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
|
@@ -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
|
|
146
|
-
for (const
|
|
147
|
-
const
|
|
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
|
-
|
|
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
|
|
195
|
-
if (!
|
|
196
|
-
|
|
197
|
-
agentEntries.set(entry.agentId,
|
|
236
|
+
let arr = agentEntries.get(entry.agentId);
|
|
237
|
+
if (!arr) {
|
|
238
|
+
arr = [];
|
|
239
|
+
agentEntries.set(entry.agentId, arr);
|
|
198
240
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
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
|
-
|
|
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) {
|