claude-mpm 4.1.10__py3-none-any.whl → 4.1.11__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/cli/__init__.py +11 -0
- claude_mpm/cli/commands/analyze.py +2 -1
- claude_mpm/cli/commands/configure.py +9 -8
- claude_mpm/cli/commands/configure_tui.py +3 -1
- claude_mpm/cli/commands/dashboard.py +288 -0
- claude_mpm/cli/commands/debug.py +0 -1
- claude_mpm/cli/commands/mpm_init.py +427 -0
- claude_mpm/cli/commands/mpm_init_handler.py +83 -0
- claude_mpm/cli/parsers/base_parser.py +15 -0
- claude_mpm/cli/parsers/dashboard_parser.py +113 -0
- claude_mpm/cli/parsers/mpm_init_parser.py +122 -0
- claude_mpm/constants.py +10 -0
- claude_mpm/dashboard/analysis_runner.py +52 -25
- claude_mpm/dashboard/static/built/components/activity-tree.js +1 -1
- claude_mpm/dashboard/static/built/components/code-tree.js +2 -0
- claude_mpm/dashboard/static/built/components/code-viewer.js +2 -0
- claude_mpm/dashboard/static/built/components/event-viewer.js +1 -1
- claude_mpm/dashboard/static/built/dashboard.js +1 -1
- claude_mpm/dashboard/static/built/socket-client.js +1 -1
- claude_mpm/dashboard/static/css/code-tree.css +330 -1
- 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/event-viewer.js +1 -1
- claude_mpm/dashboard/static/dist/dashboard.js +1 -1
- claude_mpm/dashboard/static/dist/socket-client.js +1 -1
- claude_mpm/dashboard/static/js/components/activity-tree.js +212 -13
- claude_mpm/dashboard/static/js/components/code-tree.js +1999 -821
- claude_mpm/dashboard/static/js/components/event-viewer.js +58 -19
- claude_mpm/dashboard/static/js/dashboard.js +15 -3
- claude_mpm/dashboard/static/js/socket-client.js +74 -32
- claude_mpm/dashboard/templates/index.html +9 -11
- claude_mpm/services/agents/memory/memory_format_service.py +3 -1
- claude_mpm/services/cli/agent_cleanup_service.py +1 -4
- claude_mpm/services/cli/startup_checker.py +0 -1
- claude_mpm/services/core/cache_manager.py +0 -1
- claude_mpm/services/socketio/event_normalizer.py +64 -0
- claude_mpm/services/socketio/handlers/code_analysis.py +502 -0
- claude_mpm/services/socketio/server/connection_manager.py +3 -1
- claude_mpm/tools/code_tree_analyzer.py +843 -25
- claude_mpm/tools/code_tree_builder.py +0 -1
- claude_mpm/tools/code_tree_events.py +113 -15
- {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.11.dist-info}/METADATA +2 -1
- {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.11.dist-info}/RECORD +48 -41
- {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.11.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.11.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.11.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.11.dist-info}/top_level.txt +0 -0
|
@@ -39,7 +39,6 @@ class EventViewer {
|
|
|
39
39
|
|
|
40
40
|
// Subscribe to socket events
|
|
41
41
|
this.socketClient.onEventUpdate((events, sessions) => {
|
|
42
|
-
console.log('EventViewer received event update:', events?.length || 0, 'events');
|
|
43
42
|
// Ensure we always have a valid events array
|
|
44
43
|
this.events = Array.isArray(events) ? events : [];
|
|
45
44
|
this.updateDisplay();
|
|
@@ -76,7 +75,6 @@ class EventViewer {
|
|
|
76
75
|
setupKeyboardNavigation() {
|
|
77
76
|
// Keyboard navigation is now handled by Dashboard.setupUnifiedKeyboardNavigation()
|
|
78
77
|
// This method is kept for backward compatibility but does nothing
|
|
79
|
-
console.log('EventViewer: Keyboard navigation handled by unified Dashboard system');
|
|
80
78
|
}
|
|
81
79
|
|
|
82
80
|
/**
|
|
@@ -110,18 +108,10 @@ class EventViewer {
|
|
|
110
108
|
}
|
|
111
109
|
|
|
112
110
|
this.filteredEvents = this.events.filter(event => {
|
|
113
|
-
//
|
|
114
|
-
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Filter out code analysis events (they're shown in footer status bar)
|
|
119
|
-
if (event.type === 'code' ||
|
|
120
|
-
(event.type === 'unknown' && event.originalEventName && event.originalEventName.startsWith('code:'))) {
|
|
121
|
-
return false;
|
|
122
|
-
}
|
|
111
|
+
// NO AUTOMATIC FILTERING - All events are shown by default for complete visibility
|
|
112
|
+
// Users can apply their own filters using the search and type filter controls
|
|
123
113
|
|
|
124
|
-
//
|
|
114
|
+
// User-controlled search filter
|
|
125
115
|
if (this.searchFilter) {
|
|
126
116
|
const searchableText = [
|
|
127
117
|
event.type || '',
|
|
@@ -134,7 +124,7 @@ class EventViewer {
|
|
|
134
124
|
}
|
|
135
125
|
}
|
|
136
126
|
|
|
137
|
-
//
|
|
127
|
+
// User-controlled type filter - handles full hook types (like "hook.user_prompt") and main types
|
|
138
128
|
if (this.typeFilter) {
|
|
139
129
|
// Use the same logic as formatEventType to get the full event type
|
|
140
130
|
const eventType = event.type && event.type.trim() !== '' ? event.type : '';
|
|
@@ -144,13 +134,14 @@ class EventViewer {
|
|
|
144
134
|
}
|
|
145
135
|
}
|
|
146
136
|
|
|
147
|
-
//
|
|
137
|
+
// User-controlled session filter
|
|
148
138
|
if (this.sessionFilter && this.sessionFilter !== '') {
|
|
149
139
|
if (!event.data || event.data.session_id !== this.sessionFilter) {
|
|
150
140
|
return false;
|
|
151
141
|
}
|
|
152
142
|
}
|
|
153
143
|
|
|
144
|
+
// Allow all events through unless filtered by user controls
|
|
154
145
|
return true;
|
|
155
146
|
});
|
|
156
147
|
|
|
@@ -222,7 +213,6 @@ class EventViewer {
|
|
|
222
213
|
* Update the display with current events
|
|
223
214
|
*/
|
|
224
215
|
updateDisplay() {
|
|
225
|
-
console.log('EventViewer updating display with', this.events?.length || 0, 'events');
|
|
226
216
|
this.updateEventTypeDropdown();
|
|
227
217
|
this.applyFilters();
|
|
228
218
|
}
|
|
@@ -234,6 +224,9 @@ class EventViewer {
|
|
|
234
224
|
const eventsList = document.getElementById('events-list');
|
|
235
225
|
if (!eventsList) return;
|
|
236
226
|
|
|
227
|
+
// Check if user is at bottom BEFORE rendering (for autoscroll decision)
|
|
228
|
+
const wasAtBottom = (eventsList.scrollTop + eventsList.clientHeight >= eventsList.scrollHeight - 10);
|
|
229
|
+
|
|
237
230
|
if (this.filteredEvents.length === 0) {
|
|
238
231
|
eventsList.innerHTML = `
|
|
239
232
|
<div class="no-events">
|
|
@@ -281,9 +274,12 @@ class EventViewer {
|
|
|
281
274
|
window.dashboard.tabNavigation.events.items = this.filteredEventElements;
|
|
282
275
|
}
|
|
283
276
|
|
|
284
|
-
// Auto-scroll
|
|
285
|
-
if (this.
|
|
286
|
-
|
|
277
|
+
// Auto-scroll only if user was already at bottom before rendering
|
|
278
|
+
if (this.filteredEvents.length > 0 && wasAtBottom && this.autoScroll) {
|
|
279
|
+
// Use requestAnimationFrame to ensure DOM has updated
|
|
280
|
+
requestAnimationFrame(() => {
|
|
281
|
+
eventsList.scrollTop = eventsList.scrollHeight;
|
|
282
|
+
});
|
|
287
283
|
}
|
|
288
284
|
}
|
|
289
285
|
|
|
@@ -337,6 +333,8 @@ class EventViewer {
|
|
|
337
333
|
return this.formatMemoryEvent(event);
|
|
338
334
|
case 'log':
|
|
339
335
|
return this.formatLogEvent(event);
|
|
336
|
+
case 'code':
|
|
337
|
+
return this.formatCodeEvent(event);
|
|
340
338
|
default:
|
|
341
339
|
return this.formatGenericEvent(event);
|
|
342
340
|
}
|
|
@@ -480,6 +478,47 @@ class EventViewer {
|
|
|
480
478
|
return `<strong>[${level.toUpperCase()}]</strong> ${truncated}`;
|
|
481
479
|
}
|
|
482
480
|
|
|
481
|
+
/**
|
|
482
|
+
* Format code analysis event data
|
|
483
|
+
*/
|
|
484
|
+
formatCodeEvent(event) {
|
|
485
|
+
const data = event.data || {};
|
|
486
|
+
|
|
487
|
+
// Handle different code event subtypes
|
|
488
|
+
if (event.subtype === 'progress') {
|
|
489
|
+
const message = data.message || 'Processing...';
|
|
490
|
+
const percentage = data.percentage;
|
|
491
|
+
if (percentage !== undefined) {
|
|
492
|
+
return `<strong>Progress:</strong> ${message} (${Math.round(percentage)}%)`;
|
|
493
|
+
}
|
|
494
|
+
return `<strong>Progress:</strong> ${message}`;
|
|
495
|
+
} else if (event.subtype === 'analysis:queued') {
|
|
496
|
+
return `<strong>Queued:</strong> Analysis for ${data.path || 'Unknown path'}`;
|
|
497
|
+
} else if (event.subtype === 'analysis:start') {
|
|
498
|
+
return `<strong>Started:</strong> Analyzing ${data.path || 'Unknown path'}`;
|
|
499
|
+
} else if (event.subtype === 'analysis:complete') {
|
|
500
|
+
const duration = data.duration ? ` (${data.duration.toFixed(2)}s)` : '';
|
|
501
|
+
return `<strong>Complete:</strong> Analysis finished${duration}`;
|
|
502
|
+
} else if (event.subtype === 'analysis:error') {
|
|
503
|
+
return `<strong>Error:</strong> ${data.message || 'Analysis failed'}`;
|
|
504
|
+
} else if (event.subtype === 'analysis:cancelled') {
|
|
505
|
+
return `<strong>Cancelled:</strong> Analysis stopped for ${data.path || 'Unknown path'}`;
|
|
506
|
+
} else if (event.subtype === 'file:start') {
|
|
507
|
+
return `<strong>File:</strong> Processing ${data.file || 'Unknown file'}`;
|
|
508
|
+
} else if (event.subtype === 'file:complete') {
|
|
509
|
+
const nodes = data.nodes_count !== undefined ? ` (${data.nodes_count} nodes)` : '';
|
|
510
|
+
return `<strong>File done:</strong> ${data.file || 'Unknown file'}${nodes}`;
|
|
511
|
+
} else if (event.subtype === 'node:found') {
|
|
512
|
+
return `<strong>Node:</strong> Found ${data.node_type || 'element'} "${data.name || 'unnamed'}"`;
|
|
513
|
+
} else if (event.subtype === 'error') {
|
|
514
|
+
return `<strong>Error:</strong> ${data.error || 'Unknown error'} in ${data.file || 'file'}`;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
// Generic fallback for code events
|
|
518
|
+
const json = JSON.stringify(data);
|
|
519
|
+
return `<strong>Code:</strong> ${json.length > 100 ? json.substring(0, 100) + '...' : json}`;
|
|
520
|
+
}
|
|
521
|
+
|
|
483
522
|
/**
|
|
484
523
|
* Format generic event data
|
|
485
524
|
*/
|
|
@@ -393,13 +393,25 @@ class Dashboard {
|
|
|
393
393
|
console.log('Dashboard triggering activity tree render...');
|
|
394
394
|
window.activityTreeInstance.renderWhenVisible();
|
|
395
395
|
}
|
|
396
|
+
|
|
397
|
+
// Force show to ensure the tree is visible
|
|
398
|
+
if (typeof window.activityTreeInstance.forceShow === 'function') {
|
|
399
|
+
console.log('Dashboard forcing activity tree to show...');
|
|
400
|
+
window.activityTreeInstance.forceShow();
|
|
401
|
+
}
|
|
396
402
|
}
|
|
397
403
|
} else if (window.activityTree && typeof window.activityTree === 'function') {
|
|
398
404
|
// Fallback to legacy approach if available
|
|
399
405
|
const activityTreeInstance = window.activityTree();
|
|
400
|
-
if (activityTreeInstance
|
|
401
|
-
|
|
402
|
-
|
|
406
|
+
if (activityTreeInstance) {
|
|
407
|
+
if (typeof activityTreeInstance.renderWhenVisible === 'function') {
|
|
408
|
+
console.log('Dashboard triggering activity tree render (legacy)...');
|
|
409
|
+
activityTreeInstance.renderWhenVisible();
|
|
410
|
+
}
|
|
411
|
+
if (typeof activityTreeInstance.forceShow === 'function') {
|
|
412
|
+
console.log('Dashboard forcing activity tree to show (legacy)...');
|
|
413
|
+
activityTreeInstance.forceShow();
|
|
414
|
+
}
|
|
403
415
|
}
|
|
404
416
|
} else {
|
|
405
417
|
// Module not loaded yet, retry after a delay
|
|
@@ -475,11 +475,10 @@ class SocketClient {
|
|
|
475
475
|
return;
|
|
476
476
|
}
|
|
477
477
|
|
|
478
|
-
//
|
|
479
|
-
//
|
|
478
|
+
// Code analysis events are now allowed to flow through to the events list for troubleshooting
|
|
479
|
+
// They will appear in both the Events tab and the Code tab
|
|
480
480
|
if (validatedEvent.type && validatedEvent.type.startsWith('code:')) {
|
|
481
|
-
console.log('Code analysis event received via claude_event,
|
|
482
|
-
return;
|
|
481
|
+
console.log('Code analysis event received via claude_event, adding to events list for troubleshooting:', validatedEvent.type);
|
|
483
482
|
}
|
|
484
483
|
|
|
485
484
|
// Transform event to match expected format (for backward compatibility)
|
|
@@ -551,46 +550,55 @@ class SocketClient {
|
|
|
551
550
|
this.addEvent({ type: 'log', subtype: 'entry', timestamp: new Date().toISOString(), data });
|
|
552
551
|
});
|
|
553
552
|
|
|
554
|
-
// Code analysis events -
|
|
555
|
-
// These are handled by the code-tree component and shown in the footer
|
|
553
|
+
// Code analysis events - now allowed to flow through for troubleshooting
|
|
554
|
+
// These are ALSO handled by the code-tree component and shown in the footer
|
|
555
|
+
// They will appear in both places: Events tab (for troubleshooting) and Code tab (for visualization)
|
|
556
556
|
this.socket.on('code:analysis:queued', (data) => {
|
|
557
|
-
//
|
|
558
|
-
console.log('Code analysis queued event received,
|
|
557
|
+
// Add to events list for troubleshooting
|
|
558
|
+
console.log('Code analysis queued event received, adding to events list for troubleshooting');
|
|
559
|
+
this.addEvent({ type: 'code', subtype: 'analysis:queued', timestamp: new Date().toISOString(), data });
|
|
559
560
|
});
|
|
560
561
|
|
|
561
562
|
this.socket.on('code:analysis:accepted', (data) => {
|
|
562
|
-
//
|
|
563
|
-
console.log('Code analysis accepted event received,
|
|
563
|
+
// Add to events list for troubleshooting
|
|
564
|
+
console.log('Code analysis accepted event received, adding to events list for troubleshooting');
|
|
565
|
+
this.addEvent({ type: 'code', subtype: 'analysis:accepted', timestamp: new Date().toISOString(), data });
|
|
564
566
|
});
|
|
565
567
|
|
|
566
568
|
this.socket.on('code:analysis:start', (data) => {
|
|
567
|
-
//
|
|
568
|
-
console.log('Code analysis start event received,
|
|
569
|
+
// Add to events list for troubleshooting
|
|
570
|
+
console.log('Code analysis start event received, adding to events list for troubleshooting');
|
|
571
|
+
this.addEvent({ type: 'code', subtype: 'analysis:start', timestamp: new Date().toISOString(), data });
|
|
569
572
|
});
|
|
570
573
|
|
|
571
574
|
this.socket.on('code:analysis:complete', (data) => {
|
|
572
|
-
//
|
|
573
|
-
console.log('Code analysis complete event received,
|
|
575
|
+
// Add to events list for troubleshooting
|
|
576
|
+
console.log('Code analysis complete event received, adding to events list for troubleshooting');
|
|
577
|
+
this.addEvent({ type: 'code', subtype: 'analysis:complete', timestamp: new Date().toISOString(), data });
|
|
574
578
|
});
|
|
575
579
|
|
|
576
580
|
this.socket.on('code:analysis:error', (data) => {
|
|
577
|
-
//
|
|
578
|
-
console.log('Code analysis error event received,
|
|
581
|
+
// Add to events list for troubleshooting
|
|
582
|
+
console.log('Code analysis error event received, adding to events list for troubleshooting');
|
|
583
|
+
this.addEvent({ type: 'code', subtype: 'analysis:error', timestamp: new Date().toISOString(), data });
|
|
579
584
|
});
|
|
580
585
|
|
|
581
586
|
this.socket.on('code:file:start', (data) => {
|
|
582
|
-
//
|
|
583
|
-
console.log('Code file start event received,
|
|
587
|
+
// Add to events list for troubleshooting
|
|
588
|
+
console.log('Code file start event received, adding to events list for troubleshooting');
|
|
589
|
+
this.addEvent({ type: 'code', subtype: 'file:start', timestamp: new Date().toISOString(), data });
|
|
584
590
|
});
|
|
585
591
|
|
|
586
592
|
this.socket.on('code:node:found', (data) => {
|
|
587
|
-
//
|
|
588
|
-
console.log('Code node found event received,
|
|
593
|
+
// Add to events list for troubleshooting
|
|
594
|
+
console.log('Code node found event received, adding to events list for troubleshooting');
|
|
595
|
+
this.addEvent({ type: 'code', subtype: 'node:found', timestamp: new Date().toISOString(), data });
|
|
589
596
|
});
|
|
590
597
|
|
|
591
598
|
this.socket.on('code:analysis:progress', (data) => {
|
|
592
|
-
//
|
|
593
|
-
console.log('Code analysis progress event received,
|
|
599
|
+
// Add to events list for troubleshooting
|
|
600
|
+
console.log('Code analysis progress event received, adding to events list for troubleshooting');
|
|
601
|
+
this.addEvent({ type: 'code', subtype: 'analysis:progress', timestamp: new Date().toISOString(), data });
|
|
594
602
|
});
|
|
595
603
|
|
|
596
604
|
this.socket.on('history', (data) => {
|
|
@@ -1082,6 +1090,7 @@ class SocketClient {
|
|
|
1082
1090
|
// 1. Hook events: { type: 'hook.pre_tool', timestamp: '...', data: {...} }
|
|
1083
1091
|
// 2. Legacy events: { event: 'TestStart', timestamp: '...', ... }
|
|
1084
1092
|
// 3. Standard events: { type: 'session', subtype: 'started', ... }
|
|
1093
|
+
// 4. Normalized events: { type: 'code', subtype: 'progress', ... } - already normalized, keep as-is
|
|
1085
1094
|
|
|
1086
1095
|
if (!eventData) {
|
|
1087
1096
|
return eventData; // Return as-is if null/undefined
|
|
@@ -1089,8 +1098,26 @@ class SocketClient {
|
|
|
1089
1098
|
|
|
1090
1099
|
let transformedEvent = { ...eventData };
|
|
1091
1100
|
|
|
1101
|
+
// Check if event is already normalized (has both type and subtype as separate fields)
|
|
1102
|
+
// This prevents double-transformation of events that were normalized on the backend
|
|
1103
|
+
const isAlreadyNormalized = eventData.type && eventData.subtype &&
|
|
1104
|
+
!eventData.type.includes('.') &&
|
|
1105
|
+
!eventData.type.includes(':');
|
|
1106
|
+
|
|
1107
|
+
if (isAlreadyNormalized) {
|
|
1108
|
+
// Event is already properly normalized from backend, just preserve it
|
|
1109
|
+
// Store a composite originalEventName for display if needed
|
|
1110
|
+
if (!transformedEvent.originalEventName) {
|
|
1111
|
+
if (eventData.subtype === 'generic' || eventData.type === eventData.subtype) {
|
|
1112
|
+
transformedEvent.originalEventName = eventData.type;
|
|
1113
|
+
} else {
|
|
1114
|
+
transformedEvent.originalEventName = `${eventData.type}.${eventData.subtype}`;
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
// Return early to avoid further transformation
|
|
1118
|
+
}
|
|
1092
1119
|
// Handle legacy format with 'event' field but no 'type'
|
|
1093
|
-
if (!eventData.type && eventData.event) {
|
|
1120
|
+
else if (!eventData.type && eventData.event) {
|
|
1094
1121
|
// Map common event names to proper type/subtype
|
|
1095
1122
|
const eventName = eventData.event;
|
|
1096
1123
|
|
|
@@ -1121,8 +1148,10 @@ class SocketClient {
|
|
|
1121
1148
|
|
|
1122
1149
|
// Remove the 'event' field to avoid confusion
|
|
1123
1150
|
delete transformedEvent.event;
|
|
1151
|
+
// Store original event name for display purposes
|
|
1152
|
+
transformedEvent.originalEventName = eventName;
|
|
1124
1153
|
}
|
|
1125
|
-
// Handle standard format with 'type' field
|
|
1154
|
+
// Handle standard format with 'type' field that needs transformation
|
|
1126
1155
|
else if (eventData.type) {
|
|
1127
1156
|
const type = eventData.type;
|
|
1128
1157
|
|
|
@@ -1131,30 +1160,43 @@ class SocketClient {
|
|
|
1131
1160
|
const subtype = type.substring(5); // Remove 'hook.' prefix
|
|
1132
1161
|
transformedEvent.type = 'hook';
|
|
1133
1162
|
transformedEvent.subtype = subtype;
|
|
1163
|
+
transformedEvent.originalEventName = type;
|
|
1134
1164
|
}
|
|
1135
1165
|
// Transform 'code:*' events to proper code type
|
|
1166
|
+
// Handle multi-level subtypes like 'code:analysis:queued'
|
|
1136
1167
|
else if (type.startsWith('code:')) {
|
|
1137
1168
|
transformedEvent.type = 'code';
|
|
1138
|
-
|
|
1169
|
+
// Replace colons with underscores in subtype for consistency
|
|
1170
|
+
const subtypePart = type.substring(5); // Remove 'code:' prefix
|
|
1171
|
+
transformedEvent.subtype = subtypePart.replace(/:/g, '_');
|
|
1172
|
+
transformedEvent.originalEventName = type;
|
|
1139
1173
|
}
|
|
1140
1174
|
// Transform other dotted types like 'session.started' -> type: 'session', subtype: 'started'
|
|
1141
1175
|
else if (type.includes('.')) {
|
|
1142
1176
|
const [mainType, ...subtypeParts] = type.split('.');
|
|
1143
1177
|
transformedEvent.type = mainType;
|
|
1144
1178
|
transformedEvent.subtype = subtypeParts.join('.');
|
|
1179
|
+
transformedEvent.originalEventName = type;
|
|
1180
|
+
}
|
|
1181
|
+
// Transform any remaining colon-separated types generically
|
|
1182
|
+
else if (type.includes(':')) {
|
|
1183
|
+
const parts = type.split(':', 2); // Split into max 2 parts
|
|
1184
|
+
transformedEvent.type = parts[0];
|
|
1185
|
+
// Replace any remaining colons with underscores in subtype
|
|
1186
|
+
transformedEvent.subtype = parts.length > 1 ? parts[1].replace(/:/g, '_') : 'generic';
|
|
1187
|
+
transformedEvent.originalEventName = type;
|
|
1188
|
+
}
|
|
1189
|
+
// If type doesn't need transformation but has no subtype, set a default
|
|
1190
|
+
else if (!eventData.subtype) {
|
|
1191
|
+
transformedEvent.subtype = 'generic';
|
|
1192
|
+
transformedEvent.originalEventName = type;
|
|
1145
1193
|
}
|
|
1146
1194
|
}
|
|
1147
1195
|
// If no type and no event field, mark as unknown
|
|
1148
1196
|
else {
|
|
1149
1197
|
transformedEvent.type = 'unknown';
|
|
1150
1198
|
transformedEvent.subtype = '';
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
// Store original event name for display purposes (before any transformation)
|
|
1154
|
-
if (!eventData.type && eventData.event) {
|
|
1155
|
-
transformedEvent.originalEventName = eventData.event;
|
|
1156
|
-
} else if (eventData.type) {
|
|
1157
|
-
transformedEvent.originalEventName = eventData.type;
|
|
1199
|
+
transformedEvent.originalEventName = 'unknown';
|
|
1158
1200
|
}
|
|
1159
1201
|
|
|
1160
1202
|
// Extract and flatten data fields to top level for dashboard compatibility
|
|
@@ -389,12 +389,9 @@
|
|
|
389
389
|
<!-- Code Tab -->
|
|
390
390
|
<div class="tab-content" id="code-tab">
|
|
391
391
|
<div class="code-container">
|
|
392
|
-
<!--
|
|
392
|
+
<!-- Simplified header with controls -->
|
|
393
393
|
<div class="code-header-compact">
|
|
394
394
|
<div class="header-left">
|
|
395
|
-
<input type="text" id="analysis-path" placeholder="Path" value="." class="path-input-compact">
|
|
396
|
-
<button id="analyze-code" class="btn-compact btn-primary">🔍</button>
|
|
397
|
-
<button id="cancel-analysis" class="btn-compact btn-danger" style="display: none;">✕</button>
|
|
398
395
|
<button id="code-expand-all" class="btn-compact" title="Expand All">⊕</button>
|
|
399
396
|
<button id="code-collapse-all" class="btn-compact" title="Collapse All">⊖</button>
|
|
400
397
|
<button id="code-reset-zoom" class="btn-compact" title="Reset Zoom">⟲</button>
|
|
@@ -416,22 +413,23 @@
|
|
|
416
413
|
<input type="text" id="code-search" placeholder="Search..." class="search-compact">
|
|
417
414
|
</div>
|
|
418
415
|
</div>
|
|
419
|
-
<!--
|
|
420
|
-
<
|
|
421
|
-
<summary>Advanced Options</summary>
|
|
416
|
+
<!-- Advanced options - visible by default -->
|
|
417
|
+
<div class="code-advanced-options-visible">
|
|
422
418
|
<div class="advanced-content">
|
|
423
419
|
<div class="option-group">
|
|
424
420
|
<label>Languages:</label>
|
|
425
421
|
<label><input type="checkbox" class="language-checkbox" value="python" checked> Python</label>
|
|
426
422
|
<label><input type="checkbox" class="language-checkbox" value="javascript" checked> JS</label>
|
|
427
|
-
<label><input type="checkbox" class="language-checkbox" value="typescript"> TS</label>
|
|
423
|
+
<label><input type="checkbox" class="language-checkbox" value="typescript" checked> TS</label>
|
|
428
424
|
</div>
|
|
429
425
|
<div class="option-group">
|
|
430
|
-
<label>
|
|
431
|
-
|
|
426
|
+
<label>Ignore: <input type="text" id="ignore-patterns" placeholder="test*, *.spec.js, node_modules" class="input-compact" style="width: 200px;"></label>
|
|
427
|
+
</div>
|
|
428
|
+
<div class="option-group">
|
|
429
|
+
<label><input type="checkbox" id="show-hidden-files"> Show hidden files (dotfiles)</label>
|
|
432
430
|
</div>
|
|
433
431
|
</div>
|
|
434
|
-
</
|
|
432
|
+
</div>
|
|
435
433
|
<div id="code-tree-container" class="code-tree-container">
|
|
436
434
|
<div id="code-tree"></div>
|
|
437
435
|
<!-- Collapsible legend -->
|
|
@@ -62,7 +62,9 @@ class MemoryFormatService:
|
|
|
62
62
|
line = line.strip()
|
|
63
63
|
# Skip headers, empty lines, and metadata
|
|
64
64
|
if (
|
|
65
|
-
not line
|
|
65
|
+
not line
|
|
66
|
+
or line.startswith(("#", "Last Updated:", "**"))
|
|
67
|
+
or line == "---"
|
|
66
68
|
):
|
|
67
69
|
continue
|
|
68
70
|
|
|
@@ -233,10 +233,7 @@ class AgentCleanupService(IAgentCleanupService):
|
|
|
233
233
|
all_agents = multi_source_service.discover_agents_from_all_sources()
|
|
234
234
|
|
|
235
235
|
# Detect orphaned agents
|
|
236
|
-
return multi_source_service.detect_orphaned_agents(
|
|
237
|
-
agents_dir, all_agents
|
|
238
|
-
)
|
|
239
|
-
|
|
236
|
+
return multi_source_service.detect_orphaned_agents(agents_dir, all_agents)
|
|
240
237
|
|
|
241
238
|
except Exception as e:
|
|
242
239
|
self.logger.error(f"Error finding orphaned agents: {e}", exc_info=True)
|
|
@@ -59,6 +59,7 @@ class EventType(Enum):
|
|
|
59
59
|
PERFORMANCE = "performance" # Performance metrics
|
|
60
60
|
CLAUDE = "claude" # Claude process events
|
|
61
61
|
TEST = "test" # Test events
|
|
62
|
+
CODE = "code" # Code analysis events
|
|
62
63
|
TOOL = "tool" # Tool events
|
|
63
64
|
SUBAGENT = "subagent" # Subagent events
|
|
64
65
|
|
|
@@ -351,6 +352,41 @@ class EventNormalizer:
|
|
|
351
352
|
event_type.value if isinstance(event_type, EventType) else event_type
|
|
352
353
|
), subtype
|
|
353
354
|
|
|
355
|
+
# Handle colon-separated event names (e.g., "code:analysis:queued", "code:progress")
|
|
356
|
+
# These are commonly used by the code analysis system
|
|
357
|
+
if ":" in event_name:
|
|
358
|
+
parts = event_name.split(":", 2) # Split into max 3 parts
|
|
359
|
+
if len(parts) >= 2:
|
|
360
|
+
type_part = parts[0].lower()
|
|
361
|
+
# For events like "code:analysis:queued", combine the last parts as subtype
|
|
362
|
+
# Replace colons with underscores for clean subtypes
|
|
363
|
+
if len(parts) == 3:
|
|
364
|
+
subtype_part = f"{parts[1]}_{parts[2]}"
|
|
365
|
+
else:
|
|
366
|
+
subtype_part = parts[1].replace(":", "_")
|
|
367
|
+
|
|
368
|
+
# Map the type part to known types
|
|
369
|
+
if type_part in [
|
|
370
|
+
"code", # Code analysis events
|
|
371
|
+
"hook",
|
|
372
|
+
"session",
|
|
373
|
+
"file",
|
|
374
|
+
"system",
|
|
375
|
+
"connection",
|
|
376
|
+
"memory",
|
|
377
|
+
"git",
|
|
378
|
+
"todo",
|
|
379
|
+
"ticket",
|
|
380
|
+
"agent",
|
|
381
|
+
"claude",
|
|
382
|
+
"error",
|
|
383
|
+
"performance",
|
|
384
|
+
"test",
|
|
385
|
+
"tool",
|
|
386
|
+
"subagent",
|
|
387
|
+
]:
|
|
388
|
+
return type_part, subtype_part
|
|
389
|
+
|
|
354
390
|
# Handle dotted event names (e.g., "connection.status", "session.started")
|
|
355
391
|
if "." in event_name:
|
|
356
392
|
parts = event_name.split(".", 1)
|
|
@@ -443,6 +479,34 @@ class EventNormalizer:
|
|
|
443
479
|
return EventType.MEMORY.value, "injected"
|
|
444
480
|
return EventType.MEMORY.value, "generic"
|
|
445
481
|
|
|
482
|
+
# Code analysis events - using underscores for clean subtypes
|
|
483
|
+
if "code" in event_lower:
|
|
484
|
+
if "analysis" in event_lower:
|
|
485
|
+
if "queue" in event_lower:
|
|
486
|
+
return EventType.CODE.value, "analysis_queued"
|
|
487
|
+
if "start" in event_lower:
|
|
488
|
+
return EventType.CODE.value, "analysis_start"
|
|
489
|
+
if "complete" in event_lower:
|
|
490
|
+
return EventType.CODE.value, "analysis_complete"
|
|
491
|
+
if "error" in event_lower:
|
|
492
|
+
return EventType.CODE.value, "analysis_error"
|
|
493
|
+
if "cancel" in event_lower:
|
|
494
|
+
return EventType.CODE.value, "analysis_cancelled"
|
|
495
|
+
return EventType.CODE.value, "analysis_generic"
|
|
496
|
+
if "progress" in event_lower:
|
|
497
|
+
return EventType.CODE.value, "progress"
|
|
498
|
+
if "file" in event_lower:
|
|
499
|
+
if "discovered" in event_lower:
|
|
500
|
+
return EventType.CODE.value, "file_discovered"
|
|
501
|
+
if "analyzed" in event_lower:
|
|
502
|
+
return EventType.CODE.value, "file_analyzed"
|
|
503
|
+
return EventType.CODE.value, "file_complete"
|
|
504
|
+
if "directory" in event_lower:
|
|
505
|
+
return EventType.CODE.value, "directory_discovered"
|
|
506
|
+
if "node" in event_lower:
|
|
507
|
+
return EventType.CODE.value, "node_found"
|
|
508
|
+
return EventType.CODE.value, "generic"
|
|
509
|
+
|
|
446
510
|
# Default to unknown with lowercase subtype
|
|
447
511
|
return "unknown", event_name.lower() if event_name else ""
|
|
448
512
|
|