claude-mpm 4.1.11__py3-none-any.whl → 4.1.13__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 +1 -1
- claude_mpm/cli/commands/monitor.py +88 -627
- claude_mpm/cli/commands/mpm_init.py +127 -107
- claude_mpm/cli/commands/mpm_init_handler.py +24 -23
- claude_mpm/cli/parsers/mpm_init_parser.py +34 -28
- 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/static/built/components/activity-tree.js +1 -1
- claude_mpm/dashboard/static/built/components/code-tree.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 +1239 -267
- claude_mpm/dashboard/static/css/dashboard.css +511 -0
- claude_mpm/dashboard/static/dist/components/activity-tree.js +1 -1
- claude_mpm/dashboard/static/dist/components/code-tree.js +1 -1
- claude_mpm/dashboard/static/dist/components/module-viewer.js +1 -1
- claude_mpm/dashboard/static/dist/dashboard.js +1 -1
- claude_mpm/dashboard/static/dist/socket-client.js +1 -1
- claude_mpm/dashboard/static/js/components/activity-tree.js +1193 -892
- claude_mpm/dashboard/static/js/components/build-tracker.js +15 -13
- claude_mpm/dashboard/static/js/components/code-tree.js +534 -143
- claude_mpm/dashboard/static/js/components/module-viewer.js +21 -7
- claude_mpm/dashboard/static/js/components/unified-data-viewer.js +1066 -0
- claude_mpm/dashboard/static/js/connection-manager.js +1 -1
- claude_mpm/dashboard/static/js/dashboard.js +227 -84
- claude_mpm/dashboard/static/js/socket-client.js +2 -2
- claude_mpm/dashboard/templates/index.html +100 -23
- claude_mpm/services/agents/deployment/agent_template_builder.py +11 -7
- claude_mpm/services/cli/socketio_manager.py +39 -8
- claude_mpm/services/infrastructure/monitoring.py +1 -1
- claude_mpm/services/socketio/handlers/code_analysis.py +83 -136
- claude_mpm/tools/code_tree_analyzer.py +290 -202
- {claude_mpm-4.1.11.dist-info → claude_mpm-4.1.13.dist-info}/METADATA +1 -1
- {claude_mpm-4.1.11.dist-info → claude_mpm-4.1.13.dist-info}/RECORD +41 -39
- {claude_mpm-4.1.11.dist-info → claude_mpm-4.1.13.dist-info}/WHEEL +0 -0
- {claude_mpm-4.1.11.dist-info → claude_mpm-4.1.13.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.1.11.dist-info → claude_mpm-4.1.13.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.1.11.dist-info → claude_mpm-4.1.13.dist-info}/top_level.txt +0 -0
|
@@ -172,10 +172,18 @@ class SocketIOManager(ISocketIOManager):
|
|
|
172
172
|
|
|
173
173
|
# Check if server already running on this port
|
|
174
174
|
if self.is_server_running(target_port):
|
|
175
|
-
|
|
176
|
-
|
|
175
|
+
# Verify the server is healthy and responding
|
|
176
|
+
if self.wait_for_server(target_port, timeout=2):
|
|
177
|
+
self.logger.info(
|
|
178
|
+
f"Healthy Socket.IO server already running on port {target_port}"
|
|
179
|
+
)
|
|
180
|
+
return True, self.get_server_info(target_port)
|
|
181
|
+
# Server exists but not responding, try to clean it up
|
|
182
|
+
self.logger.warning(
|
|
183
|
+
f"Socket.IO server on port {target_port} not responding, attempting cleanup"
|
|
177
184
|
)
|
|
178
|
-
|
|
185
|
+
self.stop_server(port=target_port, timeout=5)
|
|
186
|
+
# Continue with starting a new server
|
|
179
187
|
|
|
180
188
|
# Ensure dependencies are available
|
|
181
189
|
deps_ok, error_msg = self.ensure_dependencies()
|
|
@@ -459,14 +467,37 @@ class SocketIOManager(ISocketIOManager):
|
|
|
459
467
|
Returns:
|
|
460
468
|
Available port number
|
|
461
469
|
"""
|
|
462
|
-
#
|
|
470
|
+
# First check if our Socket.IO server is already running on the preferred port
|
|
471
|
+
if self.is_server_running(preferred_port):
|
|
472
|
+
# Check if it's healthy
|
|
473
|
+
if self.wait_for_server(preferred_port, timeout=2):
|
|
474
|
+
self.logger.info(
|
|
475
|
+
f"Healthy Socket.IO server already running on port {preferred_port}"
|
|
476
|
+
)
|
|
477
|
+
return preferred_port
|
|
478
|
+
self.logger.warning(
|
|
479
|
+
f"Socket.IO server on port {preferred_port} not responding, will try to restart"
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
# Try preferred port first if available
|
|
463
483
|
if self.port_manager.is_port_available(preferred_port):
|
|
464
484
|
return preferred_port
|
|
465
485
|
|
|
466
|
-
# Find alternative port
|
|
467
|
-
available_port = self.port_manager.
|
|
468
|
-
|
|
469
|
-
|
|
486
|
+
# Find alternative port using the correct method name
|
|
487
|
+
available_port = self.port_manager.find_available_port(
|
|
488
|
+
preferred_port=preferred_port, reclaim=True
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
if available_port:
|
|
492
|
+
self.logger.info(
|
|
493
|
+
f"Port {preferred_port} unavailable, using {available_port}"
|
|
494
|
+
)
|
|
495
|
+
return available_port
|
|
496
|
+
# If no port found, raise an error
|
|
497
|
+
raise RuntimeError(
|
|
498
|
+
f"No available ports in range {self.port_manager.PORT_RANGE.start}-"
|
|
499
|
+
f"{self.port_manager.PORT_RANGE.stop-1}"
|
|
500
|
+
)
|
|
470
501
|
|
|
471
502
|
def ensure_dependencies(self) -> Tuple[bool, Optional[str]]:
|
|
472
503
|
"""
|
|
@@ -30,7 +30,7 @@ For backward compatibility, legacy classes are still available:
|
|
|
30
30
|
"""
|
|
31
31
|
|
|
32
32
|
# Re-export all components from the modular implementation
|
|
33
|
-
from .monitoring import (
|
|
33
|
+
from .monitoring import (
|
|
34
34
|
AdvancedHealthMonitor,
|
|
35
35
|
HealthChecker,
|
|
36
36
|
HealthCheckResult,
|
|
@@ -216,56 +216,22 @@ class CodeAnalysisEventHandler(BaseEventHandler):
|
|
|
216
216
|
)
|
|
217
217
|
return
|
|
218
218
|
|
|
219
|
-
#
|
|
220
|
-
#
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
f"Access denied - path outside working directory: {path}"
|
|
229
|
-
)
|
|
230
|
-
await self.server.core.sio.emit(
|
|
231
|
-
"code:analysis:error",
|
|
232
|
-
{
|
|
233
|
-
"error": f"Access denied: Path outside working directory: {path}",
|
|
234
|
-
"request_id": data.get("request_id"),
|
|
235
|
-
"path": path,
|
|
236
|
-
},
|
|
237
|
-
room=sid,
|
|
238
|
-
)
|
|
239
|
-
return
|
|
219
|
+
# SECURITY: Validate the requested path
|
|
220
|
+
# Allow access to the explicitly chosen working directory and its subdirectories
|
|
221
|
+
requested_path = Path(path).absolute()
|
|
222
|
+
|
|
223
|
+
# For now, we trust the frontend to send valid paths
|
|
224
|
+
# In production, you might want to maintain a server-side list of allowed directories
|
|
225
|
+
# or implement a more sophisticated permission system
|
|
226
|
+
|
|
227
|
+
# Basic sanity checks are done below after creating the Path object
|
|
240
228
|
|
|
241
229
|
ignore_patterns = data.get("ignore_patterns", [])
|
|
242
230
|
request_id = data.get("request_id")
|
|
243
|
-
show_hidden_files = data.get("show_hidden_files", False)
|
|
244
|
-
|
|
245
|
-
# Extensive debug logging
|
|
246
|
-
self.logger.info(f"[DEBUG] handle_discover_top_level START")
|
|
247
|
-
self.logger.info(f"[DEBUG] Received show_hidden_files={show_hidden_files} (type: {type(show_hidden_files)})")
|
|
248
|
-
self.logger.info(f"[DEBUG] Current analyzer exists: {self.code_analyzer is not None}")
|
|
249
|
-
if self.code_analyzer:
|
|
250
|
-
current_value = getattr(self.code_analyzer, 'show_hidden_files', 'NOT_FOUND')
|
|
251
|
-
self.logger.info(f"[DEBUG] Current analyzer show_hidden_files={current_value}")
|
|
252
|
-
self.logger.info(f"[DEBUG] Full request data: {data}")
|
|
253
231
|
|
|
254
232
|
try:
|
|
255
|
-
# Create analyzer if needed
|
|
256
|
-
|
|
257
|
-
need_recreate = (
|
|
258
|
-
not self.code_analyzer or
|
|
259
|
-
current_show_hidden != show_hidden_files
|
|
260
|
-
)
|
|
261
|
-
|
|
262
|
-
self.logger.info(f"[DEBUG] Analyzer recreation check:")
|
|
263
|
-
self.logger.info(f"[DEBUG] - Analyzer exists: {self.code_analyzer is not None}")
|
|
264
|
-
self.logger.info(f"[DEBUG] - Current show_hidden: {current_show_hidden}")
|
|
265
|
-
self.logger.info(f"[DEBUG] - Requested show_hidden: {show_hidden_files}")
|
|
266
|
-
self.logger.info(f"[DEBUG] - Need recreate: {need_recreate}")
|
|
267
|
-
|
|
268
|
-
if need_recreate:
|
|
233
|
+
# Create analyzer if needed
|
|
234
|
+
if not self.code_analyzer:
|
|
269
235
|
# Create a custom emitter that sends to Socket.IO
|
|
270
236
|
emitter = CodeTreeEventEmitter(use_stdout=False)
|
|
271
237
|
# Override emit method to send to Socket.IO
|
|
@@ -276,14 +242,14 @@ class CodeAnalysisEventHandler(BaseEventHandler):
|
|
|
276
242
|
):
|
|
277
243
|
# Keep the original event format with colons - frontend expects this!
|
|
278
244
|
# The frontend listens for 'code:directory:discovered' not 'code.directory.discovered'
|
|
279
|
-
|
|
245
|
+
|
|
280
246
|
# Special handling for 'info' events - they should be passed through directly
|
|
281
|
-
if event_type ==
|
|
247
|
+
if event_type == "info":
|
|
282
248
|
# INFO events for granular tracking
|
|
283
249
|
loop = asyncio.get_event_loop()
|
|
284
250
|
loop.create_task(
|
|
285
251
|
self.server.core.sio.emit(
|
|
286
|
-
|
|
252
|
+
"info", {"request_id": request_id, **event_data}
|
|
287
253
|
)
|
|
288
254
|
)
|
|
289
255
|
else:
|
|
@@ -298,14 +264,9 @@ class CodeAnalysisEventHandler(BaseEventHandler):
|
|
|
298
264
|
original_emit(event_type, event_data, batch)
|
|
299
265
|
|
|
300
266
|
emitter.emit = socket_emit
|
|
301
|
-
# Initialize CodeTreeAnalyzer with emitter keyword argument
|
|
302
|
-
self.logger.info(
|
|
303
|
-
self.code_analyzer = CodeTreeAnalyzer(emitter=emitter
|
|
304
|
-
self.logger.info(f"[DEBUG] CodeTreeAnalyzer created:")
|
|
305
|
-
self.logger.info(f"[DEBUG] - analyzer.show_hidden_files={self.code_analyzer.show_hidden_files}")
|
|
306
|
-
self.logger.info(f"[DEBUG] - gitignore_manager.show_hidden_files={self.code_analyzer.gitignore_manager.show_hidden_files}")
|
|
307
|
-
else:
|
|
308
|
-
self.logger.info(f"[DEBUG] Reusing existing analyzer with show_hidden_files={self.code_analyzer.show_hidden_files}")
|
|
267
|
+
# Initialize CodeTreeAnalyzer with emitter keyword argument
|
|
268
|
+
self.logger.info("Creating CodeTreeAnalyzer")
|
|
269
|
+
self.code_analyzer = CodeTreeAnalyzer(emitter=emitter)
|
|
309
270
|
|
|
310
271
|
# Use the provided path as-is - the frontend sends the absolute path
|
|
311
272
|
# Make sure we're using an absolute path
|
|
@@ -341,17 +302,7 @@ class CodeAnalysisEventHandler(BaseEventHandler):
|
|
|
341
302
|
f"Discovering top-level contents of: {directory.absolute()}"
|
|
342
303
|
)
|
|
343
304
|
|
|
344
|
-
# Log before discovery
|
|
345
|
-
self.logger.info(f"[DEBUG] About to discover with analyzer.show_hidden_files={self.code_analyzer.show_hidden_files}")
|
|
346
|
-
|
|
347
305
|
result = self.code_analyzer.discover_top_level(directory, ignore_patterns)
|
|
348
|
-
|
|
349
|
-
# Log what we got back
|
|
350
|
-
num_items = len(result.get("children", []))
|
|
351
|
-
dotfiles = [c for c in result.get("children", []) if c.get("name", "").startswith(".")]
|
|
352
|
-
self.logger.info(f"[DEBUG] Discovery result: {num_items} items, {len(dotfiles)} dotfiles")
|
|
353
|
-
if dotfiles:
|
|
354
|
-
self.logger.info(f"[DEBUG] Dotfiles found: {[d.get('name') for d in dotfiles]}")
|
|
355
306
|
|
|
356
307
|
# Send result to client with correct event name for top level discovery
|
|
357
308
|
await self.server.core.sio.emit(
|
|
@@ -404,7 +355,6 @@ class CodeAnalysisEventHandler(BaseEventHandler):
|
|
|
404
355
|
path = data.get("path")
|
|
405
356
|
ignore_patterns = data.get("ignore_patterns", [])
|
|
406
357
|
request_id = data.get("request_id")
|
|
407
|
-
show_hidden_files = data.get("show_hidden_files", False)
|
|
408
358
|
|
|
409
359
|
if not path:
|
|
410
360
|
await self.server.core.sio.emit(
|
|
@@ -432,21 +382,34 @@ class CodeAnalysisEventHandler(BaseEventHandler):
|
|
|
432
382
|
)
|
|
433
383
|
return
|
|
434
384
|
|
|
435
|
-
#
|
|
436
|
-
#
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
385
|
+
# SECURITY: Validate the requested path
|
|
386
|
+
# Allow access to the explicitly chosen working directory and its subdirectories
|
|
387
|
+
requested_path = Path(path).absolute()
|
|
388
|
+
|
|
389
|
+
# For now, we trust the frontend to send valid paths
|
|
390
|
+
# In production, you might want to maintain a server-side list of allowed directories
|
|
391
|
+
# or implement a more sophisticated permission system
|
|
392
|
+
|
|
393
|
+
# Basic sanity checks
|
|
394
|
+
if not requested_path.exists():
|
|
395
|
+
self.logger.warning(f"Path does not exist: {path}")
|
|
396
|
+
await self.server.core.sio.emit(
|
|
397
|
+
"code:analysis:error",
|
|
398
|
+
{
|
|
399
|
+
"error": f"Path does not exist: {path}",
|
|
400
|
+
"request_id": request_id,
|
|
401
|
+
"path": path,
|
|
402
|
+
},
|
|
403
|
+
room=sid,
|
|
445
404
|
)
|
|
405
|
+
return
|
|
406
|
+
|
|
407
|
+
if not requested_path.is_dir():
|
|
408
|
+
self.logger.warning(f"Path is not a directory: {path}")
|
|
446
409
|
await self.server.core.sio.emit(
|
|
447
410
|
"code:analysis:error",
|
|
448
411
|
{
|
|
449
|
-
"error": f"
|
|
412
|
+
"error": f"Path is not a directory: {path}",
|
|
450
413
|
"request_id": request_id,
|
|
451
414
|
"path": path,
|
|
452
415
|
},
|
|
@@ -455,20 +418,8 @@ class CodeAnalysisEventHandler(BaseEventHandler):
|
|
|
455
418
|
return
|
|
456
419
|
|
|
457
420
|
try:
|
|
458
|
-
# Ensure analyzer exists
|
|
459
|
-
|
|
460
|
-
need_recreate = (
|
|
461
|
-
not self.code_analyzer or
|
|
462
|
-
current_show_hidden != show_hidden_files
|
|
463
|
-
)
|
|
464
|
-
|
|
465
|
-
self.logger.info(f"[DEBUG] Analyzer recreation check:")
|
|
466
|
-
self.logger.info(f"[DEBUG] - Analyzer exists: {self.code_analyzer is not None}")
|
|
467
|
-
self.logger.info(f"[DEBUG] - Current show_hidden: {current_show_hidden}")
|
|
468
|
-
self.logger.info(f"[DEBUG] - Requested show_hidden: {show_hidden_files}")
|
|
469
|
-
self.logger.info(f"[DEBUG] - Need recreate: {need_recreate}")
|
|
470
|
-
|
|
471
|
-
if need_recreate:
|
|
421
|
+
# Ensure analyzer exists
|
|
422
|
+
if not self.code_analyzer:
|
|
472
423
|
emitter = CodeTreeEventEmitter(use_stdout=False)
|
|
473
424
|
# Override emit method to send to Socket.IO
|
|
474
425
|
original_emit = emitter.emit
|
|
@@ -478,14 +429,14 @@ class CodeAnalysisEventHandler(BaseEventHandler):
|
|
|
478
429
|
):
|
|
479
430
|
# Keep the original event format with colons - frontend expects this!
|
|
480
431
|
# The frontend listens for 'code:directory:discovered' not 'code.directory.discovered'
|
|
481
|
-
|
|
432
|
+
|
|
482
433
|
# Special handling for 'info' events - they should be passed through directly
|
|
483
|
-
if event_type ==
|
|
434
|
+
if event_type == "info":
|
|
484
435
|
# INFO events for granular tracking
|
|
485
436
|
loop = asyncio.get_event_loop()
|
|
486
437
|
loop.create_task(
|
|
487
438
|
self.server.core.sio.emit(
|
|
488
|
-
|
|
439
|
+
"info", {"request_id": request_id, **event_data}
|
|
489
440
|
)
|
|
490
441
|
)
|
|
491
442
|
else:
|
|
@@ -499,17 +450,19 @@ class CodeAnalysisEventHandler(BaseEventHandler):
|
|
|
499
450
|
original_emit(event_type, event_data, batch)
|
|
500
451
|
|
|
501
452
|
emitter.emit = socket_emit
|
|
502
|
-
# Initialize CodeTreeAnalyzer with emitter keyword argument
|
|
503
|
-
self.logger.info(
|
|
504
|
-
self.code_analyzer = CodeTreeAnalyzer(emitter=emitter
|
|
505
|
-
self.logger.info(f"[DEBUG] CodeTreeAnalyzer created, analyzer.show_hidden_files={self.code_analyzer.show_hidden_files}")
|
|
506
|
-
self.logger.info(f"[DEBUG] GitignoreManager.show_hidden_files={self.code_analyzer.gitignore_manager.show_hidden_files}")
|
|
507
|
-
else:
|
|
508
|
-
self.logger.info(f"[DEBUG] Reusing analyzer with show_hidden_files={self.code_analyzer.show_hidden_files}")
|
|
453
|
+
# Initialize CodeTreeAnalyzer with emitter keyword argument
|
|
454
|
+
self.logger.info("Creating CodeTreeAnalyzer")
|
|
455
|
+
self.code_analyzer = CodeTreeAnalyzer(emitter=emitter)
|
|
509
456
|
|
|
510
457
|
# Discover directory
|
|
511
458
|
result = self.code_analyzer.discover_directory(path, ignore_patterns)
|
|
512
459
|
|
|
460
|
+
# Log what we're sending
|
|
461
|
+
self.logger.info(
|
|
462
|
+
f"Discovery result for {path}: {len(result.get('children', []))} children found"
|
|
463
|
+
)
|
|
464
|
+
self.logger.debug(f"Full result: {result}")
|
|
465
|
+
|
|
513
466
|
# Send result with correct event name (using colons, not dots!)
|
|
514
467
|
await self.server.core.sio.emit(
|
|
515
468
|
"code:directory:discovered",
|
|
@@ -571,20 +524,30 @@ class CodeAnalysisEventHandler(BaseEventHandler):
|
|
|
571
524
|
)
|
|
572
525
|
return
|
|
573
526
|
|
|
574
|
-
#
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
self.
|
|
582
|
-
|
|
527
|
+
# SECURITY: Validate the requested file path
|
|
528
|
+
# Allow access to files within the explicitly chosen working directory
|
|
529
|
+
requested_path = Path(path).absolute()
|
|
530
|
+
|
|
531
|
+
# Basic sanity checks
|
|
532
|
+
if not requested_path.exists():
|
|
533
|
+
self.logger.warning(f"File does not exist: {path}")
|
|
534
|
+
await self.server.core.sio.emit(
|
|
535
|
+
"code:analysis:error",
|
|
536
|
+
{
|
|
537
|
+
"error": f"File does not exist: {path}",
|
|
538
|
+
"request_id": request_id,
|
|
539
|
+
"path": path,
|
|
540
|
+
},
|
|
541
|
+
room=sid,
|
|
583
542
|
)
|
|
543
|
+
return
|
|
544
|
+
|
|
545
|
+
if not requested_path.is_file():
|
|
546
|
+
self.logger.warning(f"Path is not a file: {path}")
|
|
584
547
|
await self.server.core.sio.emit(
|
|
585
548
|
"code:analysis:error",
|
|
586
549
|
{
|
|
587
|
-
"error": f"
|
|
550
|
+
"error": f"Path is not a file: {path}",
|
|
588
551
|
"request_id": request_id,
|
|
589
552
|
"path": path,
|
|
590
553
|
},
|
|
@@ -593,20 +556,8 @@ class CodeAnalysisEventHandler(BaseEventHandler):
|
|
|
593
556
|
return
|
|
594
557
|
|
|
595
558
|
try:
|
|
596
|
-
# Ensure analyzer exists
|
|
597
|
-
|
|
598
|
-
need_recreate = (
|
|
599
|
-
not self.code_analyzer or
|
|
600
|
-
current_show_hidden != show_hidden_files
|
|
601
|
-
)
|
|
602
|
-
|
|
603
|
-
self.logger.info(f"[DEBUG] Analyzer recreation check:")
|
|
604
|
-
self.logger.info(f"[DEBUG] - Analyzer exists: {self.code_analyzer is not None}")
|
|
605
|
-
self.logger.info(f"[DEBUG] - Current show_hidden: {current_show_hidden}")
|
|
606
|
-
self.logger.info(f"[DEBUG] - Requested show_hidden: {show_hidden_files}")
|
|
607
|
-
self.logger.info(f"[DEBUG] - Need recreate: {need_recreate}")
|
|
608
|
-
|
|
609
|
-
if need_recreate:
|
|
559
|
+
# Ensure analyzer exists
|
|
560
|
+
if not self.code_analyzer:
|
|
610
561
|
emitter = CodeTreeEventEmitter(use_stdout=False)
|
|
611
562
|
# Override emit method to send to Socket.IO
|
|
612
563
|
original_emit = emitter.emit
|
|
@@ -616,14 +567,14 @@ class CodeAnalysisEventHandler(BaseEventHandler):
|
|
|
616
567
|
):
|
|
617
568
|
# Keep the original event format with colons - frontend expects this!
|
|
618
569
|
# The frontend listens for 'code:file:analyzed' not 'code.file.analyzed'
|
|
619
|
-
|
|
570
|
+
|
|
620
571
|
# Special handling for 'info' events - they should be passed through directly
|
|
621
|
-
if event_type ==
|
|
572
|
+
if event_type == "info":
|
|
622
573
|
# INFO events for granular tracking
|
|
623
574
|
loop = asyncio.get_event_loop()
|
|
624
575
|
loop.create_task(
|
|
625
576
|
self.server.core.sio.emit(
|
|
626
|
-
|
|
577
|
+
"info", {"request_id": request_id, **event_data}
|
|
627
578
|
)
|
|
628
579
|
)
|
|
629
580
|
else:
|
|
@@ -637,13 +588,9 @@ class CodeAnalysisEventHandler(BaseEventHandler):
|
|
|
637
588
|
original_emit(event_type, event_data, batch)
|
|
638
589
|
|
|
639
590
|
emitter.emit = socket_emit
|
|
640
|
-
# Initialize CodeTreeAnalyzer with emitter keyword argument
|
|
641
|
-
self.logger.info(
|
|
642
|
-
self.code_analyzer = CodeTreeAnalyzer(emitter=emitter
|
|
643
|
-
self.logger.info(f"[DEBUG] CodeTreeAnalyzer created, analyzer.show_hidden_files={self.code_analyzer.show_hidden_files}")
|
|
644
|
-
self.logger.info(f"[DEBUG] GitignoreManager.show_hidden_files={self.code_analyzer.gitignore_manager.show_hidden_files}")
|
|
645
|
-
else:
|
|
646
|
-
self.logger.info(f"[DEBUG] Reusing analyzer with show_hidden_files={self.code_analyzer.show_hidden_files}")
|
|
591
|
+
# Initialize CodeTreeAnalyzer with emitter keyword argument
|
|
592
|
+
self.logger.info("Creating CodeTreeAnalyzer")
|
|
593
|
+
self.code_analyzer = CodeTreeAnalyzer(emitter=emitter)
|
|
647
594
|
|
|
648
595
|
# Analyze file
|
|
649
596
|
result = self.code_analyzer.analyze_file(path)
|