claude-mpm 4.1.22__py3-none-any.whl → 4.1.24__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 +272 -0
- claude_mpm/dashboard/static/dist/chunks/unified-data-viewer.B7wmm2bD.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 +365 -132
- {claude_mpm-4.1.22.dist-info → claude_mpm-4.1.24.dist-info}/METADATA +1 -1
- {claude_mpm-4.1.22.dist-info → claude_mpm-4.1.24.dist-info}/RECORD +15 -14
- {claude_mpm-4.1.22.dist-info → claude_mpm-4.1.24.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.22.dist-info → claude_mpm-4.1.24.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.22.dist-info → claude_mpm-4.1.24.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.22.dist-info → claude_mpm-4.1.24.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,341 @@ 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 - horizontal single line format
|
|
430
|
+
html += `
|
|
431
|
+
<div class="todo-status-line">
|
|
432
|
+
<span class="status-inline">✅ ${statusCounts.completed} Done</span>
|
|
433
|
+
<span class="status-inline">🔄 ${statusCounts.in_progress} Active</span>
|
|
434
|
+
<span class="status-inline">⏳ ${statusCounts.pending} Pending</span>
|
|
435
|
+
</div>
|
|
436
|
+
`;
|
|
249
437
|
|
|
250
|
-
|
|
251
|
-
|
|
438
|
+
// Todo items list
|
|
439
|
+
html += `
|
|
440
|
+
<div class="todo-list-primary">
|
|
441
|
+
`;
|
|
442
|
+
|
|
443
|
+
todos.forEach((todo, index) => {
|
|
444
|
+
const statusIcon = this.getCheckboxIcon(todo.status);
|
|
445
|
+
const displayText = todo.status === 'in_progress' ?
|
|
446
|
+
(todo.activeForm || todo.content) : todo.content;
|
|
447
|
+
const statusClass = this.formatStatusClass(todo.status);
|
|
448
|
+
|
|
449
|
+
html += `
|
|
450
|
+
<div class="todo-item ${todo.status}">
|
|
451
|
+
<span class="todo-icon ${statusClass}">${statusIcon}</span>
|
|
452
|
+
<span class="todo-text">${this.escapeHtml(displayText)}</span>
|
|
453
|
+
${todo.status === 'in_progress' ? '<span class="todo-badge active">ACTIVE</span>' : ''}
|
|
454
|
+
</div>
|
|
455
|
+
`;
|
|
456
|
+
});
|
|
457
|
+
|
|
458
|
+
html += `
|
|
459
|
+
</div>
|
|
460
|
+
`;
|
|
461
|
+
} else {
|
|
252
462
|
html += `
|
|
253
463
|
<div class="detail-row">
|
|
254
|
-
<span class="detail-
|
|
255
|
-
<span class="detail-value">${this.formatTimestamp(data.timestamp)}</span>
|
|
464
|
+
<span class="detail-value">No todos in list</span>
|
|
256
465
|
</div>
|
|
257
466
|
`;
|
|
258
467
|
}
|
|
259
468
|
|
|
260
|
-
//
|
|
261
|
-
if (data.
|
|
469
|
+
// Metadata section
|
|
470
|
+
if (data.callCount && data.callCount > 1) {
|
|
262
471
|
html += `
|
|
263
|
-
<div class="detail-
|
|
264
|
-
<span class="detail-
|
|
265
|
-
<
|
|
472
|
+
<div class="detail-row">
|
|
473
|
+
<span class="detail-label">Updates:</span>
|
|
474
|
+
<span class="detail-value">${data.callCount}</span>
|
|
266
475
|
</div>
|
|
267
476
|
`;
|
|
268
477
|
}
|
|
269
478
|
|
|
479
|
+
// Collapsible JSON viewer for full details
|
|
480
|
+
html += this.createCollapsibleJSON(data, 'Full Details');
|
|
481
|
+
|
|
270
482
|
html += '</div>';
|
|
271
483
|
this.container.innerHTML = html;
|
|
272
484
|
}
|
|
273
485
|
|
|
274
486
|
/**
|
|
275
|
-
* Display todo data with checklist formatting
|
|
487
|
+
* Display todo data with checklist formatting (for standalone todos, not TodoWrite)
|
|
276
488
|
*/
|
|
277
489
|
displayTodo(data) {
|
|
278
|
-
// Handle different data structures for
|
|
490
|
+
// Handle different data structures for standalone todos
|
|
279
491
|
let todos;
|
|
280
492
|
let toolName = 'Todo List';
|
|
281
|
-
let timestamp = null;
|
|
282
|
-
let status = null;
|
|
283
493
|
|
|
284
494
|
if (data.todos && Array.isArray(data.todos)) {
|
|
285
|
-
// Direct todo list format
|
|
286
495
|
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
496
|
} else if (Array.isArray(data)) {
|
|
294
|
-
// Array of todos
|
|
295
497
|
todos = data;
|
|
296
498
|
} else if (data.content && data.activeForm && data.status) {
|
|
297
|
-
// Single todo item
|
|
298
499
|
todos = [data];
|
|
299
500
|
} else {
|
|
300
|
-
// Fallback
|
|
301
501
|
todos = [];
|
|
302
502
|
}
|
|
303
503
|
|
|
304
504
|
let html = `
|
|
305
505
|
<div class="unified-viewer-header">
|
|
306
|
-
<h6
|
|
307
|
-
${status ? `<span class="unified-viewer-status">${this.formatStatus(status)}</span>` : ''}
|
|
506
|
+
<h6>📋 ${toolName}</h6>
|
|
308
507
|
</div>
|
|
309
508
|
<div class="unified-viewer-content">
|
|
310
509
|
`;
|
|
311
510
|
|
|
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
511
|
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
|
|
512
|
+
// Show todos immediately
|
|
349
513
|
html += `
|
|
350
|
-
<div class="
|
|
351
|
-
<span class="detail-section-title">Todo List (${todos.length} items)</span>
|
|
352
|
-
<div class="todo-checklist">
|
|
514
|
+
<div class="todo-list-primary">
|
|
353
515
|
`;
|
|
354
516
|
|
|
355
|
-
todos.forEach((todo
|
|
517
|
+
todos.forEach((todo) => {
|
|
356
518
|
const statusIcon = this.getCheckboxIcon(todo.status);
|
|
357
519
|
const displayText = todo.status === 'in_progress' ?
|
|
358
520
|
(todo.activeForm || todo.content) : todo.content;
|
|
359
521
|
const statusClass = this.formatStatusClass(todo.status);
|
|
360
522
|
|
|
361
523
|
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>
|
|
524
|
+
<div class="todo-item ${todo.status}">
|
|
525
|
+
<span class="todo-icon ${statusClass}">${statusIcon}</span>
|
|
526
|
+
<span class="todo-text">${this.escapeHtml(displayText)}</span>
|
|
527
|
+
<span class="todo-status-text ${statusClass}">${todo.status.replace('_', ' ')}</span>
|
|
370
528
|
</div>
|
|
371
529
|
`;
|
|
372
530
|
});
|
|
373
531
|
|
|
374
532
|
html += `
|
|
375
|
-
</div>
|
|
376
533
|
</div>
|
|
377
534
|
`;
|
|
378
535
|
} else {
|
|
@@ -389,6 +546,8 @@ class UnifiedDataViewer {
|
|
|
389
546
|
|
|
390
547
|
/**
|
|
391
548
|
* Display instruction data
|
|
549
|
+
* PRIMARY: Instruction text prominently displayed
|
|
550
|
+
* SECONDARY: Metadata in collapsible section
|
|
392
551
|
*/
|
|
393
552
|
displayInstruction(data) {
|
|
394
553
|
let html = `
|
|
@@ -397,16 +556,27 @@ class UnifiedDataViewer {
|
|
|
397
556
|
<span class="unified-viewer-timestamp">${this.formatTimestamp(data.timestamp)}</span>
|
|
398
557
|
</div>
|
|
399
558
|
<div class="unified-viewer-content">
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
559
|
+
`;
|
|
560
|
+
|
|
561
|
+
// PRIMARY DATA: The instruction text itself
|
|
562
|
+
html += `
|
|
563
|
+
<div class="primary-data">
|
|
564
|
+
<div class="instruction-content">
|
|
565
|
+
${this.escapeHtml(data.text)}
|
|
403
566
|
</div>
|
|
404
|
-
<div class="
|
|
405
|
-
<span class="
|
|
406
|
-
<span class="
|
|
567
|
+
<div class="instruction-meta">
|
|
568
|
+
<span class="meta-item">📏 ${data.text.length} characters</span>
|
|
569
|
+
<span class="meta-item">🕐 ${this.formatTimestamp(data.timestamp)}</span>
|
|
407
570
|
</div>
|
|
408
571
|
</div>
|
|
409
572
|
`;
|
|
573
|
+
|
|
574
|
+
// SECONDARY DATA: Full instruction object if there's more data
|
|
575
|
+
if (Object.keys(data).length > 3) {
|
|
576
|
+
html += this.createCollapsibleJSON(data, 'Full Instruction Data');
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
html += '</div>';
|
|
410
580
|
this.container.innerHTML = html;
|
|
411
581
|
}
|
|
412
582
|
|
|
@@ -1023,6 +1193,69 @@ class UnifiedDataViewer {
|
|
|
1023
1193
|
return div.innerHTML;
|
|
1024
1194
|
}
|
|
1025
1195
|
|
|
1196
|
+
/**
|
|
1197
|
+
* Create a collapsible JSON viewer for secondary details
|
|
1198
|
+
* Provides a clean way to show full data without cluttering the main view
|
|
1199
|
+
*/
|
|
1200
|
+
createCollapsibleJSON(data, title = 'Full Details') {
|
|
1201
|
+
// Generate unique ID for this collapsible section
|
|
1202
|
+
const sectionId = `json-details-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
1203
|
+
|
|
1204
|
+
// Filter out sensitive or overly verbose properties
|
|
1205
|
+
const cleanData = this.cleanDataForDisplay(data);
|
|
1206
|
+
|
|
1207
|
+
return `
|
|
1208
|
+
<div class="collapsible-json-section">
|
|
1209
|
+
<button class="collapsible-json-toggle" onclick="
|
|
1210
|
+
const content = document.getElementById('${sectionId}');
|
|
1211
|
+
const button = this;
|
|
1212
|
+
if (content.style.display === 'none' || content.style.display === '') {
|
|
1213
|
+
content.style.display = 'block';
|
|
1214
|
+
button.classList.add('expanded');
|
|
1215
|
+
button.innerHTML = '▼ ${title}';
|
|
1216
|
+
} else {
|
|
1217
|
+
content.style.display = 'none';
|
|
1218
|
+
button.classList.remove('expanded');
|
|
1219
|
+
button.innerHTML = '▶ ${title}';
|
|
1220
|
+
}
|
|
1221
|
+
">▶ ${title}</button>
|
|
1222
|
+
<div id="${sectionId}" class="collapsible-json-content" style="display: none;">
|
|
1223
|
+
<pre class="json-viewer">${this.escapeHtml(JSON.stringify(cleanData, null, 2))}</pre>
|
|
1224
|
+
</div>
|
|
1225
|
+
</div>
|
|
1226
|
+
`;
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
/**
|
|
1230
|
+
* Clean data for display in JSON viewer
|
|
1231
|
+
* Removes circular references and limits string lengths
|
|
1232
|
+
*/
|
|
1233
|
+
cleanDataForDisplay(data) {
|
|
1234
|
+
const seen = new WeakSet();
|
|
1235
|
+
|
|
1236
|
+
return JSON.parse(JSON.stringify(data, (key, value) => {
|
|
1237
|
+
// Handle circular references
|
|
1238
|
+
if (typeof value === 'object' && value !== null) {
|
|
1239
|
+
if (seen.has(value)) {
|
|
1240
|
+
return '[Circular Reference]';
|
|
1241
|
+
}
|
|
1242
|
+
seen.add(value);
|
|
1243
|
+
}
|
|
1244
|
+
|
|
1245
|
+
// Truncate very long strings
|
|
1246
|
+
if (typeof value === 'string' && value.length > 1000) {
|
|
1247
|
+
return value.substring(0, 1000) + '... [truncated]';
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
// Handle functions
|
|
1251
|
+
if (typeof value === 'function') {
|
|
1252
|
+
return '[Function]';
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
return value;
|
|
1256
|
+
}));
|
|
1257
|
+
}
|
|
1258
|
+
|
|
1026
1259
|
// ==================== PUBLIC API METHODS ====================
|
|
1027
1260
|
|
|
1028
1261
|
/**
|