claude-mpm 4.1.10__py3-none-any.whl → 4.1.12__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/agents/INSTRUCTIONS.md +8 -0
- 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 +442 -0
- claude_mpm/cli/commands/mpm_init_handler.py +84 -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 +128 -0
- claude_mpm/constants.py +10 -0
- claude_mpm/core/config.py +18 -0
- claude_mpm/core/instruction_reinforcement_hook.py +266 -0
- claude_mpm/core/pm_hook_interceptor.py +105 -8
- 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 +2593 -2
- 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/build-tracker.js +15 -13
- claude_mpm/dashboard/static/js/components/code-tree.js +2503 -917
- claude_mpm/dashboard/static/js/components/event-viewer.js +58 -19
- claude_mpm/dashboard/static/js/dashboard.js +46 -44
- claude_mpm/dashboard/static/js/socket-client.js +74 -32
- claude_mpm/dashboard/templates/index.html +25 -20
- claude_mpm/services/agents/deployment/agent_template_builder.py +11 -7
- 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/socketio_manager.py +39 -8
- claude_mpm/services/cli/startup_checker.py +0 -1
- claude_mpm/services/core/cache_manager.py +0 -1
- claude_mpm/services/infrastructure/monitoring.py +1 -1
- claude_mpm/services/socketio/event_normalizer.py +64 -0
- claude_mpm/services/socketio/handlers/code_analysis.py +449 -0
- claude_mpm/services/socketio/server/connection_manager.py +3 -1
- claude_mpm/tools/code_tree_analyzer.py +930 -24
- 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.12.dist-info}/METADATA +2 -1
- {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.12.dist-info}/RECORD +56 -48
- {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.12.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.12.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.12.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.10.dist-info → claude_mpm-4.1.12.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
|
*/
|
|
@@ -163,14 +163,22 @@ class Dashboard {
|
|
|
163
163
|
// Set the socket client for receiving updates
|
|
164
164
|
this.buildTracker.setSocketClient(this.socketClient);
|
|
165
165
|
|
|
166
|
-
// Mount to header
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
166
|
+
// Mount to header with retry logic for DOM readiness
|
|
167
|
+
const mountBuildTracker = () => {
|
|
168
|
+
const headerTitle = document.querySelector('.header-title');
|
|
169
|
+
if (headerTitle) {
|
|
170
|
+
// Insert after the title and status badge
|
|
171
|
+
this.buildTracker.mount(headerTitle);
|
|
172
|
+
console.log('BuildTracker mounted successfully');
|
|
173
|
+
} else {
|
|
174
|
+
console.warn('Header-title element not found for build tracker, will retry');
|
|
175
|
+
// Retry after a short delay if DOM is still being constructed
|
|
176
|
+
setTimeout(mountBuildTracker, 100);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
// Try to mount immediately, with retry logic if needed
|
|
181
|
+
mountBuildTracker();
|
|
174
182
|
|
|
175
183
|
// Make available globally for debugging
|
|
176
184
|
window.buildTracker = this.buildTracker;
|
|
@@ -393,13 +401,25 @@ class Dashboard {
|
|
|
393
401
|
console.log('Dashboard triggering activity tree render...');
|
|
394
402
|
window.activityTreeInstance.renderWhenVisible();
|
|
395
403
|
}
|
|
404
|
+
|
|
405
|
+
// Force show to ensure the tree is visible
|
|
406
|
+
if (typeof window.activityTreeInstance.forceShow === 'function') {
|
|
407
|
+
console.log('Dashboard forcing activity tree to show...');
|
|
408
|
+
window.activityTreeInstance.forceShow();
|
|
409
|
+
}
|
|
396
410
|
}
|
|
397
411
|
} else if (window.activityTree && typeof window.activityTree === 'function') {
|
|
398
412
|
// Fallback to legacy approach if available
|
|
399
413
|
const activityTreeInstance = window.activityTree();
|
|
400
|
-
if (activityTreeInstance
|
|
401
|
-
|
|
402
|
-
|
|
414
|
+
if (activityTreeInstance) {
|
|
415
|
+
if (typeof activityTreeInstance.renderWhenVisible === 'function') {
|
|
416
|
+
console.log('Dashboard triggering activity tree render (legacy)...');
|
|
417
|
+
activityTreeInstance.renderWhenVisible();
|
|
418
|
+
}
|
|
419
|
+
if (typeof activityTreeInstance.forceShow === 'function') {
|
|
420
|
+
console.log('Dashboard forcing activity tree to show (legacy)...');
|
|
421
|
+
activityTreeInstance.forceShow();
|
|
422
|
+
}
|
|
403
423
|
}
|
|
404
424
|
} else {
|
|
405
425
|
// Module not loaded yet, retry after a delay
|
|
@@ -1068,14 +1088,11 @@ async function updateFileViewerModal(modal, filePath, workingDir) {
|
|
|
1068
1088
|
working_dir: workingDir
|
|
1069
1089
|
});
|
|
1070
1090
|
|
|
1071
|
-
|
|
1072
|
-
filePath,
|
|
1073
|
-
workingDir
|
|
1074
|
-
});
|
|
1091
|
+
// File viewer request sent
|
|
1075
1092
|
|
|
1076
1093
|
// Wait for response
|
|
1077
1094
|
const result = await responsePromise;
|
|
1078
|
-
|
|
1095
|
+
// File content received successfully
|
|
1079
1096
|
|
|
1080
1097
|
// Hide loading
|
|
1081
1098
|
modal.querySelector('.file-viewer-loading').style.display = 'none';
|
|
@@ -1131,7 +1148,7 @@ async function updateFileViewerModal(modal, filePath, workingDir) {
|
|
|
1131
1148
|
}
|
|
1132
1149
|
|
|
1133
1150
|
function displayFileContent(modal, result) {
|
|
1134
|
-
|
|
1151
|
+
// Display file content in modal
|
|
1135
1152
|
const contentArea = modal.querySelector('.file-viewer-content-area');
|
|
1136
1153
|
const extensionElement = modal.querySelector('.file-extension');
|
|
1137
1154
|
const encodingElement = modal.querySelector('.file-encoding');
|
|
@@ -1145,7 +1162,7 @@ function displayFileContent(modal, result) {
|
|
|
1145
1162
|
|
|
1146
1163
|
// Update content with basic syntax highlighting
|
|
1147
1164
|
if (codeElement && result.content) {
|
|
1148
|
-
|
|
1165
|
+
// Setting file content
|
|
1149
1166
|
codeElement.innerHTML = highlightCode(result.content, result.extension);
|
|
1150
1167
|
|
|
1151
1168
|
// Force scrolling to work by setting explicit heights
|
|
@@ -1163,12 +1180,7 @@ function displayFileContent(modal, result) {
|
|
|
1163
1180
|
|
|
1164
1181
|
const availableHeight = modalHeight - headerHeight - toolbarHeight - 40; // 40px for padding
|
|
1165
1182
|
|
|
1166
|
-
|
|
1167
|
-
modalHeight,
|
|
1168
|
-
headerHeight,
|
|
1169
|
-
toolbarHeight,
|
|
1170
|
-
availableHeight
|
|
1171
|
-
});
|
|
1183
|
+
// Setting file viewer scroll height
|
|
1172
1184
|
|
|
1173
1185
|
wrapper.style.maxHeight = `${availableHeight}px`;
|
|
1174
1186
|
wrapper.style.overflowY = 'auto';
|
|
@@ -1181,7 +1193,7 @@ function displayFileContent(modal, result) {
|
|
|
1181
1193
|
// Show content area
|
|
1182
1194
|
if (contentArea) {
|
|
1183
1195
|
contentArea.style.display = 'block';
|
|
1184
|
-
|
|
1196
|
+
// File content area displayed
|
|
1185
1197
|
}
|
|
1186
1198
|
}
|
|
1187
1199
|
|
|
@@ -1521,7 +1533,7 @@ async function updateGitDiffModal(modal, filePath, timestamp, workingDir) {
|
|
|
1521
1533
|
throw new Error(`Server health check failed: ${healthResponse.status} ${healthResponse.statusText}`);
|
|
1522
1534
|
}
|
|
1523
1535
|
|
|
1524
|
-
|
|
1536
|
+
// Server health check passed
|
|
1525
1537
|
} catch (healthError) {
|
|
1526
1538
|
throw new Error(`Cannot reach server at localhost:${port}. Health check failed: ${healthError.message}`);
|
|
1527
1539
|
}
|
|
@@ -1541,17 +1553,17 @@ async function updateGitDiffModal(modal, filePath, timestamp, workingDir) {
|
|
|
1541
1553
|
}
|
|
1542
1554
|
|
|
1543
1555
|
const result = await response.json();
|
|
1544
|
-
|
|
1556
|
+
// Git diff response received
|
|
1545
1557
|
|
|
1546
1558
|
// Hide loading
|
|
1547
1559
|
modal.querySelector('.git-diff-loading').style.display = 'none';
|
|
1548
1560
|
|
|
1549
1561
|
if (result.success) {
|
|
1550
|
-
|
|
1562
|
+
// Displaying successful git diff
|
|
1551
1563
|
// Show successful diff
|
|
1552
1564
|
displayGitDiff(modal, result);
|
|
1553
1565
|
} else {
|
|
1554
|
-
|
|
1566
|
+
// Displaying git diff error
|
|
1555
1567
|
// Show error
|
|
1556
1568
|
displayGitDiffError(modal, result);
|
|
1557
1569
|
}
|
|
@@ -1649,18 +1661,13 @@ function highlightGitDiff(diffText) {
|
|
|
1649
1661
|
}
|
|
1650
1662
|
|
|
1651
1663
|
function displayGitDiff(modal, result) {
|
|
1652
|
-
|
|
1664
|
+
// Display git diff content
|
|
1653
1665
|
const contentArea = modal.querySelector('.git-diff-content-area');
|
|
1654
1666
|
const commitHashElement = modal.querySelector('.commit-hash');
|
|
1655
1667
|
const methodElement = modal.querySelector('.diff-method');
|
|
1656
1668
|
const codeElement = modal.querySelector('.git-diff-code');
|
|
1657
1669
|
|
|
1658
|
-
|
|
1659
|
-
contentArea: !!contentArea,
|
|
1660
|
-
commitHashElement: !!commitHashElement,
|
|
1661
|
-
methodElement: !!methodElement,
|
|
1662
|
-
codeElement: !!codeElement
|
|
1663
|
-
});
|
|
1670
|
+
// Elements found for diff display
|
|
1664
1671
|
|
|
1665
1672
|
// Update metadata
|
|
1666
1673
|
if (commitHashElement) commitHashElement.textContent = `Commit: ${result.commit_hash}`;
|
|
@@ -1668,7 +1675,7 @@ function displayGitDiff(modal, result) {
|
|
|
1668
1675
|
|
|
1669
1676
|
// Update diff content with basic syntax highlighting
|
|
1670
1677
|
if (codeElement && result.diff) {
|
|
1671
|
-
|
|
1678
|
+
// Setting diff content
|
|
1672
1679
|
codeElement.innerHTML = highlightGitDiff(result.diff);
|
|
1673
1680
|
|
|
1674
1681
|
// Force scrolling to work by setting explicit heights
|
|
@@ -1686,12 +1693,7 @@ function displayGitDiff(modal, result) {
|
|
|
1686
1693
|
|
|
1687
1694
|
const availableHeight = modalHeight - headerHeight - toolbarHeight - 40; // 40px for padding
|
|
1688
1695
|
|
|
1689
|
-
|
|
1690
|
-
modalHeight,
|
|
1691
|
-
headerHeight,
|
|
1692
|
-
toolbarHeight,
|
|
1693
|
-
availableHeight
|
|
1694
|
-
});
|
|
1696
|
+
// Setting explicit scroll height
|
|
1695
1697
|
|
|
1696
1698
|
wrapper.style.maxHeight = `${availableHeight}px`;
|
|
1697
1699
|
wrapper.style.overflowY = 'auto';
|
|
@@ -1704,7 +1706,7 @@ function displayGitDiff(modal, result) {
|
|
|
1704
1706
|
// Show content area
|
|
1705
1707
|
if (contentArea) {
|
|
1706
1708
|
contentArea.style.display = 'block';
|
|
1707
|
-
|
|
1709
|
+
// Content area displayed
|
|
1708
1710
|
}
|
|
1709
1711
|
}
|
|
1710
1712
|
|
|
@@ -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,20 @@
|
|
|
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
|
-
<label>Ignore: <input type="text" id="ignore-patterns" placeholder="test*, *.spec.js" class="input-compact"></label>
|
|
426
|
+
<label>Ignore: <input type="text" id="ignore-patterns" placeholder="test*, *.spec.js, node_modules" class="input-compact" style="width: 200px;"></label>
|
|
432
427
|
</div>
|
|
433
428
|
</div>
|
|
434
|
-
</
|
|
429
|
+
</div>
|
|
435
430
|
<div id="code-tree-container" class="code-tree-container">
|
|
436
431
|
<div id="code-tree"></div>
|
|
437
432
|
<!-- Collapsible legend -->
|
|
@@ -515,14 +510,24 @@
|
|
|
515
510
|
</div>
|
|
516
511
|
|
|
517
512
|
<!-- JavaScript Modules -->
|
|
518
|
-
<!-- Load bundled dashboard assets (built with Vite) -->
|
|
519
|
-
<script type="module"
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
513
|
+
<!-- Load bundled dashboard assets (built with Vite) - with timestamp cache busting -->
|
|
514
|
+
<script type="module">
|
|
515
|
+
// Add timestamp-based cache busting to all module imports
|
|
516
|
+
const timestamp = Date.now();
|
|
517
|
+
const modules = [
|
|
518
|
+
'/static/dist/dashboard.js',
|
|
519
|
+
'/static/dist/components/activity-tree.js',
|
|
520
|
+
'/static/dist/components/code-tree.js',
|
|
521
|
+
'/static/dist/components/code-viewer.js'
|
|
522
|
+
];
|
|
523
|
+
|
|
524
|
+
// Dynamically import each module with cache busting
|
|
525
|
+
modules.forEach(modulePath => {
|
|
526
|
+
const script = document.createElement('script');
|
|
527
|
+
script.type = 'module';
|
|
528
|
+
script.src = `${modulePath}?t=${timestamp}`;
|
|
529
|
+
document.body.appendChild(script);
|
|
530
|
+
});
|
|
531
|
+
</script>
|
|
527
532
|
</body>
|
|
528
533
|
</html>
|
|
@@ -190,7 +190,17 @@ class AgentTemplateBuilder:
|
|
|
190
190
|
# Include tools field only if agent is clearly restricted (missing core tools or very few tools)
|
|
191
191
|
include_tools_field = not has_core_tools or len(agent_tools) < 6
|
|
192
192
|
|
|
193
|
-
# Build YAML frontmatter using Claude Code's
|
|
193
|
+
# Build YAML frontmatter using Claude Code's minimal format
|
|
194
|
+
# ONLY include fields that Claude Code recognizes
|
|
195
|
+
#
|
|
196
|
+
# REMOVED FIELDS for Claude Code compatibility:
|
|
197
|
+
# - model, color, version, type, source, author
|
|
198
|
+
# These fields caused Claude Code to silently fail agent discovery
|
|
199
|
+
#
|
|
200
|
+
# CLAUDE CODE COMPATIBLE FORMAT:
|
|
201
|
+
# - name: kebab-case agent name (required)
|
|
202
|
+
# - description: when/why to use this agent (required)
|
|
203
|
+
# - tools: comma-separated tool list (optional, only if restricting)
|
|
194
204
|
frontmatter_lines = [
|
|
195
205
|
"---",
|
|
196
206
|
f"name: {claude_code_name}",
|
|
@@ -203,12 +213,6 @@ class AgentTemplateBuilder:
|
|
|
203
213
|
|
|
204
214
|
frontmatter_lines.extend(
|
|
205
215
|
[
|
|
206
|
-
f"model: {model_type}", # Use explicit model type instead of inherit
|
|
207
|
-
f"color: {color}",
|
|
208
|
-
f"version: {agent_version}",
|
|
209
|
-
f"type: {agent_type}",
|
|
210
|
-
f"source: {source_info}", # Track which source provided this agent
|
|
211
|
-
"author: claude-mpm", # Mark as system-managed agent
|
|
212
216
|
"---",
|
|
213
217
|
"",
|
|
214
218
|
]
|