claude-mpm 4.1.21__py3-none-any.whl → 4.1.23__py3-none-any.whl
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.
- claude_mpm/VERSION +1 -1
- claude_mpm/dashboard/static/css/activity.css +252 -0
- claude_mpm/dashboard/static/dist/chunks/unified-data-viewer.CvAmgM3l.js +2 -0
- claude_mpm/dashboard/static/dist/components/activity-tree.js +1 -1
- claude_mpm/dashboard/static/dist/components/code-tree.js +1 -1
- claude_mpm/dashboard/static/dist/components/module-viewer.js +1 -1
- claude_mpm/dashboard/static/dist/dashboard.js +1 -1
- claude_mpm/dashboard/static/js/components/activity-tree.js +140 -51
- claude_mpm/dashboard/static/js/components/unified-data-viewer.js +377 -132
- claude_mpm/services/agents/deployment/agent_version_manager.py +6 -1
- {claude_mpm-4.1.21.dist-info → claude_mpm-4.1.23.dist-info}/METADATA +1 -1
- {claude_mpm-4.1.21.dist-info → claude_mpm-4.1.23.dist-info}/RECORD +16 -15
- {claude_mpm-4.1.21.dist-info → claude_mpm-4.1.23.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.21.dist-info → claude_mpm-4.1.23.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.21.dist-info → claude_mpm-4.1.23.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.21.dist-info → claude_mpm-4.1.23.dist-info}/top_level.txt +0 -0
|
@@ -134,6 +134,8 @@ class UnifiedDataViewer {
|
|
|
134
134
|
|
|
135
135
|
/**
|
|
136
136
|
* Display event data with comprehensive formatting
|
|
137
|
+
* PRIMARY: Event type, timestamp, and key details
|
|
138
|
+
* SECONDARY: Full event data in collapsible JSON
|
|
137
139
|
*/
|
|
138
140
|
displayEvent(data) {
|
|
139
141
|
const eventType = this.formatEventType(data);
|
|
@@ -147,19 +149,45 @@ class UnifiedDataViewer {
|
|
|
147
149
|
<div class="unified-viewer-content">
|
|
148
150
|
`;
|
|
149
151
|
|
|
150
|
-
// Event-specific details
|
|
152
|
+
// PRIMARY DATA: Event-specific key details
|
|
153
|
+
html += `<div class="primary-data">`;
|
|
151
154
|
html += this.formatEventDetails(data);
|
|
152
|
-
|
|
153
|
-
//
|
|
154
|
-
if (data.
|
|
155
|
-
const
|
|
156
|
-
html +=
|
|
155
|
+
|
|
156
|
+
// Show important tool parameters inline if present
|
|
157
|
+
if (data.tool_name || data.data?.tool_name) {
|
|
158
|
+
const toolName = data.tool_name || data.data.tool_name;
|
|
159
|
+
html += `
|
|
160
|
+
<div class="detail-row highlight">
|
|
161
|
+
<span class="detail-label">Tool:</span>
|
|
162
|
+
<span class="detail-value">${this.getToolIcon(toolName)} ${toolName}</span>
|
|
163
|
+
</div>
|
|
164
|
+
`;
|
|
165
|
+
|
|
166
|
+
// Show key parameters for specific tools
|
|
167
|
+
const params = data.tool_parameters || data.data?.tool_parameters;
|
|
168
|
+
if (params) {
|
|
169
|
+
if (params.file_path) {
|
|
170
|
+
html += `
|
|
171
|
+
<div class="detail-row">
|
|
172
|
+
<span class="detail-label">File:</span>
|
|
173
|
+
<span class="detail-value code">${params.file_path}</span>
|
|
174
|
+
</div>
|
|
175
|
+
`;
|
|
176
|
+
}
|
|
177
|
+
if (params.command) {
|
|
178
|
+
html += `
|
|
179
|
+
<div class="detail-row">
|
|
180
|
+
<span class="detail-label">Command:</span>
|
|
181
|
+
<pre class="code-snippet">${this.escapeHtml(params.command)}</pre>
|
|
182
|
+
</div>
|
|
183
|
+
`;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
157
186
|
}
|
|
187
|
+
html += `</div>`;
|
|
158
188
|
|
|
159
|
-
//
|
|
160
|
-
|
|
161
|
-
html += this.formatEventData(data);
|
|
162
|
-
}
|
|
189
|
+
// SECONDARY DATA: Collapsible JSON viewer for full event data
|
|
190
|
+
html += this.createCollapsibleJSON(data, 'Full Event Data');
|
|
163
191
|
|
|
164
192
|
html += '</div>';
|
|
165
193
|
this.container.innerHTML = html;
|
|
@@ -167,212 +195,353 @@ class UnifiedDataViewer {
|
|
|
167
195
|
|
|
168
196
|
/**
|
|
169
197
|
* Display agent data with full details
|
|
198
|
+
* PRIMARY: Agent status, active tools, and key info
|
|
199
|
+
* SECONDARY: Full agent data in collapsible JSON
|
|
170
200
|
*/
|
|
171
201
|
displayAgent(data) {
|
|
172
202
|
const agentIcon = this.getAgentIcon(data.name || data.agentName);
|
|
203
|
+
const agentName = data.name || data.agentName || 'Unknown Agent';
|
|
173
204
|
const status = this.formatStatus(data.status);
|
|
174
205
|
|
|
175
206
|
let html = `
|
|
176
207
|
<div class="unified-viewer-header">
|
|
177
|
-
<h6>${agentIcon} ${
|
|
208
|
+
<h6>${agentIcon} ${agentName}</h6>
|
|
178
209
|
<span class="unified-viewer-status">${status}</span>
|
|
179
210
|
</div>
|
|
180
211
|
<div class="unified-viewer-content">
|
|
181
|
-
<div class="detail-row">
|
|
182
|
-
<span class="detail-label">Status:</span>
|
|
183
|
-
<span class="detail-value">${status}</span>
|
|
184
|
-
</div>
|
|
185
|
-
<div class="detail-row">
|
|
186
|
-
<span class="detail-label">Session ID:</span>
|
|
187
|
-
<span class="detail-value">${data.sessionId || data.session_id || 'N/A'}</span>
|
|
188
|
-
</div>
|
|
189
|
-
<div class="detail-row">
|
|
190
|
-
<span class="detail-label">Timestamp:</span>
|
|
191
|
-
<span class="detail-value">${this.formatTimestamp(data.timestamp)}</span>
|
|
192
|
-
</div>
|
|
193
212
|
`;
|
|
194
213
|
|
|
195
|
-
//
|
|
214
|
+
// PRIMARY DATA: Key agent information
|
|
215
|
+
html += `<div class="primary-data">`;
|
|
216
|
+
|
|
217
|
+
// Status with visual indicator
|
|
218
|
+
html += `
|
|
219
|
+
<div class="detail-row highlight">
|
|
220
|
+
<span class="detail-label">Status:</span>
|
|
221
|
+
<span class="detail-value ${this.formatStatusClass(status)}">${status}</span>
|
|
222
|
+
</div>
|
|
223
|
+
`;
|
|
224
|
+
|
|
225
|
+
// Tools summary if present
|
|
196
226
|
if (data.tools && data.tools.length > 0) {
|
|
227
|
+
// Show active tools prominently
|
|
228
|
+
const activeTools = data.tools.filter(t => t.status === 'in_progress');
|
|
229
|
+
const completedTools = data.tools.filter(t => t.status === 'completed');
|
|
230
|
+
|
|
231
|
+
if (activeTools.length > 0) {
|
|
232
|
+
html += `
|
|
233
|
+
<div class="active-tools-section">
|
|
234
|
+
<span class="section-label">🔄 Active Tools:</span>
|
|
235
|
+
<div class="tools-grid">
|
|
236
|
+
`;
|
|
237
|
+
activeTools.forEach(tool => {
|
|
238
|
+
html += `
|
|
239
|
+
<div class="tool-chip active">
|
|
240
|
+
${this.getToolIcon(tool.name)} ${tool.name}
|
|
241
|
+
</div>
|
|
242
|
+
`;
|
|
243
|
+
});
|
|
244
|
+
html += `</div></div>`;
|
|
245
|
+
}
|
|
246
|
+
|
|
197
247
|
html += `
|
|
198
|
-
<div class="detail-
|
|
199
|
-
<span class="detail-
|
|
200
|
-
<
|
|
201
|
-
${data.tools.
|
|
202
|
-
|
|
203
|
-
<span class="tool-icon">${this.getToolIcon(tool.name)}</span>
|
|
204
|
-
<span class="tool-name">${tool.name}</span>
|
|
205
|
-
<span class="tool-status ${this.formatStatusClass(tool.status)}">${tool.status}</span>
|
|
206
|
-
</div>
|
|
207
|
-
`).join('')}
|
|
208
|
-
</div>
|
|
248
|
+
<div class="detail-row">
|
|
249
|
+
<span class="detail-label">Tools Summary:</span>
|
|
250
|
+
<span class="detail-value">
|
|
251
|
+
${activeTools.length} active, ${completedTools.length} completed, ${data.tools.length} total
|
|
252
|
+
</span>
|
|
209
253
|
</div>
|
|
210
254
|
`;
|
|
211
255
|
}
|
|
212
256
|
|
|
257
|
+
// Current task if available
|
|
258
|
+
if (data.currentTask || data.description) {
|
|
259
|
+
html += `
|
|
260
|
+
<div class="detail-row">
|
|
261
|
+
<span class="detail-label">Current Task:</span>
|
|
262
|
+
<span class="detail-value">${data.currentTask || data.description}</span>
|
|
263
|
+
</div>
|
|
264
|
+
`;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
html += `</div>`;
|
|
268
|
+
|
|
269
|
+
// SECONDARY DATA: Collapsible JSON viewer
|
|
270
|
+
html += this.createCollapsibleJSON(data, 'Full Agent Details');
|
|
271
|
+
|
|
213
272
|
html += '</div>';
|
|
214
273
|
this.container.innerHTML = html;
|
|
215
274
|
}
|
|
216
275
|
|
|
217
276
|
/**
|
|
218
277
|
* Display tool data with parameters and results
|
|
278
|
+
* Special handling for TodoWrite to show todos prominently
|
|
219
279
|
*/
|
|
220
280
|
displayTool(data) {
|
|
221
|
-
const
|
|
281
|
+
const toolName = data.name || data.tool_name || 'Unknown Tool';
|
|
282
|
+
const toolIcon = this.getToolIcon(toolName);
|
|
222
283
|
const status = this.formatStatus(data.status);
|
|
223
284
|
|
|
285
|
+
// Special handling for TodoWrite tool
|
|
286
|
+
if (toolName === 'TodoWrite') {
|
|
287
|
+
this.displayTodoWriteTool(data);
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
224
291
|
let html = `
|
|
225
292
|
<div class="unified-viewer-header">
|
|
226
|
-
<h6>${toolIcon} ${
|
|
293
|
+
<h6>${toolIcon} ${toolName}</h6>
|
|
227
294
|
<span class="unified-viewer-status">${status}</span>
|
|
228
295
|
</div>
|
|
229
296
|
<div class="unified-viewer-content">
|
|
297
|
+
`;
|
|
298
|
+
|
|
299
|
+
// PRIMARY DATA: Show important tool-specific information first
|
|
300
|
+
const params = data.params || data.tool_parameters || {};
|
|
301
|
+
|
|
302
|
+
// Tool-specific primary data display
|
|
303
|
+
if (toolName === 'Read' || toolName === 'Edit' || toolName === 'Write') {
|
|
304
|
+
// File tools - show file path prominently
|
|
305
|
+
if (params.file_path) {
|
|
306
|
+
html += `
|
|
307
|
+
<div class="primary-data">
|
|
308
|
+
<div class="detail-row highlight">
|
|
309
|
+
<span class="detail-label">📁 File:</span>
|
|
310
|
+
<span class="detail-value code">${params.file_path}</span>
|
|
311
|
+
</div>
|
|
312
|
+
`;
|
|
313
|
+
if (params.old_string) {
|
|
314
|
+
html += `
|
|
315
|
+
<div class="detail-row">
|
|
316
|
+
<span class="detail-label">Old Text:</span>
|
|
317
|
+
<pre class="code-snippet">${this.escapeHtml(params.old_string.substring(0, 200))}${params.old_string.length > 200 ? '...' : ''}</pre>
|
|
318
|
+
</div>
|
|
319
|
+
`;
|
|
320
|
+
}
|
|
321
|
+
if (params.new_string) {
|
|
322
|
+
html += `
|
|
323
|
+
<div class="detail-row">
|
|
324
|
+
<span class="detail-label">New Text:</span>
|
|
325
|
+
<pre class="code-snippet">${this.escapeHtml(params.new_string.substring(0, 200))}${params.new_string.length > 200 ? '...' : ''}</pre>
|
|
326
|
+
</div>
|
|
327
|
+
`;
|
|
328
|
+
}
|
|
329
|
+
html += '</div>';
|
|
330
|
+
}
|
|
331
|
+
} else if (toolName === 'Bash') {
|
|
332
|
+
// Bash tool - show command prominently
|
|
333
|
+
if (params.command) {
|
|
334
|
+
html += `
|
|
335
|
+
<div class="primary-data">
|
|
336
|
+
<div class="detail-row highlight">
|
|
337
|
+
<span class="detail-label">💻 Command:</span>
|
|
338
|
+
<pre class="code-snippet">${this.escapeHtml(params.command)}</pre>
|
|
339
|
+
</div>
|
|
340
|
+
</div>
|
|
341
|
+
`;
|
|
342
|
+
}
|
|
343
|
+
} else if (toolName === 'Grep' || toolName === 'Glob') {
|
|
344
|
+
// Search tools - show pattern prominently
|
|
345
|
+
if (params.pattern) {
|
|
346
|
+
html += `
|
|
347
|
+
<div class="primary-data">
|
|
348
|
+
<div class="detail-row highlight">
|
|
349
|
+
<span class="detail-label">🔍 Pattern:</span>
|
|
350
|
+
<span class="detail-value code">${this.escapeHtml(params.pattern)}</span>
|
|
351
|
+
</div>
|
|
352
|
+
`;
|
|
353
|
+
if (params.path) {
|
|
354
|
+
html += `
|
|
355
|
+
<div class="detail-row">
|
|
356
|
+
<span class="detail-label">Path:</span>
|
|
357
|
+
<span class="detail-value">${params.path}</span>
|
|
358
|
+
</div>
|
|
359
|
+
`;
|
|
360
|
+
}
|
|
361
|
+
html += '</div>';
|
|
362
|
+
}
|
|
363
|
+
} else if (toolName === 'Task') {
|
|
364
|
+
// Task tool - show delegation info prominently
|
|
365
|
+
if (params.subagent_type) {
|
|
366
|
+
html += `
|
|
367
|
+
<div class="primary-data">
|
|
368
|
+
<div class="detail-row highlight">
|
|
369
|
+
<span class="detail-label">🤖 Delegating to:</span>
|
|
370
|
+
<span class="detail-value">${params.subagent_type} agent</span>
|
|
371
|
+
</div>
|
|
372
|
+
`;
|
|
373
|
+
if (params.description) {
|
|
374
|
+
html += `
|
|
375
|
+
<div class="detail-row">
|
|
376
|
+
<span class="detail-label">Task:</span>
|
|
377
|
+
<span class="detail-value">${params.description}</span>
|
|
378
|
+
</div>
|
|
379
|
+
`;
|
|
380
|
+
}
|
|
381
|
+
html += '</div>';
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// Status and metadata
|
|
386
|
+
html += `
|
|
387
|
+
<div class="detail-row">
|
|
388
|
+
<span class="detail-label">Status:</span>
|
|
389
|
+
<span class="detail-value">${status}</span>
|
|
390
|
+
</div>
|
|
391
|
+
`;
|
|
392
|
+
|
|
393
|
+
if (data.callCount) {
|
|
394
|
+
html += `
|
|
230
395
|
<div class="detail-row">
|
|
231
|
-
<span class="detail-label">
|
|
232
|
-
<span class="detail-value"
|
|
233
|
-
</div>
|
|
234
|
-
<div class="detail-row">
|
|
235
|
-
<span class="detail-label">Name:</span>
|
|
236
|
-
<span class="detail-value">${data.name || data.tool_name || 'Unknown Tool'}</span>
|
|
237
|
-
</div>
|
|
238
|
-
<div class="detail-row">
|
|
239
|
-
<span class="detail-label">Status:</span>
|
|
240
|
-
<span class="detail-value">${status}</span>
|
|
396
|
+
<span class="detail-label">Call Count:</span>
|
|
397
|
+
<span class="detail-value">${data.callCount}</span>
|
|
241
398
|
</div>
|
|
399
|
+
`;
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Collapsible JSON viewer for full details
|
|
403
|
+
html += this.createCollapsibleJSON(data, 'Full Tool Details');
|
|
404
|
+
|
|
405
|
+
html += '</div>';
|
|
406
|
+
this.container.innerHTML = html;
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Display TodoWrite tool with todos list prominently after title
|
|
411
|
+
*/
|
|
412
|
+
displayTodoWriteTool(data) {
|
|
413
|
+
const status = this.formatStatus(data.status);
|
|
414
|
+
const params = data.params || data.tool_parameters || {};
|
|
415
|
+
const todos = params.todos || [];
|
|
416
|
+
|
|
417
|
+
let html = `
|
|
418
|
+
<div class="unified-viewer-header">
|
|
419
|
+
<h6>📝 TodoWrite</h6>
|
|
420
|
+
<span class="unified-viewer-status">${status}</span>
|
|
421
|
+
</div>
|
|
422
|
+
<div class="unified-viewer-content">
|
|
242
423
|
`;
|
|
243
424
|
|
|
244
|
-
//
|
|
245
|
-
if (
|
|
246
|
-
const
|
|
247
|
-
|
|
248
|
-
|
|
425
|
+
// PRIMARY DATA: Todo list and status summary immediately after title
|
|
426
|
+
if (todos.length > 0) {
|
|
427
|
+
const statusCounts = this.getTodoStatusCounts(todos);
|
|
428
|
+
|
|
429
|
+
// Status summary bar
|
|
430
|
+
html += `
|
|
431
|
+
<div class="todo-status-bar">
|
|
432
|
+
<div class="status-item completed">
|
|
433
|
+
<span class="status-icon">✅</span>
|
|
434
|
+
<span class="status-count">${statusCounts.completed}</span>
|
|
435
|
+
<span class="status-label">Done</span>
|
|
436
|
+
</div>
|
|
437
|
+
<div class="status-item in_progress">
|
|
438
|
+
<span class="status-icon">🔄</span>
|
|
439
|
+
<span class="status-count">${statusCounts.in_progress}</span>
|
|
440
|
+
<span class="status-label">Active</span>
|
|
441
|
+
</div>
|
|
442
|
+
<div class="status-item pending">
|
|
443
|
+
<span class="status-icon">⏳</span>
|
|
444
|
+
<span class="status-count">${statusCounts.pending}</span>
|
|
445
|
+
<span class="status-label">Pending</span>
|
|
446
|
+
</div>
|
|
447
|
+
</div>
|
|
448
|
+
`;
|
|
249
449
|
|
|
250
|
-
|
|
251
|
-
|
|
450
|
+
// Todo items list
|
|
451
|
+
html += `
|
|
452
|
+
<div class="todo-list-primary">
|
|
453
|
+
`;
|
|
454
|
+
|
|
455
|
+
todos.forEach((todo, index) => {
|
|
456
|
+
const statusIcon = this.getCheckboxIcon(todo.status);
|
|
457
|
+
const displayText = todo.status === 'in_progress' ?
|
|
458
|
+
(todo.activeForm || todo.content) : todo.content;
|
|
459
|
+
const statusClass = this.formatStatusClass(todo.status);
|
|
460
|
+
|
|
461
|
+
html += `
|
|
462
|
+
<div class="todo-item ${todo.status}">
|
|
463
|
+
<span class="todo-icon ${statusClass}">${statusIcon}</span>
|
|
464
|
+
<span class="todo-text">${this.escapeHtml(displayText)}</span>
|
|
465
|
+
${todo.status === 'in_progress' ? '<span class="todo-badge active">ACTIVE</span>' : ''}
|
|
466
|
+
</div>
|
|
467
|
+
`;
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
html += `
|
|
471
|
+
</div>
|
|
472
|
+
`;
|
|
473
|
+
} else {
|
|
252
474
|
html += `
|
|
253
475
|
<div class="detail-row">
|
|
254
|
-
<span class="detail-
|
|
255
|
-
<span class="detail-value">${this.formatTimestamp(data.timestamp)}</span>
|
|
476
|
+
<span class="detail-value">No todos in list</span>
|
|
256
477
|
</div>
|
|
257
478
|
`;
|
|
258
479
|
}
|
|
259
480
|
|
|
260
|
-
//
|
|
261
|
-
if (data.
|
|
481
|
+
// Metadata section
|
|
482
|
+
if (data.callCount && data.callCount > 1) {
|
|
262
483
|
html += `
|
|
263
|
-
<div class="detail-
|
|
264
|
-
<span class="detail-
|
|
265
|
-
<
|
|
484
|
+
<div class="detail-row">
|
|
485
|
+
<span class="detail-label">Updates:</span>
|
|
486
|
+
<span class="detail-value">${data.callCount}</span>
|
|
266
487
|
</div>
|
|
267
488
|
`;
|
|
268
489
|
}
|
|
269
490
|
|
|
491
|
+
// Collapsible JSON viewer for full details
|
|
492
|
+
html += this.createCollapsibleJSON(data, 'Full Details');
|
|
493
|
+
|
|
270
494
|
html += '</div>';
|
|
271
495
|
this.container.innerHTML = html;
|
|
272
496
|
}
|
|
273
497
|
|
|
274
498
|
/**
|
|
275
|
-
* Display todo data with checklist formatting
|
|
499
|
+
* Display todo data with checklist formatting (for standalone todos, not TodoWrite)
|
|
276
500
|
*/
|
|
277
501
|
displayTodo(data) {
|
|
278
|
-
// Handle different data structures for
|
|
502
|
+
// Handle different data structures for standalone todos
|
|
279
503
|
let todos;
|
|
280
504
|
let toolName = 'Todo List';
|
|
281
|
-
let timestamp = null;
|
|
282
|
-
let status = null;
|
|
283
505
|
|
|
284
506
|
if (data.todos && Array.isArray(data.todos)) {
|
|
285
|
-
// Direct todo list format
|
|
286
507
|
todos = data.todos;
|
|
287
|
-
} else if (data.tool_parameters && data.tool_parameters.todos) {
|
|
288
|
-
// TodoWrite tool format
|
|
289
|
-
todos = data.tool_parameters.todos;
|
|
290
|
-
toolName = 'TodoWrite';
|
|
291
|
-
timestamp = data.timestamp;
|
|
292
|
-
status = data.status;
|
|
293
508
|
} else if (Array.isArray(data)) {
|
|
294
|
-
// Array of todos
|
|
295
509
|
todos = data;
|
|
296
510
|
} else if (data.content && data.activeForm && data.status) {
|
|
297
|
-
// Single todo item
|
|
298
511
|
todos = [data];
|
|
299
512
|
} else {
|
|
300
|
-
// Fallback
|
|
301
513
|
todos = [];
|
|
302
514
|
}
|
|
303
515
|
|
|
304
516
|
let html = `
|
|
305
517
|
<div class="unified-viewer-header">
|
|
306
|
-
<h6
|
|
307
|
-
${status ? `<span class="unified-viewer-status">${this.formatStatus(status)}</span>` : ''}
|
|
518
|
+
<h6>📋 ${toolName}</h6>
|
|
308
519
|
</div>
|
|
309
520
|
<div class="unified-viewer-content">
|
|
310
521
|
`;
|
|
311
522
|
|
|
312
|
-
// Show timestamp if available
|
|
313
|
-
if (timestamp) {
|
|
314
|
-
html += `
|
|
315
|
-
<div class="detail-row">
|
|
316
|
-
<span class="detail-label">Timestamp:</span>
|
|
317
|
-
<span class="detail-value">${this.formatTimestamp(timestamp)}</span>
|
|
318
|
-
</div>
|
|
319
|
-
`;
|
|
320
|
-
}
|
|
321
|
-
|
|
322
523
|
if (todos.length > 0) {
|
|
323
|
-
//
|
|
324
|
-
const statusCounts = this.getTodoStatusCounts(todos);
|
|
325
|
-
html += `
|
|
326
|
-
<div class="detail-section">
|
|
327
|
-
<span class="detail-section-title">Todo Summary</span>
|
|
328
|
-
<div class="todo-summary">
|
|
329
|
-
<div class="summary-item completed">
|
|
330
|
-
<span class="summary-icon">✅</span>
|
|
331
|
-
<span class="summary-count">${statusCounts.completed}</span>
|
|
332
|
-
<span class="summary-label">Completed</span>
|
|
333
|
-
</div>
|
|
334
|
-
<div class="summary-item in_progress">
|
|
335
|
-
<span class="summary-icon">🔄</span>
|
|
336
|
-
<span class="summary-count">${statusCounts.in_progress}</span>
|
|
337
|
-
<span class="summary-label">In Progress</span>
|
|
338
|
-
</div>
|
|
339
|
-
<div class="summary-item pending">
|
|
340
|
-
<span class="summary-icon">⏳</span>
|
|
341
|
-
<span class="summary-count">${statusCounts.pending}</span>
|
|
342
|
-
<span class="summary-label">Pending</span>
|
|
343
|
-
</div>
|
|
344
|
-
</div>
|
|
345
|
-
</div>
|
|
346
|
-
`;
|
|
347
|
-
|
|
348
|
-
// Enhanced todo items display
|
|
524
|
+
// Show todos immediately
|
|
349
525
|
html += `
|
|
350
|
-
<div class="
|
|
351
|
-
<span class="detail-section-title">Todo List (${todos.length} items)</span>
|
|
352
|
-
<div class="todo-checklist">
|
|
526
|
+
<div class="todo-list-primary">
|
|
353
527
|
`;
|
|
354
528
|
|
|
355
|
-
todos.forEach((todo
|
|
529
|
+
todos.forEach((todo) => {
|
|
356
530
|
const statusIcon = this.getCheckboxIcon(todo.status);
|
|
357
531
|
const displayText = todo.status === 'in_progress' ?
|
|
358
532
|
(todo.activeForm || todo.content) : todo.content;
|
|
359
533
|
const statusClass = this.formatStatusClass(todo.status);
|
|
360
534
|
|
|
361
535
|
html += `
|
|
362
|
-
<div class="todo-
|
|
363
|
-
<
|
|
364
|
-
|
|
365
|
-
</
|
|
366
|
-
<div class="todo-text">
|
|
367
|
-
<span class="todo-content">${this.escapeHtml(displayText)}</span>
|
|
368
|
-
<span class="todo-status-badge ${statusClass}">${todo.status.replace('_', ' ')}</span>
|
|
369
|
-
</div>
|
|
536
|
+
<div class="todo-item ${todo.status}">
|
|
537
|
+
<span class="todo-icon ${statusClass}">${statusIcon}</span>
|
|
538
|
+
<span class="todo-text">${this.escapeHtml(displayText)}</span>
|
|
539
|
+
<span class="todo-status-text ${statusClass}">${todo.status.replace('_', ' ')}</span>
|
|
370
540
|
</div>
|
|
371
541
|
`;
|
|
372
542
|
});
|
|
373
543
|
|
|
374
544
|
html += `
|
|
375
|
-
</div>
|
|
376
545
|
</div>
|
|
377
546
|
`;
|
|
378
547
|
} else {
|
|
@@ -389,6 +558,8 @@ class UnifiedDataViewer {
|
|
|
389
558
|
|
|
390
559
|
/**
|
|
391
560
|
* Display instruction data
|
|
561
|
+
* PRIMARY: Instruction text prominently displayed
|
|
562
|
+
* SECONDARY: Metadata in collapsible section
|
|
392
563
|
*/
|
|
393
564
|
displayInstruction(data) {
|
|
394
565
|
let html = `
|
|
@@ -397,16 +568,27 @@ class UnifiedDataViewer {
|
|
|
397
568
|
<span class="unified-viewer-timestamp">${this.formatTimestamp(data.timestamp)}</span>
|
|
398
569
|
</div>
|
|
399
570
|
<div class="unified-viewer-content">
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
571
|
+
`;
|
|
572
|
+
|
|
573
|
+
// PRIMARY DATA: The instruction text itself
|
|
574
|
+
html += `
|
|
575
|
+
<div class="primary-data">
|
|
576
|
+
<div class="instruction-content">
|
|
577
|
+
${this.escapeHtml(data.text)}
|
|
403
578
|
</div>
|
|
404
|
-
<div class="
|
|
405
|
-
<span class="
|
|
406
|
-
<span class="
|
|
579
|
+
<div class="instruction-meta">
|
|
580
|
+
<span class="meta-item">📏 ${data.text.length} characters</span>
|
|
581
|
+
<span class="meta-item">🕐 ${this.formatTimestamp(data.timestamp)}</span>
|
|
407
582
|
</div>
|
|
408
583
|
</div>
|
|
409
584
|
`;
|
|
585
|
+
|
|
586
|
+
// SECONDARY DATA: Full instruction object if there's more data
|
|
587
|
+
if (Object.keys(data).length > 3) {
|
|
588
|
+
html += this.createCollapsibleJSON(data, 'Full Instruction Data');
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
html += '</div>';
|
|
410
592
|
this.container.innerHTML = html;
|
|
411
593
|
}
|
|
412
594
|
|
|
@@ -1023,6 +1205,69 @@ class UnifiedDataViewer {
|
|
|
1023
1205
|
return div.innerHTML;
|
|
1024
1206
|
}
|
|
1025
1207
|
|
|
1208
|
+
/**
|
|
1209
|
+
* Create a collapsible JSON viewer for secondary details
|
|
1210
|
+
* Provides a clean way to show full data without cluttering the main view
|
|
1211
|
+
*/
|
|
1212
|
+
createCollapsibleJSON(data, title = 'Full Details') {
|
|
1213
|
+
// Generate unique ID for this collapsible section
|
|
1214
|
+
const sectionId = `json-details-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
1215
|
+
|
|
1216
|
+
// Filter out sensitive or overly verbose properties
|
|
1217
|
+
const cleanData = this.cleanDataForDisplay(data);
|
|
1218
|
+
|
|
1219
|
+
return `
|
|
1220
|
+
<div class="collapsible-json-section">
|
|
1221
|
+
<button class="collapsible-json-toggle" onclick="
|
|
1222
|
+
const content = document.getElementById('${sectionId}');
|
|
1223
|
+
const button = this;
|
|
1224
|
+
if (content.style.display === 'none' || content.style.display === '') {
|
|
1225
|
+
content.style.display = 'block';
|
|
1226
|
+
button.classList.add('expanded');
|
|
1227
|
+
button.innerHTML = '▼ ${title}';
|
|
1228
|
+
} else {
|
|
1229
|
+
content.style.display = 'none';
|
|
1230
|
+
button.classList.remove('expanded');
|
|
1231
|
+
button.innerHTML = '▶ ${title}';
|
|
1232
|
+
}
|
|
1233
|
+
">▶ ${title}</button>
|
|
1234
|
+
<div id="${sectionId}" class="collapsible-json-content" style="display: none;">
|
|
1235
|
+
<pre class="json-viewer">${this.escapeHtml(JSON.stringify(cleanData, null, 2))}</pre>
|
|
1236
|
+
</div>
|
|
1237
|
+
</div>
|
|
1238
|
+
`;
|
|
1239
|
+
}
|
|
1240
|
+
|
|
1241
|
+
/**
|
|
1242
|
+
* Clean data for display in JSON viewer
|
|
1243
|
+
* Removes circular references and limits string lengths
|
|
1244
|
+
*/
|
|
1245
|
+
cleanDataForDisplay(data) {
|
|
1246
|
+
const seen = new WeakSet();
|
|
1247
|
+
|
|
1248
|
+
return JSON.parse(JSON.stringify(data, (key, value) => {
|
|
1249
|
+
// Handle circular references
|
|
1250
|
+
if (typeof value === 'object' && value !== null) {
|
|
1251
|
+
if (seen.has(value)) {
|
|
1252
|
+
return '[Circular Reference]';
|
|
1253
|
+
}
|
|
1254
|
+
seen.add(value);
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
// Truncate very long strings
|
|
1258
|
+
if (typeof value === 'string' && value.length > 1000) {
|
|
1259
|
+
return value.substring(0, 1000) + '... [truncated]';
|
|
1260
|
+
}
|
|
1261
|
+
|
|
1262
|
+
// Handle functions
|
|
1263
|
+
if (typeof value === 'function') {
|
|
1264
|
+
return '[Function]';
|
|
1265
|
+
}
|
|
1266
|
+
|
|
1267
|
+
return value;
|
|
1268
|
+
}));
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1026
1271
|
// ==================== PUBLIC API METHODS ====================
|
|
1027
1272
|
|
|
1028
1273
|
/**
|
|
@@ -236,7 +236,12 @@ class AgentVersionManager:
|
|
|
236
236
|
deployed_content = deployed_file.read_text()
|
|
237
237
|
|
|
238
238
|
# Skip non-system agents (user-created)
|
|
239
|
-
|
|
239
|
+
# Check for various author formats used by system agents
|
|
240
|
+
if not any(author in deployed_content.lower() for author in [
|
|
241
|
+
"author: claude-mpm",
|
|
242
|
+
"author: claude mpm team",
|
|
243
|
+
"author: claude mpm"
|
|
244
|
+
]):
|
|
240
245
|
return (False, "not a system agent")
|
|
241
246
|
|
|
242
247
|
# Extract version info from YAML frontmatter
|