claude-mpm 4.0.32__py3-none-any.whl → 4.1.0__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 +70 -2
- claude_mpm/agents/OUTPUT_STYLE.md +0 -11
- claude_mpm/agents/WORKFLOW.md +14 -2
- claude_mpm/agents/templates/documentation.json +51 -34
- claude_mpm/agents/templates/research.json +0 -11
- claude_mpm/cli/__init__.py +111 -33
- claude_mpm/cli/commands/agent_manager.py +10 -8
- claude_mpm/cli/commands/agents.py +82 -0
- claude_mpm/cli/commands/cleanup_orphaned_agents.py +150 -0
- claude_mpm/cli/commands/mcp_pipx_config.py +199 -0
- claude_mpm/cli/parsers/agents_parser.py +27 -0
- claude_mpm/cli/parsers/base_parser.py +6 -0
- claude_mpm/cli/startup_logging.py +75 -0
- claude_mpm/core/framework_loader.py +173 -84
- claude_mpm/dashboard/static/css/dashboard.css +449 -0
- claude_mpm/dashboard/static/dist/components/agent-inference.js +1 -1
- claude_mpm/dashboard/static/dist/components/event-viewer.js +1 -1
- claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +1 -1
- claude_mpm/dashboard/static/dist/components/module-viewer.js +1 -1
- claude_mpm/dashboard/static/dist/components/session-manager.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/agent-hierarchy.js +774 -0
- claude_mpm/dashboard/static/js/components/agent-inference.js +257 -3
- claude_mpm/dashboard/static/js/components/build-tracker.js +323 -0
- claude_mpm/dashboard/static/js/components/event-viewer.js +168 -39
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +17 -0
- claude_mpm/dashboard/static/js/components/session-manager.js +23 -3
- claude_mpm/dashboard/static/js/components/socket-manager.js +2 -0
- claude_mpm/dashboard/static/js/dashboard.js +207 -31
- claude_mpm/dashboard/static/js/socket-client.js +92 -11
- claude_mpm/dashboard/templates/index.html +1 -0
- claude_mpm/hooks/claude_hooks/connection_pool.py +25 -4
- claude_mpm/hooks/claude_hooks/event_handlers.py +81 -19
- claude_mpm/hooks/claude_hooks/hook_handler.py +125 -163
- claude_mpm/hooks/claude_hooks/hook_handler_eventbus.py +398 -0
- claude_mpm/hooks/claude_hooks/response_tracking.py +10 -0
- claude_mpm/services/agents/deployment/agent_deployment.py +34 -48
- claude_mpm/services/agents/deployment/agent_discovery_service.py +4 -1
- claude_mpm/services/agents/deployment/agent_template_builder.py +20 -11
- claude_mpm/services/agents/deployment/agent_version_manager.py +4 -1
- claude_mpm/services/agents/deployment/agents_directory_resolver.py +10 -25
- claude_mpm/services/agents/deployment/multi_source_deployment_service.py +396 -13
- claude_mpm/services/agents/deployment/pipeline/steps/target_directory_step.py +3 -2
- claude_mpm/services/agents/deployment/strategies/system_strategy.py +10 -3
- claude_mpm/services/agents/deployment/strategies/user_strategy.py +10 -14
- claude_mpm/services/agents/deployment/system_instructions_deployer.py +8 -85
- claude_mpm/services/agents/memory/content_manager.py +98 -105
- claude_mpm/services/event_bus/__init__.py +18 -0
- claude_mpm/services/event_bus/config.py +165 -0
- claude_mpm/services/event_bus/event_bus.py +349 -0
- claude_mpm/services/event_bus/relay.py +297 -0
- claude_mpm/services/events/__init__.py +44 -0
- claude_mpm/services/events/consumers/__init__.py +18 -0
- claude_mpm/services/events/consumers/dead_letter.py +296 -0
- claude_mpm/services/events/consumers/logging.py +183 -0
- claude_mpm/services/events/consumers/metrics.py +242 -0
- claude_mpm/services/events/consumers/socketio.py +376 -0
- claude_mpm/services/events/core.py +470 -0
- claude_mpm/services/events/interfaces.py +230 -0
- claude_mpm/services/events/producers/__init__.py +14 -0
- claude_mpm/services/events/producers/hook.py +269 -0
- claude_mpm/services/events/producers/system.py +327 -0
- claude_mpm/services/mcp_gateway/auto_configure.py +372 -0
- claude_mpm/services/mcp_gateway/core/process_pool.py +411 -0
- claude_mpm/services/mcp_gateway/server/stdio_server.py +13 -0
- claude_mpm/services/monitor_build_service.py +345 -0
- claude_mpm/services/socketio/event_normalizer.py +667 -0
- claude_mpm/services/socketio/handlers/connection.py +81 -23
- claude_mpm/services/socketio/handlers/hook.py +14 -5
- claude_mpm/services/socketio/migration_utils.py +329 -0
- claude_mpm/services/socketio/server/broadcaster.py +26 -33
- claude_mpm/services/socketio/server/core.py +29 -5
- claude_mpm/services/socketio/server/eventbus_integration.py +189 -0
- claude_mpm/services/socketio/server/main.py +25 -0
- {claude_mpm-4.0.32.dist-info → claude_mpm-4.1.0.dist-info}/METADATA +28 -9
- {claude_mpm-4.0.32.dist-info → claude_mpm-4.1.0.dist-info}/RECORD +82 -56
- {claude_mpm-4.0.32.dist-info → claude_mpm-4.1.0.dist-info}/WHEEL +0 -0
- {claude_mpm-4.0.32.dist-info → claude_mpm-4.1.0.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.0.32.dist-info → claude_mpm-4.1.0.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.0.32.dist-info → claude_mpm-4.1.0.dist-info}/top_level.txt +0 -0
|
@@ -19,11 +19,13 @@ import { EventViewer } from '@components/event-viewer.js';
|
|
|
19
19
|
import { ModuleViewer } from '@components/module-viewer.js';
|
|
20
20
|
import { SessionManager } from '@components/session-manager.js';
|
|
21
21
|
import { AgentInference } from '@components/agent-inference.js';
|
|
22
|
+
import { AgentHierarchy } from '@components/agent-hierarchy.js';
|
|
22
23
|
import { UIStateManager } from '@components/ui-state-manager.js';
|
|
23
24
|
import { EventProcessor } from '@components/event-processor.js';
|
|
24
25
|
import { ExportManager } from '@components/export-manager.js';
|
|
25
26
|
import { WorkingDirectoryManager } from '@components/working-directory.js';
|
|
26
27
|
import { FileToolTracker } from '@components/file-tool-tracker.js';
|
|
28
|
+
import { BuildTracker } from '@components/build-tracker.js';
|
|
27
29
|
class Dashboard {
|
|
28
30
|
constructor() {
|
|
29
31
|
// Core components (existing)
|
|
@@ -34,11 +36,13 @@ class Dashboard {
|
|
|
34
36
|
// New modular components
|
|
35
37
|
this.socketManager = null;
|
|
36
38
|
this.agentInference = null;
|
|
39
|
+
this.agentHierarchy = null;
|
|
37
40
|
this.uiStateManager = null;
|
|
38
41
|
this.eventProcessor = null;
|
|
39
42
|
this.exportManager = null;
|
|
40
43
|
this.workingDirectoryManager = null;
|
|
41
44
|
this.fileToolTracker = null;
|
|
45
|
+
this.buildTracker = null;
|
|
42
46
|
|
|
43
47
|
// Initialize the dashboard
|
|
44
48
|
this.init();
|
|
@@ -50,23 +54,75 @@ class Dashboard {
|
|
|
50
54
|
init() {
|
|
51
55
|
console.log('Initializing refactored Claude MPM Dashboard...');
|
|
52
56
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
57
|
+
try {
|
|
58
|
+
// Initialize modules in dependency order
|
|
59
|
+
this.initializeSocketManager();
|
|
60
|
+
this.initializeCoreComponents();
|
|
61
|
+
this.initializeBuildTracker();
|
|
62
|
+
this.initializeAgentInference();
|
|
63
|
+
this.initializeAgentHierarchy();
|
|
64
|
+
this.initializeUIStateManager();
|
|
65
|
+
this.initializeWorkingDirectoryManager();
|
|
66
|
+
this.initializeFileToolTracker();
|
|
67
|
+
this.initializeEventProcessor();
|
|
68
|
+
this.initializeExportManager();
|
|
69
|
+
|
|
70
|
+
// Set up inter-module communication
|
|
71
|
+
this.setupModuleInteractions();
|
|
72
|
+
|
|
73
|
+
// Initialize from URL parameters
|
|
74
|
+
this.initializeFromURL();
|
|
75
|
+
|
|
76
|
+
console.log('Claude MPM Dashboard initialized successfully');
|
|
77
|
+
} catch (error) {
|
|
78
|
+
console.error('Error during dashboard initialization:', error);
|
|
79
|
+
// Re-throw to be caught by DOMContentLoaded handler
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Validate that all critical components are initialized
|
|
86
|
+
* WHY: Ensures dashboard is in a valid state after initialization
|
|
87
|
+
*/
|
|
88
|
+
validateInitialization() {
|
|
89
|
+
const criticalComponents = [
|
|
90
|
+
{ name: 'socketManager', component: this.socketManager },
|
|
91
|
+
{ name: 'eventViewer', component: this.eventViewer },
|
|
92
|
+
{ name: 'agentHierarchy', component: this.agentHierarchy }
|
|
93
|
+
];
|
|
94
|
+
|
|
95
|
+
const missing = criticalComponents.filter(c => !c.component);
|
|
96
|
+
if (missing.length > 0) {
|
|
97
|
+
console.warn('Missing critical components:', missing.map(c => c.name));
|
|
98
|
+
} else {
|
|
99
|
+
console.log('All critical components initialized');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
68
102
|
|
|
69
|
-
|
|
103
|
+
/**
|
|
104
|
+
* Post-initialization setup that requires window.dashboard to be set
|
|
105
|
+
* WHY: Some components need to reference window.dashboard but it's not available
|
|
106
|
+
* during constructor execution. This method is called after the Dashboard instance
|
|
107
|
+
* is assigned to window.dashboard, ensuring proper initialization order.
|
|
108
|
+
*
|
|
109
|
+
* DESIGN DECISION: Separate post-init phase prevents "cannot read property of undefined"
|
|
110
|
+
* errors when components try to access window.dashboard during construction.
|
|
111
|
+
*/
|
|
112
|
+
postInit() {
|
|
113
|
+
try {
|
|
114
|
+
// Set global reference for agent hierarchy after dashboard is available
|
|
115
|
+
if (this.agentHierarchy) {
|
|
116
|
+
window.dashboard.agentHierarchy = this.agentHierarchy;
|
|
117
|
+
console.log('Agent hierarchy global reference set');
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Initialize any other components that need window.dashboard
|
|
121
|
+
this.validateInitialization();
|
|
122
|
+
} catch (error) {
|
|
123
|
+
console.error('Error in dashboard postInit:', error);
|
|
124
|
+
// Continue execution - non-critical error
|
|
125
|
+
}
|
|
70
126
|
}
|
|
71
127
|
|
|
72
128
|
/**
|
|
@@ -98,6 +154,28 @@ class Dashboard {
|
|
|
98
154
|
window.sessionManager = this.sessionManager;
|
|
99
155
|
}
|
|
100
156
|
|
|
157
|
+
/**
|
|
158
|
+
* Initialize build tracker
|
|
159
|
+
*/
|
|
160
|
+
initializeBuildTracker() {
|
|
161
|
+
this.buildTracker = new BuildTracker();
|
|
162
|
+
|
|
163
|
+
// Set the socket client for receiving updates
|
|
164
|
+
this.buildTracker.setSocketClient(this.socketClient);
|
|
165
|
+
|
|
166
|
+
// Mount to header - find the best location
|
|
167
|
+
const headerTitle = document.querySelector('.header-title');
|
|
168
|
+
if (headerTitle) {
|
|
169
|
+
// Insert after the title and status badge
|
|
170
|
+
this.buildTracker.mount(headerTitle);
|
|
171
|
+
} else {
|
|
172
|
+
console.warn('Could not find header-title element for build tracker');
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Make available globally for debugging
|
|
176
|
+
window.buildTracker = this.buildTracker;
|
|
177
|
+
}
|
|
178
|
+
|
|
101
179
|
/**
|
|
102
180
|
* Initialize agent inference system
|
|
103
181
|
*/
|
|
@@ -105,6 +183,28 @@ class Dashboard {
|
|
|
105
183
|
this.agentInference = new AgentInference(this.eventViewer);
|
|
106
184
|
this.agentInference.initialize();
|
|
107
185
|
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Initialize agent hierarchy component
|
|
189
|
+
* WHY: Creates the agent hierarchy visualization component but defers global
|
|
190
|
+
* reference setting to postInit() to avoid initialization order issues.
|
|
191
|
+
*/
|
|
192
|
+
initializeAgentHierarchy() {
|
|
193
|
+
try {
|
|
194
|
+
this.agentHierarchy = new AgentHierarchy(this.agentInference, this.eventViewer);
|
|
195
|
+
// Global reference will be set in postInit() after window.dashboard exists
|
|
196
|
+
console.log('Agent hierarchy component created');
|
|
197
|
+
} catch (error) {
|
|
198
|
+
console.error('Failed to initialize agent hierarchy:', error);
|
|
199
|
+
// Create a stub to prevent further errors
|
|
200
|
+
this.agentHierarchy = {
|
|
201
|
+
render: () => '<div class="error">Agent hierarchy unavailable</div>',
|
|
202
|
+
expandAllNodes: () => {},
|
|
203
|
+
collapseAllNodes: () => {},
|
|
204
|
+
updateWithNewEvents: () => {}
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
}
|
|
108
208
|
|
|
109
209
|
/**
|
|
110
210
|
* Initialize UI state manager
|
|
@@ -154,6 +254,9 @@ class Dashboard {
|
|
|
154
254
|
|
|
155
255
|
// Process agent inference for new events
|
|
156
256
|
this.agentInference.processAgentInference();
|
|
257
|
+
|
|
258
|
+
// Update agent hierarchy with new events
|
|
259
|
+
this.agentHierarchy.updateWithNewEvents(events);
|
|
157
260
|
|
|
158
261
|
// Auto-scroll events list if on events tab
|
|
159
262
|
if (this.uiStateManager.getCurrentTab() === 'events') {
|
|
@@ -291,26 +394,74 @@ class Dashboard {
|
|
|
291
394
|
}
|
|
292
395
|
|
|
293
396
|
/**
|
|
294
|
-
* Render agents tab with
|
|
397
|
+
* Render agents tab with hierarchical view
|
|
295
398
|
*/
|
|
296
399
|
renderAgents() {
|
|
297
400
|
const agentsList = document.getElementById('agents-list');
|
|
298
401
|
if (!agentsList) return;
|
|
299
|
-
|
|
300
|
-
//
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
402
|
+
|
|
403
|
+
// Get filter values
|
|
404
|
+
const searchText = document.getElementById('agents-search-input')?.value || '';
|
|
405
|
+
const agentType = document.getElementById('agents-type-filter')?.value || '';
|
|
406
|
+
|
|
407
|
+
// Build filters object
|
|
408
|
+
const filters = {};
|
|
409
|
+
if (searchText) filters.searchText = searchText;
|
|
410
|
+
if (agentType) filters.agentType = agentType;
|
|
411
|
+
|
|
412
|
+
// Generate hierarchical HTML
|
|
413
|
+
const hierarchyHTML = this.agentHierarchy.render(filters);
|
|
414
|
+
agentsList.innerHTML = hierarchyHTML;
|
|
415
|
+
|
|
416
|
+
// Add expand/collapse all buttons if not present
|
|
417
|
+
this.addHierarchyControls();
|
|
418
|
+
|
|
419
|
+
// Update filter dropdowns with available agent types
|
|
311
420
|
const uniqueInstances = this.agentInference.getUniqueAgentInstances();
|
|
312
421
|
this.updateAgentsFilterDropdowns(uniqueInstances);
|
|
313
422
|
}
|
|
423
|
+
|
|
424
|
+
/**
|
|
425
|
+
* Add hierarchy control buttons
|
|
426
|
+
*/
|
|
427
|
+
addHierarchyControls() {
|
|
428
|
+
const tabFilters = document.querySelector('#agents-tab .tab-filters');
|
|
429
|
+
if (!tabFilters) return;
|
|
430
|
+
|
|
431
|
+
// Check if controls already exist
|
|
432
|
+
if (document.getElementById('hierarchy-controls')) return;
|
|
433
|
+
|
|
434
|
+
// Create control buttons
|
|
435
|
+
const controls = document.createElement('div');
|
|
436
|
+
controls.id = 'hierarchy-controls';
|
|
437
|
+
controls.className = 'hierarchy-controls';
|
|
438
|
+
controls.innerHTML = `
|
|
439
|
+
<button data-action="expand-all"
|
|
440
|
+
class="hierarchy-btn hierarchy-expand-all">
|
|
441
|
+
Expand All
|
|
442
|
+
</button>
|
|
443
|
+
<button data-action="collapse-all"
|
|
444
|
+
class="hierarchy-btn hierarchy-collapse-all">
|
|
445
|
+
Collapse All
|
|
446
|
+
</button>
|
|
447
|
+
`;
|
|
448
|
+
|
|
449
|
+
// Add safe event listeners
|
|
450
|
+
controls.addEventListener('click', (event) => {
|
|
451
|
+
const action = event.target.dataset.action;
|
|
452
|
+
if (action && window.dashboard && window.dashboard.agentHierarchy) {
|
|
453
|
+
if (action === 'expand-all') {
|
|
454
|
+
window.dashboard.agentHierarchy.expandAllNodes();
|
|
455
|
+
window.dashboard.renderAgents();
|
|
456
|
+
} else if (action === 'collapse-all') {
|
|
457
|
+
window.dashboard.agentHierarchy.collapseAllNodes();
|
|
458
|
+
window.dashboard.renderAgents();
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
});
|
|
462
|
+
|
|
463
|
+
tabFilters.appendChild(controls);
|
|
464
|
+
}
|
|
314
465
|
|
|
315
466
|
/**
|
|
316
467
|
* Render tools tab with unique instance view (one row per unique tool call)
|
|
@@ -1810,8 +1961,33 @@ window.showAgentInstanceDetails = function(instanceId) {
|
|
|
1810
1961
|
|
|
1811
1962
|
// Initialize dashboard when page loads
|
|
1812
1963
|
document.addEventListener('DOMContentLoaded', function() {
|
|
1813
|
-
|
|
1814
|
-
|
|
1964
|
+
try {
|
|
1965
|
+
// Create dashboard instance
|
|
1966
|
+
window.dashboard = new Dashboard();
|
|
1967
|
+
|
|
1968
|
+
// Call post-initialization setup that requires window.dashboard
|
|
1969
|
+
// This must happen after window.dashboard is set
|
|
1970
|
+
if (window.dashboard && typeof window.dashboard.postInit === 'function') {
|
|
1971
|
+
window.dashboard.postInit();
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
console.log('Dashboard loaded and initialized successfully');
|
|
1975
|
+
|
|
1976
|
+
// Dispatch custom event to signal dashboard ready
|
|
1977
|
+
document.dispatchEvent(new CustomEvent('dashboardReady', {
|
|
1978
|
+
detail: { dashboard: window.dashboard }
|
|
1979
|
+
}));
|
|
1980
|
+
} catch (error) {
|
|
1981
|
+
console.error('Failed to initialize dashboard:', error);
|
|
1982
|
+
// Show user-friendly error message
|
|
1983
|
+
document.body.innerHTML = `
|
|
1984
|
+
<div style="padding: 20px; font-family: sans-serif;">
|
|
1985
|
+
<h1>Dashboard Initialization Error</h1>
|
|
1986
|
+
<p>The dashboard failed to load properly. Please refresh the page or check the console for details.</p>
|
|
1987
|
+
<pre style="background: #f5f5f5; padding: 10px; border-radius: 4px;">${error.message}</pre>
|
|
1988
|
+
</div>
|
|
1989
|
+
`;
|
|
1990
|
+
}
|
|
1815
1991
|
});
|
|
1816
1992
|
|
|
1817
1993
|
// ES6 Module export
|
|
@@ -16,6 +16,12 @@ class SocketClient {
|
|
|
16
16
|
error: [],
|
|
17
17
|
event: []
|
|
18
18
|
};
|
|
19
|
+
|
|
20
|
+
// Event schema validation
|
|
21
|
+
this.eventSchema = {
|
|
22
|
+
required: ['source', 'type', 'subtype', 'timestamp', 'data'],
|
|
23
|
+
optional: ['event', 'session_id']
|
|
24
|
+
};
|
|
19
25
|
|
|
20
26
|
// Connection state
|
|
21
27
|
this.isConnected = false;
|
|
@@ -41,7 +47,7 @@ class SocketClient {
|
|
|
41
47
|
// Health monitoring
|
|
42
48
|
this.lastPingTime = null;
|
|
43
49
|
this.lastPongTime = null;
|
|
44
|
-
this.pingTimeout =
|
|
50
|
+
this.pingTimeout = 90000; // 90 seconds for health check (more lenient than Socket.IO timeout)
|
|
45
51
|
this.healthCheckInterval = null;
|
|
46
52
|
|
|
47
53
|
// Start periodic status check as fallback mechanism
|
|
@@ -91,11 +97,13 @@ class SocketClient {
|
|
|
91
97
|
autoConnect: true,
|
|
92
98
|
reconnection: true,
|
|
93
99
|
reconnectionDelay: 1000,
|
|
94
|
-
reconnectionDelayMax:
|
|
95
|
-
|
|
96
|
-
timeout:
|
|
100
|
+
reconnectionDelayMax: 5000,
|
|
101
|
+
reconnectionAttempts: Infinity, // Keep trying indefinitely
|
|
102
|
+
timeout: 20000, // Increase connection timeout
|
|
97
103
|
forceNew: true,
|
|
98
|
-
transports: ['websocket', 'polling']
|
|
104
|
+
transports: ['websocket', 'polling'],
|
|
105
|
+
pingInterval: 25000, // Match server setting
|
|
106
|
+
pingTimeout: 60000 // Match server setting
|
|
99
107
|
});
|
|
100
108
|
|
|
101
109
|
this.setupSocketHandlers();
|
|
@@ -187,11 +195,18 @@ class SocketClient {
|
|
|
187
195
|
|
|
188
196
|
// Primary event handler - this is what the server actually emits
|
|
189
197
|
this.socket.on('claude_event', (data) => {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
//
|
|
193
|
-
const
|
|
194
|
-
|
|
198
|
+
console.log('Received claude_event:', data);
|
|
199
|
+
|
|
200
|
+
// Validate event schema
|
|
201
|
+
const validatedEvent = this.validateEventSchema(data);
|
|
202
|
+
if (!validatedEvent) {
|
|
203
|
+
console.warn('Invalid event schema received:', data);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Transform event to match expected format (for backward compatibility)
|
|
208
|
+
const transformedEvent = this.transformEvent(validatedEvent);
|
|
209
|
+
console.log('Transformed event:', transformedEvent);
|
|
195
210
|
this.addEvent(transformedEvent);
|
|
196
211
|
});
|
|
197
212
|
|
|
@@ -628,6 +643,51 @@ class SocketClient {
|
|
|
628
643
|
};
|
|
629
644
|
}
|
|
630
645
|
|
|
646
|
+
/**
|
|
647
|
+
* Validate event against expected schema
|
|
648
|
+
* @param {Object} eventData - Raw event data
|
|
649
|
+
* @returns {Object|null} Validated event or null if invalid
|
|
650
|
+
*/
|
|
651
|
+
validateEventSchema(eventData) {
|
|
652
|
+
if (!eventData || typeof eventData !== 'object') {
|
|
653
|
+
console.warn('Event data is not an object:', eventData);
|
|
654
|
+
return null;
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
// Make a copy to avoid modifying the original
|
|
658
|
+
const validated = { ...eventData };
|
|
659
|
+
|
|
660
|
+
// Check and provide defaults for required fields
|
|
661
|
+
if (!validated.source) {
|
|
662
|
+
validated.source = 'system'; // Default source for backward compatibility
|
|
663
|
+
}
|
|
664
|
+
if (!validated.type) {
|
|
665
|
+
// If there's an event field, use it as the type
|
|
666
|
+
if (validated.event) {
|
|
667
|
+
validated.type = validated.event;
|
|
668
|
+
} else {
|
|
669
|
+
validated.type = 'unknown';
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
if (!validated.subtype) {
|
|
673
|
+
validated.subtype = 'generic';
|
|
674
|
+
}
|
|
675
|
+
if (!validated.timestamp) {
|
|
676
|
+
validated.timestamp = new Date().toISOString();
|
|
677
|
+
}
|
|
678
|
+
if (!validated.data) {
|
|
679
|
+
validated.data = {};
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
// Ensure data field is an object
|
|
683
|
+
if (validated.data && typeof validated.data !== 'object') {
|
|
684
|
+
validated.data = { value: validated.data };
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
console.log('Validated event:', validated);
|
|
688
|
+
return validated;
|
|
689
|
+
}
|
|
690
|
+
|
|
631
691
|
/**
|
|
632
692
|
* Transform received event to match expected dashboard format
|
|
633
693
|
* @param {Object} eventData - Raw event data from server
|
|
@@ -718,7 +778,14 @@ class SocketClient {
|
|
|
718
778
|
Object.keys(eventData.data).forEach(key => {
|
|
719
779
|
// Only copy if not a protected field
|
|
720
780
|
if (!protectedFields.includes(key)) {
|
|
721
|
-
|
|
781
|
+
// Special handling for tool_parameters to ensure it's properly preserved
|
|
782
|
+
// This is critical for file path extraction in file-tool-tracker
|
|
783
|
+
if (key === 'tool_parameters' && typeof eventData.data[key] === 'object') {
|
|
784
|
+
// Deep copy the tool_parameters object to preserve all nested fields
|
|
785
|
+
transformedEvent[key] = JSON.parse(JSON.stringify(eventData.data[key]));
|
|
786
|
+
} else {
|
|
787
|
+
transformedEvent[key] = eventData.data[key];
|
|
788
|
+
}
|
|
722
789
|
} else {
|
|
723
790
|
// Log warning if data field would overwrite a protected field
|
|
724
791
|
console.warn(`Protected field '${key}' in data object was not copied to top level to preserve event structure`);
|
|
@@ -735,9 +802,23 @@ class SocketClient {
|
|
|
735
802
|
type: transformedEvent.type,
|
|
736
803
|
subtype: transformedEvent.subtype,
|
|
737
804
|
tool_name: transformedEvent.tool_name,
|
|
805
|
+
has_tool_parameters: !!transformedEvent.tool_parameters,
|
|
806
|
+
tool_parameters: transformedEvent.tool_parameters,
|
|
738
807
|
has_data: !!transformedEvent.data,
|
|
739
808
|
keys: Object.keys(transformedEvent).filter(k => k !== 'data')
|
|
740
809
|
});
|
|
810
|
+
|
|
811
|
+
// Extra debug logging for file-related tools
|
|
812
|
+
const fileTools = ['Read', 'Write', 'Edit', 'MultiEdit', 'NotebookEdit'];
|
|
813
|
+
if (fileTools.includes(transformedEvent.tool_name)) {
|
|
814
|
+
console.log('File tool event details:', {
|
|
815
|
+
tool_name: transformedEvent.tool_name,
|
|
816
|
+
file_path: transformedEvent.tool_parameters?.file_path,
|
|
817
|
+
path: transformedEvent.tool_parameters?.path,
|
|
818
|
+
notebook_path: transformedEvent.tool_parameters?.notebook_path,
|
|
819
|
+
full_parameters: transformedEvent.tool_parameters
|
|
820
|
+
});
|
|
821
|
+
}
|
|
741
822
|
}
|
|
742
823
|
|
|
743
824
|
return transformedEvent;
|
|
@@ -141,6 +141,7 @@
|
|
|
141
141
|
<div id="connection-status" class="status-badge status-disconnected">
|
|
142
142
|
<span>●</span> Disconnected
|
|
143
143
|
</div>
|
|
144
|
+
<!-- Version display will be inserted here by BuildTracker component -->
|
|
144
145
|
</div>
|
|
145
146
|
<div class="metrics-widget">
|
|
146
147
|
<div class="metric-mini">
|
|
@@ -1,7 +1,18 @@
|
|
|
1
1
|
#!/usr/bin/env python3
|
|
2
|
-
"""Socket.IO connection pool for Claude Code hook handler.
|
|
2
|
+
"""[DEPRECATED] Socket.IO connection pool for Claude Code hook handler.
|
|
3
3
|
|
|
4
|
-
|
|
4
|
+
DEPRECATION NOTICE: As of v4.0.35, this module is deprecated.
|
|
5
|
+
All event emission now goes through the EventBus, which handles
|
|
6
|
+
Socket.IO connections via its relay component. This provides:
|
|
7
|
+
- Single event path (no duplicates)
|
|
8
|
+
- Better separation of concerns
|
|
9
|
+
- Centralized connection management
|
|
10
|
+
- More resilient architecture
|
|
11
|
+
|
|
12
|
+
This module is kept for backward compatibility but will be removed in v5.0.0.
|
|
13
|
+
Please use EventBus.publish() instead of direct Socket.IO emission.
|
|
14
|
+
|
|
15
|
+
Original purpose: Provided connection pooling for Socket.IO clients to reduce
|
|
5
16
|
connection overhead and implement circuit breaker patterns.
|
|
6
17
|
"""
|
|
7
18
|
|
|
@@ -109,7 +120,12 @@ class SocketIOConnectionPool:
|
|
|
109
120
|
if client.connected:
|
|
110
121
|
# Send a keep-alive ping to establish the connection
|
|
111
122
|
try:
|
|
112
|
-
client.emit('ping', {
|
|
123
|
+
client.emit('ping', {
|
|
124
|
+
'type': 'system',
|
|
125
|
+
'subtype': 'ping',
|
|
126
|
+
'timestamp': time.time(),
|
|
127
|
+
'source': 'connection_pool'
|
|
128
|
+
})
|
|
113
129
|
except:
|
|
114
130
|
pass # Ignore ping errors
|
|
115
131
|
return client
|
|
@@ -137,7 +153,12 @@ class SocketIOConnectionPool:
|
|
|
137
153
|
# This helps detect zombie connections
|
|
138
154
|
try:
|
|
139
155
|
# Just emit a ping, don't wait for response (faster)
|
|
140
|
-
client.emit('ping', {
|
|
156
|
+
client.emit('ping', {
|
|
157
|
+
'type': 'system',
|
|
158
|
+
'subtype': 'ping',
|
|
159
|
+
'timestamp': time.time(),
|
|
160
|
+
'source': 'connection_pool'
|
|
161
|
+
})
|
|
141
162
|
return True
|
|
142
163
|
except:
|
|
143
164
|
# If ping fails, connection might be dead
|