claude-mpm 4.1.8__py3-none-any.whl → 4.1.10__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 +26 -1
- claude_mpm/agents/agents_metadata.py +57 -0
- claude_mpm/agents/templates/.claude-mpm/memories/README.md +17 -0
- claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md +3 -0
- claude_mpm/agents/templates/agent-manager.json +263 -17
- claude_mpm/agents/templates/agentic_coder_optimizer.json +222 -0
- claude_mpm/agents/templates/code_analyzer.json +18 -8
- claude_mpm/agents/templates/engineer.json +1 -1
- claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md +39 -0
- claude_mpm/agents/templates/qa.json +1 -1
- claude_mpm/agents/templates/research.json +1 -1
- claude_mpm/cli/__init__.py +4 -0
- claude_mpm/cli/commands/__init__.py +6 -0
- claude_mpm/cli/commands/analyze.py +547 -0
- claude_mpm/cli/commands/analyze_code.py +524 -0
- claude_mpm/cli/commands/configure.py +77 -28
- claude_mpm/cli/commands/configure_tui.py +60 -60
- claude_mpm/cli/commands/debug.py +1387 -0
- claude_mpm/cli/parsers/analyze_code_parser.py +170 -0
- claude_mpm/cli/parsers/analyze_parser.py +135 -0
- claude_mpm/cli/parsers/base_parser.py +29 -0
- claude_mpm/cli/parsers/debug_parser.py +319 -0
- claude_mpm/constants.py +3 -1
- claude_mpm/core/framework_loader.py +148 -6
- claude_mpm/core/log_manager.py +16 -13
- claude_mpm/core/logger.py +1 -1
- claude_mpm/core/unified_agent_registry.py +1 -1
- claude_mpm/dashboard/.claude-mpm/socketio-instances.json +1 -0
- claude_mpm/dashboard/analysis_runner.py +428 -0
- claude_mpm/dashboard/static/built/components/activity-tree.js +2 -0
- claude_mpm/dashboard/static/built/components/agent-inference.js +1 -1
- claude_mpm/dashboard/static/built/components/event-viewer.js +1 -1
- claude_mpm/dashboard/static/built/components/file-tool-tracker.js +1 -1
- claude_mpm/dashboard/static/built/components/module-viewer.js +1 -1
- claude_mpm/dashboard/static/built/components/session-manager.js +1 -1
- claude_mpm/dashboard/static/built/components/working-directory.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/activity.css +549 -0
- claude_mpm/dashboard/static/css/code-tree.css +846 -0
- claude_mpm/dashboard/static/css/dashboard.css +245 -0
- claude_mpm/dashboard/static/dist/components/activity-tree.js +2 -0
- claude_mpm/dashboard/static/dist/components/code-tree.js +2 -0
- claude_mpm/dashboard/static/dist/components/code-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-viewer.js +1 -1
- claude_mpm/dashboard/static/dist/components/session-manager.js +1 -1
- claude_mpm/dashboard/static/dist/components/working-directory.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 +1139 -0
- claude_mpm/dashboard/static/js/components/code-tree.js +1357 -0
- claude_mpm/dashboard/static/js/components/code-viewer.js +480 -0
- claude_mpm/dashboard/static/js/components/event-viewer.js +11 -0
- claude_mpm/dashboard/static/js/components/session-manager.js +40 -4
- claude_mpm/dashboard/static/js/components/socket-manager.js +12 -0
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +4 -0
- claude_mpm/dashboard/static/js/components/working-directory.js +17 -1
- claude_mpm/dashboard/static/js/dashboard.js +39 -0
- claude_mpm/dashboard/static/js/socket-client.js +414 -20
- claude_mpm/dashboard/templates/index.html +184 -4
- claude_mpm/hooks/claude_hooks/hook_handler.py +182 -5
- claude_mpm/hooks/claude_hooks/installer.py +386 -113
- claude_mpm/scripts/claude-hook-handler.sh +161 -0
- claude_mpm/scripts/socketio_daemon.py +121 -8
- claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +2 -2
- claude_mpm/services/agents/deployment/agent_record_service.py +1 -2
- claude_mpm/services/agents/memory/memory_format_service.py +1 -5
- claude_mpm/services/cli/agent_cleanup_service.py +1 -2
- claude_mpm/services/cli/agent_dependency_service.py +1 -1
- claude_mpm/services/cli/agent_validation_service.py +3 -4
- claude_mpm/services/cli/dashboard_launcher.py +2 -3
- claude_mpm/services/cli/startup_checker.py +0 -10
- claude_mpm/services/core/cache_manager.py +1 -2
- claude_mpm/services/core/path_resolver.py +1 -4
- claude_mpm/services/core/service_container.py +2 -2
- claude_mpm/services/diagnostics/checks/instructions_check.py +1 -2
- claude_mpm/services/infrastructure/monitoring/__init__.py +11 -11
- claude_mpm/services/infrastructure/monitoring.py +11 -11
- claude_mpm/services/project/architecture_analyzer.py +1 -1
- claude_mpm/services/project/dependency_analyzer.py +4 -4
- claude_mpm/services/project/language_analyzer.py +3 -3
- claude_mpm/services/project/metrics_collector.py +3 -6
- claude_mpm/services/socketio/handlers/__init__.py +2 -0
- claude_mpm/services/socketio/handlers/code_analysis.py +170 -0
- claude_mpm/services/socketio/handlers/registry.py +2 -0
- claude_mpm/services/socketio/server/connection_manager.py +4 -4
- claude_mpm/services/socketio/server/core.py +100 -11
- claude_mpm/services/socketio/server/main.py +8 -2
- claude_mpm/services/visualization/__init__.py +19 -0
- claude_mpm/services/visualization/mermaid_generator.py +938 -0
- claude_mpm/tools/__main__.py +208 -0
- claude_mpm/tools/code_tree_analyzer.py +778 -0
- claude_mpm/tools/code_tree_builder.py +632 -0
- claude_mpm/tools/code_tree_events.py +318 -0
- claude_mpm/tools/socketio_debug.py +671 -0
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.10.dist-info}/METADATA +1 -1
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.10.dist-info}/RECORD +102 -73
- claude_mpm/agents/schema/agent_schema.json +0 -314
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.10.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.10.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.10.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.10.dist-info}/top_level.txt +0 -0
|
@@ -1,74 +1,303 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Socket.IO Client for Claude MPM Dashboard
|
|
3
|
-
*
|
|
3
|
+
*
|
|
4
|
+
* This module provides real-time WebSocket communication between the Claude MPM dashboard
|
|
5
|
+
* and the backend Socket.IO server. It handles connection management, event processing,
|
|
6
|
+
* retry logic, and health monitoring.
|
|
7
|
+
*
|
|
8
|
+
* Architecture:
|
|
9
|
+
* - Maintains persistent WebSocket connection to Claude MPM backend
|
|
10
|
+
* - Implements robust retry logic with exponential backoff
|
|
11
|
+
* - Provides event queuing during disconnections
|
|
12
|
+
* - Validates event schemas for data integrity
|
|
13
|
+
* - Monitors connection health with ping/pong mechanisms
|
|
14
|
+
*
|
|
15
|
+
* Event Flow:
|
|
16
|
+
* 1. Events from Claude Code hooks → Socket.IO server → Dashboard client
|
|
17
|
+
* 2. Dashboard requests → Socket.IO server → Backend services
|
|
18
|
+
* 3. Status updates → Socket.IO server → All connected clients
|
|
19
|
+
*
|
|
20
|
+
* Thread Safety:
|
|
21
|
+
* - Single-threaded JavaScript execution model ensures safety
|
|
22
|
+
* - Event callbacks are queued and executed sequentially
|
|
23
|
+
* - Connection state changes are atomic
|
|
24
|
+
*
|
|
25
|
+
* Performance Considerations:
|
|
26
|
+
* - Event queue limited to 100 items to prevent memory leaks
|
|
27
|
+
* - Health checks run every 45s to match server ping interval
|
|
28
|
+
* - Exponential backoff prevents connection spam
|
|
29
|
+
* - Lazy event validation reduces overhead
|
|
30
|
+
*
|
|
31
|
+
* Security:
|
|
32
|
+
* - Connects only to localhost to prevent external access
|
|
33
|
+
* - Event schema validation prevents malformed data processing
|
|
34
|
+
* - Connection timeout prevents hanging connections
|
|
35
|
+
*
|
|
36
|
+
* @author Claude MPM Team
|
|
37
|
+
* @version 1.0
|
|
38
|
+
* @since v4.0.25
|
|
4
39
|
*/
|
|
5
40
|
|
|
6
41
|
// Access the global io from window object in ES6 module context
|
|
42
|
+
// WHY: Socket.IO is loaded via CDN in HTML, available as window.io
|
|
7
43
|
const io = window.io;
|
|
8
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Primary Socket.IO client for dashboard communication.
|
|
47
|
+
*
|
|
48
|
+
* Manages WebSocket connection lifecycle, event processing, and error handling.
|
|
49
|
+
* Implements connection resilience with automatic retry and health monitoring.
|
|
50
|
+
*
|
|
51
|
+
* Key Features:
|
|
52
|
+
* - Automatic connection retry with exponential backoff
|
|
53
|
+
* - Event queue management during disconnections
|
|
54
|
+
* - Schema validation for incoming events
|
|
55
|
+
* - Health monitoring with ping/pong
|
|
56
|
+
* - Session management and event history
|
|
57
|
+
*
|
|
58
|
+
* Connection States:
|
|
59
|
+
* - isConnected: Currently connected to server
|
|
60
|
+
* - isConnecting: Connection attempt in progress
|
|
61
|
+
* - disconnectTime: Timestamp of last disconnection
|
|
62
|
+
*
|
|
63
|
+
* Event Processing:
|
|
64
|
+
* - Validates against schema before processing
|
|
65
|
+
* - Queues events during disconnection (max 100)
|
|
66
|
+
* - Maintains event history and session tracking
|
|
67
|
+
*
|
|
68
|
+
* @class SocketClient
|
|
69
|
+
*/
|
|
9
70
|
class SocketClient {
|
|
71
|
+
/**
|
|
72
|
+
* Initialize Socket.IO client with default configuration.
|
|
73
|
+
*
|
|
74
|
+
* Sets up connection management, event processing, and health monitoring.
|
|
75
|
+
* Configures retry logic and event queue management.
|
|
76
|
+
*
|
|
77
|
+
* WHY this initialization approach:
|
|
78
|
+
* - Lazy socket creation allows for port specification
|
|
79
|
+
* - Event queue prevents data loss during reconnections
|
|
80
|
+
* - Health monitoring detects server issues early
|
|
81
|
+
* - Schema validation ensures data integrity
|
|
82
|
+
*
|
|
83
|
+
* @constructor
|
|
84
|
+
*/
|
|
10
85
|
constructor() {
|
|
86
|
+
/**
|
|
87
|
+
* Socket.IO connection instance.
|
|
88
|
+
* @type {Socket|null}
|
|
89
|
+
* @private
|
|
90
|
+
*/
|
|
11
91
|
this.socket = null;
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Current connection port.
|
|
95
|
+
* @type {string|null}
|
|
96
|
+
* @private
|
|
97
|
+
*/
|
|
12
98
|
this.port = null; // Store the current port
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Event callback registry for connection lifecycle events.
|
|
102
|
+
* WHY: Allows multiple components to register for connection events.
|
|
103
|
+
* @type {Object.<string, Function[]>}
|
|
104
|
+
* @private
|
|
105
|
+
*/
|
|
13
106
|
this.connectionCallbacks = {
|
|
14
|
-
connect: [],
|
|
15
|
-
disconnect: [],
|
|
16
|
-
error: [],
|
|
17
|
-
event: []
|
|
107
|
+
connect: [], // Called on successful connection
|
|
108
|
+
disconnect: [], // Called on disconnection
|
|
109
|
+
error: [], // Called on connection errors
|
|
110
|
+
event: [] // Called on incoming events
|
|
18
111
|
};
|
|
19
112
|
|
|
20
|
-
|
|
113
|
+
/**
|
|
114
|
+
* Event schema definition for validation.
|
|
115
|
+
* WHY: Ensures data integrity and prevents processing malformed events.
|
|
116
|
+
* @type {Object}
|
|
117
|
+
* @private
|
|
118
|
+
*/
|
|
21
119
|
this.eventSchema = {
|
|
22
120
|
required: ['source', 'type', 'subtype', 'timestamp', 'data'],
|
|
23
121
|
optional: ['event', 'session_id']
|
|
24
122
|
};
|
|
25
123
|
|
|
26
|
-
|
|
124
|
+
/**
|
|
125
|
+
* Current connection state.
|
|
126
|
+
* @type {boolean}
|
|
127
|
+
* @private
|
|
128
|
+
*/
|
|
27
129
|
this.isConnected = false;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Connection attempt in progress flag.
|
|
133
|
+
* WHY: Prevents multiple simultaneous connection attempts.
|
|
134
|
+
* @type {boolean}
|
|
135
|
+
* @private
|
|
136
|
+
*/
|
|
28
137
|
this.isConnecting = false;
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Timestamp of last successful connection.
|
|
141
|
+
* @type {number|null}
|
|
142
|
+
* @private
|
|
143
|
+
*/
|
|
29
144
|
this.lastConnectTime = null;
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Timestamp of last disconnection.
|
|
148
|
+
* WHY: Used to calculate downtime and trigger reconnection logic.
|
|
149
|
+
* @type {number|null}
|
|
150
|
+
* @private
|
|
151
|
+
*/
|
|
30
152
|
this.disconnectTime = null;
|
|
31
153
|
|
|
32
|
-
|
|
154
|
+
/**
|
|
155
|
+
* Event history storage.
|
|
156
|
+
* WHY: Maintains event history for dashboard display and analysis.
|
|
157
|
+
* @type {Array.<Object>}
|
|
158
|
+
* @private
|
|
159
|
+
*/
|
|
33
160
|
this.events = [];
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Session tracking map.
|
|
164
|
+
* WHY: Groups events by session for better organization.
|
|
165
|
+
* @type {Map<string, Object>}
|
|
166
|
+
* @private
|
|
167
|
+
*/
|
|
34
168
|
this.sessions = new Map();
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Current active session identifier.
|
|
172
|
+
* @type {string|null}
|
|
173
|
+
* @private
|
|
174
|
+
*/
|
|
35
175
|
this.currentSessionId = null;
|
|
36
176
|
|
|
37
|
-
|
|
177
|
+
/**
|
|
178
|
+
* Event queue for disconnection periods.
|
|
179
|
+
* WHY: Prevents event loss during temporary disconnections.
|
|
180
|
+
* @type {Array.<Object>}
|
|
181
|
+
* @private
|
|
182
|
+
*/
|
|
38
183
|
this.eventQueue = [];
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Maximum queue size to prevent memory leaks.
|
|
187
|
+
* WHY: Limits memory usage during extended disconnections.
|
|
188
|
+
* @type {number}
|
|
189
|
+
* @private
|
|
190
|
+
* @const
|
|
191
|
+
*/
|
|
39
192
|
this.maxQueueSize = 100;
|
|
40
193
|
|
|
41
|
-
|
|
194
|
+
/**
|
|
195
|
+
* Current retry attempt counter.
|
|
196
|
+
* WHY: Tracks retry attempts for exponential backoff logic.
|
|
197
|
+
* @type {number}
|
|
198
|
+
* @private
|
|
199
|
+
*/
|
|
42
200
|
this.retryAttempts = 0;
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Maximum retry attempts before giving up.
|
|
204
|
+
* WHY: Prevents infinite retry loops that could impact performance.
|
|
205
|
+
* @type {number}
|
|
206
|
+
* @private
|
|
207
|
+
* @const
|
|
208
|
+
*/
|
|
43
209
|
this.maxRetryAttempts = 5; // Increased from 3 to 5 for better stability
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Retry delay intervals in milliseconds (exponential backoff).
|
|
213
|
+
* WHY: Prevents server overload during connection issues.
|
|
214
|
+
* @type {number[]}
|
|
215
|
+
* @private
|
|
216
|
+
* @const
|
|
217
|
+
*/
|
|
44
218
|
this.retryDelays = [1000, 2000, 3000, 4000, 5000]; // Exponential backoff with 5 attempts
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Map of pending emissions for retry logic.
|
|
222
|
+
* WHY: Tracks failed emissions that need to be retried.
|
|
223
|
+
* @type {Map<string, Object>}
|
|
224
|
+
* @private
|
|
225
|
+
*/
|
|
45
226
|
this.pendingEmissions = new Map(); // Track pending emissions for retry
|
|
46
227
|
|
|
47
|
-
|
|
228
|
+
/**
|
|
229
|
+
* Timestamp of last ping sent to server.
|
|
230
|
+
* WHY: Used for health monitoring and connection validation.
|
|
231
|
+
* @type {number|null}
|
|
232
|
+
* @private
|
|
233
|
+
*/
|
|
48
234
|
this.lastPingTime = null;
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Timestamp of last pong received from server.
|
|
238
|
+
* WHY: Confirms server is responsive and connection is healthy.
|
|
239
|
+
* @type {number|null}
|
|
240
|
+
* @private
|
|
241
|
+
*/
|
|
49
242
|
this.lastPongTime = null;
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Health check timeout in milliseconds.
|
|
246
|
+
* WHY: More lenient than Socket.IO timeout to prevent false positives.
|
|
247
|
+
* @type {number}
|
|
248
|
+
* @private
|
|
249
|
+
* @const
|
|
250
|
+
*/
|
|
50
251
|
this.pingTimeout = 90000; // 90 seconds for health check (more lenient than Socket.IO timeout)
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Health check interval timer.
|
|
255
|
+
* @type {number|null}
|
|
256
|
+
* @private
|
|
257
|
+
*/
|
|
51
258
|
this.healthCheckInterval = null;
|
|
52
259
|
|
|
53
|
-
//
|
|
260
|
+
// Initialize background monitoring
|
|
54
261
|
this.startStatusCheckFallback();
|
|
55
262
|
this.startHealthMonitoring();
|
|
56
263
|
}
|
|
57
264
|
|
|
58
265
|
/**
|
|
59
|
-
* Connect to Socket.IO server
|
|
60
|
-
*
|
|
266
|
+
* Connect to Socket.IO server on specified port.
|
|
267
|
+
*
|
|
268
|
+
* Initiates WebSocket connection to the Claude MPM Socket.IO server.
|
|
269
|
+
* Handles connection conflicts and ensures clean state transitions.
|
|
270
|
+
*
|
|
271
|
+
* Connection Process:
|
|
272
|
+
* 1. Validates port and constructs localhost URL
|
|
273
|
+
* 2. Checks for existing connections and cleans up if needed
|
|
274
|
+
* 3. Delegates to doConnect() for actual connection logic
|
|
275
|
+
*
|
|
276
|
+
* Thread Safety:
|
|
277
|
+
* - Uses setTimeout for async cleanup to prevent race conditions
|
|
278
|
+
* - Connection state flags prevent multiple simultaneous attempts
|
|
279
|
+
*
|
|
280
|
+
* @param {string} [port='8765'] - Port number to connect to (defaults to 8765)
|
|
281
|
+
*
|
|
282
|
+
* @throws {Error} If Socket.IO library is not loaded
|
|
283
|
+
*
|
|
284
|
+
* @example
|
|
285
|
+
* // Connect to default port
|
|
286
|
+
* socketClient.connect();
|
|
287
|
+
*
|
|
288
|
+
* // Connect to specific port
|
|
289
|
+
* socketClient.connect('8766');
|
|
61
290
|
*/
|
|
62
291
|
connect(port = '8765') {
|
|
63
|
-
// Store the port for later use
|
|
292
|
+
// Store the port for later use in reconnections
|
|
64
293
|
this.port = port;
|
|
65
294
|
const url = `http://localhost:${port}`;
|
|
66
295
|
|
|
67
|
-
//
|
|
296
|
+
// WHY this check: Prevents connection conflicts that can cause memory leaks
|
|
68
297
|
if (this.socket && (this.socket.connected || this.socket.connecting)) {
|
|
69
298
|
console.log('Already connected or connecting, disconnecting first...');
|
|
70
299
|
this.socket.disconnect();
|
|
71
|
-
//
|
|
300
|
+
// WHY 100ms delay: Allows cleanup to complete before new connection
|
|
72
301
|
setTimeout(() => this.doConnect(url), 100);
|
|
73
302
|
return;
|
|
74
303
|
}
|
|
@@ -77,8 +306,28 @@ class SocketClient {
|
|
|
77
306
|
}
|
|
78
307
|
|
|
79
308
|
/**
|
|
80
|
-
*
|
|
81
|
-
*
|
|
309
|
+
* Execute the actual Socket.IO connection with full configuration.
|
|
310
|
+
*
|
|
311
|
+
* Creates and configures Socket.IO client with appropriate timeouts,
|
|
312
|
+
* retry logic, and transport settings. Sets up event handlers for
|
|
313
|
+
* connection lifecycle management.
|
|
314
|
+
*
|
|
315
|
+
* Configuration Details:
|
|
316
|
+
* - autoConnect: true - Immediate connection attempt
|
|
317
|
+
* - reconnection: true - Built-in reconnection enabled
|
|
318
|
+
* - pingInterval: 45000ms - Matches server configuration
|
|
319
|
+
* - pingTimeout: 20000ms - Health check timeout
|
|
320
|
+
* - transports: ['websocket', 'polling'] - Fallback options
|
|
321
|
+
*
|
|
322
|
+
* WHY these settings:
|
|
323
|
+
* - Ping intervals must match server to prevent timeouts
|
|
324
|
+
* - Limited reconnection attempts prevent infinite loops
|
|
325
|
+
* - forceNew prevents socket reuse issues
|
|
326
|
+
*
|
|
327
|
+
* @param {string} url - Complete Socket.IO server URL (http://localhost:port)
|
|
328
|
+
* @private
|
|
329
|
+
*
|
|
330
|
+
* @throws {Error} If Socket.IO library is not available
|
|
82
331
|
*/
|
|
83
332
|
doConnect(url) {
|
|
84
333
|
console.log(`Connecting to Socket.IO server at ${url}`);
|
|
@@ -132,6 +381,10 @@ class SocketClient {
|
|
|
132
381
|
|
|
133
382
|
this.notifyConnectionStatus('Connected', 'connected');
|
|
134
383
|
|
|
384
|
+
// Expose socket globally for components that need direct access
|
|
385
|
+
window.socket = this.socket;
|
|
386
|
+
console.log('SocketClient: Exposed socket globally as window.socket');
|
|
387
|
+
|
|
135
388
|
// Emit connect callback
|
|
136
389
|
this.connectionCallbacks.connect.forEach(callback =>
|
|
137
390
|
callback(this.socket.id)
|
|
@@ -222,6 +475,13 @@ class SocketClient {
|
|
|
222
475
|
return;
|
|
223
476
|
}
|
|
224
477
|
|
|
478
|
+
// Check if this is a code analysis event - if so, don't add to events list
|
|
479
|
+
// Code analysis events are handled by the code-tree component and shown in the footer
|
|
480
|
+
if (validatedEvent.type && validatedEvent.type.startsWith('code:')) {
|
|
481
|
+
console.log('Code analysis event received via claude_event, not adding to events list:', validatedEvent.type);
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
|
|
225
485
|
// Transform event to match expected format (for backward compatibility)
|
|
226
486
|
const transformedEvent = this.transformEvent(validatedEvent);
|
|
227
487
|
console.log('Transformed event:', transformedEvent);
|
|
@@ -291,6 +551,48 @@ class SocketClient {
|
|
|
291
551
|
this.addEvent({ type: 'log', subtype: 'entry', timestamp: new Date().toISOString(), data });
|
|
292
552
|
});
|
|
293
553
|
|
|
554
|
+
// Code analysis events - don't add to event list, just pass through
|
|
555
|
+
// These are handled by the code-tree component and shown in the footer
|
|
556
|
+
this.socket.on('code:analysis:queued', (data) => {
|
|
557
|
+
// Don't add to events list - handled by code-tree component
|
|
558
|
+
console.log('Code analysis queued event received, not adding to events list');
|
|
559
|
+
});
|
|
560
|
+
|
|
561
|
+
this.socket.on('code:analysis:accepted', (data) => {
|
|
562
|
+
// Don't add to events list
|
|
563
|
+
console.log('Code analysis accepted event received, not adding to events list');
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
this.socket.on('code:analysis:start', (data) => {
|
|
567
|
+
// Don't add to events list
|
|
568
|
+
console.log('Code analysis start event received, not adding to events list');
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
this.socket.on('code:analysis:complete', (data) => {
|
|
572
|
+
// Don't add to events list
|
|
573
|
+
console.log('Code analysis complete event received, not adding to events list');
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
this.socket.on('code:analysis:error', (data) => {
|
|
577
|
+
// Don't add to events list
|
|
578
|
+
console.log('Code analysis error event received, not adding to events list');
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
this.socket.on('code:file:start', (data) => {
|
|
582
|
+
// Don't add to events list
|
|
583
|
+
console.log('Code file start event received, not adding to events list');
|
|
584
|
+
});
|
|
585
|
+
|
|
586
|
+
this.socket.on('code:node:found', (data) => {
|
|
587
|
+
// Don't add to events list
|
|
588
|
+
console.log('Code node found event received, not adding to events list');
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
this.socket.on('code:analysis:progress', (data) => {
|
|
592
|
+
// Don't add to events list
|
|
593
|
+
console.log('Code analysis progress event received, not adding to events list');
|
|
594
|
+
});
|
|
595
|
+
|
|
294
596
|
this.socket.on('history', (data) => {
|
|
295
597
|
console.log('Received event history:', data);
|
|
296
598
|
if (data && Array.isArray(data.events)) {
|
|
@@ -528,12 +830,44 @@ class SocketClient {
|
|
|
528
830
|
id: sessionId,
|
|
529
831
|
startTime: eventData.timestamp,
|
|
530
832
|
lastActivity: eventData.timestamp,
|
|
531
|
-
eventCount: 0
|
|
833
|
+
eventCount: 0,
|
|
834
|
+
working_directory: null,
|
|
835
|
+
git_branch: null
|
|
532
836
|
});
|
|
533
837
|
}
|
|
534
838
|
const session = this.sessions.get(sessionId);
|
|
535
839
|
session.lastActivity = eventData.timestamp;
|
|
536
840
|
session.eventCount++;
|
|
841
|
+
|
|
842
|
+
// Extract working directory from event data if available (prioritize newer data)
|
|
843
|
+
// Check multiple possible locations for working directory
|
|
844
|
+
const possiblePaths = [
|
|
845
|
+
eventData.data.cwd,
|
|
846
|
+
eventData.data.working_directory,
|
|
847
|
+
eventData.data.working_dir,
|
|
848
|
+
eventData.data.workingDirectory,
|
|
849
|
+
eventData.data.instance_info?.working_dir,
|
|
850
|
+
eventData.data.instance_info?.working_directory,
|
|
851
|
+
eventData.data.instance_info?.cwd,
|
|
852
|
+
eventData.cwd,
|
|
853
|
+
eventData.working_directory,
|
|
854
|
+
eventData.working_dir
|
|
855
|
+
];
|
|
856
|
+
|
|
857
|
+
for (const path of possiblePaths) {
|
|
858
|
+
if (path && typeof path === 'string' && path.trim()) {
|
|
859
|
+
session.working_directory = path;
|
|
860
|
+
console.log(`[SOCKET-CLIENT] Found working directory for session ${sessionId}:`, path);
|
|
861
|
+
break;
|
|
862
|
+
}
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
// Extract git branch if available
|
|
866
|
+
if (eventData.data.git_branch) {
|
|
867
|
+
session.git_branch = eventData.data.git_branch;
|
|
868
|
+
} else if (eventData.data.instance_info && eventData.data.instance_info.git_branch) {
|
|
869
|
+
session.git_branch = eventData.data.instance_info.git_branch;
|
|
870
|
+
}
|
|
537
871
|
}
|
|
538
872
|
|
|
539
873
|
if (notify) {
|
|
@@ -604,6 +938,32 @@ class SocketClient {
|
|
|
604
938
|
this.connectionCallbacks.event.push(callback);
|
|
605
939
|
}
|
|
606
940
|
|
|
941
|
+
/**
|
|
942
|
+
* Subscribe to socket events (proxy to underlying socket)
|
|
943
|
+
* @param {string} event - Event name
|
|
944
|
+
* @param {Function} callback - Callback function
|
|
945
|
+
*/
|
|
946
|
+
on(event, callback) {
|
|
947
|
+
if (this.socket) {
|
|
948
|
+
return this.socket.on(event, callback);
|
|
949
|
+
} else {
|
|
950
|
+
console.warn(`Cannot subscribe to '${event}': socket not initialized`);
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
/**
|
|
955
|
+
* Unsubscribe from socket events (proxy to underlying socket)
|
|
956
|
+
* @param {string} event - Event name
|
|
957
|
+
* @param {Function} callback - Callback function (optional)
|
|
958
|
+
*/
|
|
959
|
+
off(event, callback) {
|
|
960
|
+
if (this.socket) {
|
|
961
|
+
return this.socket.off(event, callback);
|
|
962
|
+
} else {
|
|
963
|
+
console.warn(`Cannot unsubscribe from '${event}': socket not initialized`);
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
|
|
607
967
|
/**
|
|
608
968
|
* Notify connection status change
|
|
609
969
|
* @param {string} status - Status message
|
|
@@ -772,6 +1132,11 @@ class SocketClient {
|
|
|
772
1132
|
transformedEvent.type = 'hook';
|
|
773
1133
|
transformedEvent.subtype = subtype;
|
|
774
1134
|
}
|
|
1135
|
+
// Transform 'code:*' events to proper code type
|
|
1136
|
+
else if (type.startsWith('code:')) {
|
|
1137
|
+
transformedEvent.type = 'code';
|
|
1138
|
+
transformedEvent.subtype = type.substring(5); // Remove 'code:' prefix
|
|
1139
|
+
}
|
|
775
1140
|
// Transform other dotted types like 'session.started' -> type: 'session', subtype: 'started'
|
|
776
1141
|
else if (type.includes('.')) {
|
|
777
1142
|
const [mainType, ...subtypeParts] = type.split('.');
|
|
@@ -820,11 +1185,40 @@ class SocketClient {
|
|
|
820
1185
|
transformedEvent.data = eventData.data;
|
|
821
1186
|
}
|
|
822
1187
|
|
|
1188
|
+
// Add hook_event_name for ActivityTree compatibility
|
|
1189
|
+
// Map the type/subtype structure to the expected hook_event_name format
|
|
1190
|
+
if (transformedEvent.type === 'hook') {
|
|
1191
|
+
if (transformedEvent.subtype === 'pre_tool') {
|
|
1192
|
+
transformedEvent.hook_event_name = 'PreToolUse';
|
|
1193
|
+
} else if (transformedEvent.subtype === 'post_tool') {
|
|
1194
|
+
transformedEvent.hook_event_name = 'PostToolUse';
|
|
1195
|
+
} else if (transformedEvent.subtype === 'subagent_start') {
|
|
1196
|
+
transformedEvent.hook_event_name = 'SubagentStart';
|
|
1197
|
+
} else if (transformedEvent.subtype === 'subagent_stop') {
|
|
1198
|
+
transformedEvent.hook_event_name = 'SubagentStop';
|
|
1199
|
+
} else if (transformedEvent.subtype === 'todo_write') {
|
|
1200
|
+
transformedEvent.hook_event_name = 'TodoWrite';
|
|
1201
|
+
} else if (transformedEvent.subtype === 'start') {
|
|
1202
|
+
transformedEvent.hook_event_name = 'Start';
|
|
1203
|
+
} else if (transformedEvent.subtype === 'stop') {
|
|
1204
|
+
transformedEvent.hook_event_name = 'Stop';
|
|
1205
|
+
}
|
|
1206
|
+
} else if (transformedEvent.type === 'subagent') {
|
|
1207
|
+
if (transformedEvent.subtype === 'start') {
|
|
1208
|
+
transformedEvent.hook_event_name = 'SubagentStart';
|
|
1209
|
+
} else if (transformedEvent.subtype === 'stop') {
|
|
1210
|
+
transformedEvent.hook_event_name = 'SubagentStop';
|
|
1211
|
+
}
|
|
1212
|
+
} else if (transformedEvent.type === 'todo' && transformedEvent.subtype === 'updated') {
|
|
1213
|
+
transformedEvent.hook_event_name = 'TodoWrite';
|
|
1214
|
+
}
|
|
1215
|
+
|
|
823
1216
|
// Debug logging for tool events
|
|
824
1217
|
if (transformedEvent.type === 'hook' && (transformedEvent.subtype === 'pre_tool' || transformedEvent.subtype === 'post_tool')) {
|
|
825
1218
|
console.log('Transformed tool event:', {
|
|
826
1219
|
type: transformedEvent.type,
|
|
827
1220
|
subtype: transformedEvent.subtype,
|
|
1221
|
+
hook_event_name: transformedEvent.hook_event_name,
|
|
828
1222
|
tool_name: transformedEvent.tool_name,
|
|
829
1223
|
has_tool_parameters: !!transformedEvent.tool_parameters,
|
|
830
1224
|
tool_parameters: transformedEvent.tool_parameters,
|