claude-mpm 4.2.43__py3-none-any.whl → 4.2.44__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.
@@ -388,7 +388,9 @@ class CodeViewer {
388
388
  if (window.socket) {
389
389
  window.socket.on('claude_event', (event) => {
390
390
  console.log('[CodeViewer] Received claude_event:', event);
391
- if (this.isFileOperationEvent(event)) {
391
+
392
+ // Process both hook events and direct file operation events
393
+ if (this.isFileOperationEvent(event) || this.isDirectFileEvent(event)) {
392
394
  this.processClaudeEvent(event);
393
395
  // Only update if the File Tree tab is active
394
396
  if (this.isTabActive()) {
@@ -398,13 +400,31 @@ class CodeViewer {
398
400
  }
399
401
  }
400
402
  });
403
+
404
+ // Also listen for specific file events
405
+ window.socket.on('file:read', (data) => {
406
+ console.log('[CodeViewer] Received file:read event:', data);
407
+ this.handleDirectFileEvent('Read', data);
408
+ });
409
+
410
+ window.socket.on('file:write', (data) => {
411
+ console.log('[CodeViewer] Received file:write event:', data);
412
+ this.handleDirectFileEvent('Write', data);
413
+ });
414
+
415
+ window.socket.on('file:edit', (data) => {
416
+ console.log('[CodeViewer] Received file:edit event:', data);
417
+ this.handleDirectFileEvent('Edit', data);
418
+ });
401
419
  }
402
420
 
403
421
  // Listen for events from event bus
404
422
  if (window.eventBus) {
405
423
  window.eventBus.on('claude_event', (event) => {
406
424
  console.log('[CodeViewer] Received claude_event from eventBus:', event);
407
- if (this.isFileOperationEvent(event)) {
425
+
426
+ // Process both hook events and direct file operation events
427
+ if (this.isFileOperationEvent(event) || this.isDirectFileEvent(event)) {
408
428
  this.processClaudeEvent(event);
409
429
  // Only update if the File Tree tab is active
410
430
  if (this.isTabActive()) {
@@ -452,6 +472,46 @@ class CodeViewer {
452
472
  }
453
473
  return false;
454
474
  }
475
+
476
+ /**
477
+ * Check if an event is a direct file event (not wrapped in hook)
478
+ */
479
+ isDirectFileEvent(event) {
480
+ // Check if this is a direct file operation event
481
+ if (event.type === 'file_operation' ||
482
+ (event.tool && ['Read', 'Write', 'Edit', 'MultiEdit', 'NotebookEdit'].includes(event.tool))) {
483
+ return true;
484
+ }
485
+ return false;
486
+ }
487
+
488
+ /**
489
+ * Handle direct file events from WebSocket
490
+ */
491
+ handleDirectFileEvent(tool_name, data) {
492
+ const event = {
493
+ type: 'file_operation',
494
+ tool: tool_name,
495
+ data: {
496
+ tool_name: tool_name,
497
+ tool_parameters: data.parameters || data,
498
+ tool_output: data.output || null,
499
+ session_id: data.session_id || this.currentSession,
500
+ working_directory: data.working_directory || '/'
501
+ },
502
+ timestamp: data.timestamp || new Date().toISOString()
503
+ };
504
+
505
+ console.log('[CodeViewer] Processing direct file event:', event);
506
+ this.processClaudeEvent(event);
507
+
508
+ // Only update if the File Tree tab is active
509
+ if (this.isTabActive()) {
510
+ this.buildTreeData();
511
+ this.renderTree();
512
+ this.updateStats();
513
+ }
514
+ }
455
515
 
456
516
  /**
457
517
  * Check if an event is a file operation (legacy format)
@@ -465,18 +525,33 @@ class CodeViewer {
465
525
  * Process a claude event with file operation
466
526
  */
467
527
  processClaudeEvent(event) {
468
- if (!this.isFileOperationEvent(event)) return;
469
-
470
- // Extract data from claude_event structure
471
- const data = event.data || {};
472
- const tool_name = data.tool_name;
473
- const tool_parameters = data.tool_parameters || {};
474
- const tool_output = data.tool_output;
475
- const timestamp = event.timestamp || new Date().toISOString();
476
- const session_id = event.session_id || data.session_id;
477
- const working_directory = data.working_directory || '/';
528
+ // Handle both hook events and direct file events
529
+ if (!this.isFileOperationEvent(event) && !this.isDirectFileEvent(event)) return;
530
+
531
+ let tool_name, tool_parameters, tool_output, timestamp, session_id, working_directory, filePath;
532
+
533
+ // Extract data based on event format
534
+ if (this.isFileOperationEvent(event)) {
535
+ // Hook event format
536
+ const data = event.data || {};
537
+ tool_name = data.tool_name;
538
+ tool_parameters = data.tool_parameters || {};
539
+ tool_output = data.tool_output;
540
+ timestamp = event.timestamp || new Date().toISOString();
541
+ session_id = event.session_id || data.session_id;
542
+ working_directory = data.working_directory || '/';
543
+ } else if (this.isDirectFileEvent(event)) {
544
+ // Direct file event format
545
+ const data = event.data || event;
546
+ tool_name = event.tool || data.tool_name;
547
+ tool_parameters = data.tool_parameters || data.parameters || {};
548
+ tool_output = data.tool_output || data.output;
549
+ timestamp = event.timestamp || data.timestamp || new Date().toISOString();
550
+ session_id = event.session_id || data.session_id;
551
+ working_directory = data.working_directory || '/';
552
+ }
478
553
 
479
- const filePath = tool_parameters.file_path || tool_parameters.notebook_path;
554
+ filePath = tool_parameters.file_path || tool_parameters.notebook_path;
480
555
 
481
556
  console.log('[CodeViewer] Processing file operation:', tool_name, filePath);
482
557
 
@@ -22,7 +22,6 @@ class UIStateManager {
22
22
  '#files': 'files',
23
23
  '#activity': 'activity',
24
24
  '#file_tree': 'claude-tree',
25
- '#browser_logs': 'browser-logs',
26
25
  '': 'events', // default
27
26
  };
28
27
 
@@ -33,8 +32,7 @@ class UIStateManager {
33
32
  'tools': '#tools',
34
33
  'files': '#files',
35
34
  'activity': '#activity',
36
- 'claude-tree': '#file_tree',
37
- 'browser-logs': '#browser_logs'
35
+ 'claude-tree': '#file_tree'
38
36
  };
39
37
 
40
38
  // Current active tab - will be set based on URL hash
@@ -157,7 +155,6 @@ class UIStateManager {
157
155
  if (text.includes('activity')) return 'activity';
158
156
  if (text.includes('agents')) return 'agents';
159
157
  if (text.includes('tools')) return 'tools';
160
- if (text.includes('browser')) return 'browser-logs'; // Added browser logs support
161
158
  if (text.includes('files')) return 'files';
162
159
  if (text.includes('file tree')) return 'claude-tree';
163
160
  if (text.includes('code')) return 'code';
@@ -263,25 +260,6 @@ class UIStateManager {
263
260
  window.CodeViewer.show();
264
261
  }
265
262
  }
266
-
267
- // SIMPLEST POSSIBLE Browser Logs tab - just static text
268
- if (tabName === 'browser-logs') {
269
- console.log('[UIStateManager] Switching to Browser Logs tab - simple mode');
270
-
271
- const container = document.getElementById('browser-logs-container');
272
- if (container) {
273
- // Clear EVERYTHING - no complex logic, just clear it
274
- container.innerHTML = '';
275
-
276
- // Set the simplest possible content - just text
277
- container.innerHTML = '<h2 style="padding: 20px;">Browser Logs</h2>';
278
-
279
- // That's it. Nothing else. No event listeners, no watchers, nothing.
280
- console.log('[UIStateManager] Browser Logs tab set to simple text');
281
- } else {
282
- console.warn('[UIStateManager] Browser logs container not found');
283
- }
284
- }
285
263
  }, 100);
286
264
  }
287
265
 
@@ -493,22 +493,6 @@ class Dashboard {
493
493
  case 'files':
494
494
  this.renderFiles();
495
495
  break;
496
- case 'browser-logs':
497
- // Simple browser logs display - no events
498
- const browserLogsContainer = document.getElementById('browser-logs-container');
499
- if (browserLogsContainer) {
500
- // Only set content if it's not already set
501
- if (!browserLogsContainer.querySelector('.browser-logs-simple')) {
502
- browserLogsContainer.innerHTML = `
503
- <div class="browser-logs-simple" style="padding: 20px;">
504
- <h2>Browser Logs</h2>
505
- <p style="color: #666;">Browser console monitoring - no events shown here</p>
506
- </div>
507
- `;
508
- }
509
- }
510
- console.log('[Dashboard] Browser Logs tab rendered (simple mode)');
511
- break;
512
496
  }
513
497
 
514
498
  // Update selection UI if we have a selected card
@@ -249,8 +249,7 @@
249
249
  <a href="#tools" class="tab-button" data-tab="tools">🔧 Tools</a>
250
250
  <a href="#files" class="tab-button" data-tab="files">📁 Files</a>
251
251
  <a href="#activity" class="tab-button" data-tab="activity">🌳 Activity</a>
252
- <a href="#file_tree" class="tab-button active" data-tab="claude-tree">📝 File Tree</a>
253
- <a href="#browser_logs" class="tab-button" data-tab="browser-logs">🌐 Browser Logs</a>
252
+ <a href="#file_tree" class="tab-button" data-tab="claude-tree">📝 File Tree</a>
254
253
  </div>
255
254
 
256
255
  <!-- Events Tab -->
@@ -390,19 +389,12 @@
390
389
  </div>
391
390
 
392
391
  <!-- File Tree Tab -->
393
- <div class="tab-content active" id="claude-tree-tab">
392
+ <div class="tab-content" id="claude-tree-tab">
394
393
  <div id="claude-tree-container" style="width: 100%; height: 100%;">
395
394
  <!-- File activity tree will be rendered here by code-viewer.js -->
396
395
  </div>
397
396
  </div>
398
397
 
399
- <!-- Browser Logs Tab -->
400
- <div class="tab-content" id="browser-logs-tab">
401
- <div id="browser-logs-container" style="width: 100%; height: 100%;" data-component="browser-logs">
402
- <!-- Browser logs will be rendered here by browser-log-viewer.js -->
403
- <!-- This container is EXCLUSIVELY for browser console logs -->
404
- </div>
405
- </div>
406
398
 
407
399
  </div>
408
400
  </div>
@@ -508,25 +500,7 @@
508
500
  loadModule('/static/dist/components/activity-tree.js'),
509
501
  loadModule('/static/js/components/code-tree.js'), // TEMPORARY: Direct source for debugging
510
502
  loadModule('/static/js/components/code-viewer.js'), // Code viewer now includes file change tracking
511
- loadModule('/static/dist/components/file-viewer.js'), // File viewer for viewing file contents
512
- // TEMPORARILY DISABLED for simplest implementation
513
- // loadModule('/static/js/components/browser-log-viewer.js?v=2.0-NUCLEAR') // Browser console log viewer v2.0 NUCLEAR
514
- // TEMPORARILY DISABLED - BrowserLogViewer initialization
515
- // .then(() => {
516
- // // Initialize BrowserLogViewer v2.0 immediately after loading
517
- // if (typeof BrowserLogViewer !== 'undefined') {
518
- // const container = document.getElementById('browser-logs-container');
519
- // if (container && !window.browserLogViewer) {
520
- // console.error('[Main] Initializing BrowserLogViewer v2.0 NUCLEAR...');
521
- // window.browserLogViewer = new BrowserLogViewer(container);
522
- // console.error('[Main] BrowserLogViewer v2.0 NUCLEAR initialized successfully');
523
- // } else {
524
- // console.error('[Main] BrowserLogViewer v2.0 already initialized or container not found');
525
- // }
526
- // } else {
527
- // console.error('[Main] BrowserLogViewer class not found - script may not have loaded');
528
- // }
529
- // })
503
+ loadModule('/static/dist/components/file-viewer.js') // File viewer for viewing file contents
530
504
  ]);
531
505
  })
532
506
  .then(() => {
@@ -28,7 +28,6 @@ from aiohttp import web
28
28
  from ...core.logging_config import get_logger
29
29
  from ...dashboard.api.simple_directory import list_directory
30
30
  from .event_emitter import get_event_emitter
31
- from .handlers.browser import BrowserHandler
32
31
  from .handlers.code_analysis import CodeAnalysisHandler
33
32
  from .handlers.dashboard import DashboardHandler
34
33
  from .handlers.file import FileHandler
@@ -69,7 +68,6 @@ class UnifiedMonitorServer:
69
68
  self.site = None
70
69
 
71
70
  # Event handlers
72
- self.browser_handler = None
73
71
  self.code_analysis_handler = None
74
72
  self.dashboard_handler = None
75
73
  self.file_handler = None
@@ -272,14 +270,12 @@ class UnifiedMonitorServer:
272
270
  """Setup Socket.IO event handlers."""
273
271
  try:
274
272
  # Create event handlers
275
- self.browser_handler = BrowserHandler(self.sio)
276
273
  self.code_analysis_handler = CodeAnalysisHandler(self.sio)
277
274
  self.dashboard_handler = DashboardHandler(self.sio)
278
275
  self.file_handler = FileHandler(self.sio)
279
276
  self.hook_handler = HookHandler(self.sio)
280
277
 
281
278
  # Register handlers
282
- self.browser_handler.register()
283
279
  self.code_analysis_handler.register()
284
280
  self.dashboard_handler.register()
285
281
  self.file_handler.register()
@@ -512,219 +508,6 @@ class UnifiedMonitorServer:
512
508
  {"working_directory": os.getcwd(), "success": True}
513
509
  )
514
510
 
515
- # Browser monitor script endpoint
516
- async def browser_monitor_script_handler(request):
517
- """Serve the browser console monitoring script with dynamic port injection."""
518
- try:
519
- # Read the browser monitor script template
520
- script_path = (
521
- dashboard_dir / "static" / "js" / "browser-console-monitor.js"
522
- )
523
-
524
- if not script_path.exists():
525
- return web.Response(
526
- text="Browser monitor script not found",
527
- status=404,
528
- content_type="text/javascript",
529
- )
530
-
531
- # Read script content
532
- with open(script_path, encoding="utf-8") as f:
533
- script_content = f.read()
534
-
535
- # Replace the port placeholder with actual monitor port
536
- script_content = script_content.replace(
537
- "__MONITOR_PORT__", str(self.port)
538
- )
539
-
540
- # Set appropriate headers for JavaScript
541
- headers = {
542
- "Content-Type": "application/javascript; charset=utf-8",
543
- "Access-Control-Allow-Origin": "*",
544
- "Access-Control-Allow-Methods": "GET, OPTIONS",
545
- "Access-Control-Allow-Headers": "Content-Type",
546
- "Cache-Control": "no-cache, no-store, must-revalidate",
547
- "Pragma": "no-cache",
548
- "Expires": "0",
549
- }
550
-
551
- return web.Response(text=script_content, headers=headers)
552
-
553
- except Exception as e:
554
- self.logger.error(f"Error serving browser monitor script: {e}")
555
- return web.Response(
556
- text=f"// Error loading browser monitor script: {e}",
557
- status=500,
558
- content_type="application/javascript",
559
- )
560
-
561
- # Browser log endpoints
562
- async def api_browser_logs_handler(request):
563
- """Return list of browser log files."""
564
- try:
565
- from pathlib import Path
566
-
567
- # Get browser log directory
568
- log_dir = Path.home() / ".claude-mpm" / "logs" / "client"
569
-
570
- if not log_dir.exists():
571
- return web.json_response({"files": [], "total": 0})
572
-
573
- # Get all log files
574
- log_files = []
575
- for file_path in log_dir.glob("*.log"):
576
- stat = file_path.stat()
577
- log_files.append(
578
- {
579
- "name": file_path.name,
580
- "size": stat.st_size,
581
- "modified": stat.st_mtime,
582
- "modified_iso": datetime.fromtimestamp(
583
- stat.st_mtime
584
- ).isoformat(),
585
- }
586
- )
587
-
588
- # Sort by modification time (newest first)
589
- log_files.sort(key=lambda x: x["modified"], reverse=True)
590
-
591
- return web.json_response(
592
- {
593
- "files": log_files,
594
- "total": len(log_files),
595
- "directory": str(log_dir),
596
- }
597
- )
598
-
599
- except Exception as e:
600
- self.logger.error(f"Error listing browser logs: {e}")
601
- return web.json_response(
602
- {"error": str(e), "files": [], "total": 0}, status=500
603
- )
604
-
605
- async def api_browser_log_file_handler(request):
606
- """Return contents of specific browser log file."""
607
- try:
608
- import json
609
- from pathlib import Path
610
-
611
- filename = request.match_info.get("filename", "")
612
-
613
- # Security: ensure filename is safe (no path traversal)
614
- if (
615
- not filename
616
- or "/" in filename
617
- or "\\" in filename
618
- or ".." in filename
619
- ):
620
- return web.json_response(
621
- {"error": "Invalid filename"}, status=400
622
- )
623
-
624
- # Get log file path
625
- log_dir = Path.home() / ".claude-mpm" / "logs" / "client"
626
- log_file = log_dir / filename
627
-
628
- # Check if file exists and is within log directory
629
- if not log_file.exists() or not log_file.is_file():
630
- return web.json_response(
631
- {"error": "Log file not found"}, status=404
632
- )
633
-
634
- # Ensure file is within the log directory (security check)
635
- try:
636
- log_file.resolve().relative_to(log_dir.resolve())
637
- except ValueError:
638
- return web.json_response(
639
- {"error": "Invalid file path"}, status=403
640
- )
641
-
642
- # Read log entries
643
- entries = []
644
- with open(log_file, encoding="utf-8") as f:
645
- for line in f:
646
- line = line.strip()
647
- if line:
648
- try:
649
- entry = json.loads(line)
650
- entries.append(entry)
651
- except json.JSONDecodeError:
652
- # If not JSON, treat as plain text log
653
- entries.append(
654
- {
655
- "timestamp": "",
656
- "level": "INFO",
657
- "message": line,
658
- }
659
- )
660
-
661
- # Limit entries for performance
662
- max_entries = 1000
663
- if len(entries) > max_entries:
664
- entries = entries[-max_entries:] # Get last N entries
665
-
666
- return web.json_response(
667
- {
668
- "filename": filename,
669
- "entries": entries,
670
- "total": len(entries),
671
- "truncated": len(entries) == max_entries,
672
- }
673
- )
674
-
675
- except Exception as e:
676
- self.logger.error(f"Error reading browser log file: {e}")
677
- return web.json_response(
678
- {"error": str(e), "entries": []}, status=500
679
- )
680
-
681
- async def api_browser_log_handler(request):
682
- """Handle browser log submissions from injected monitoring script."""
683
- try:
684
- import json
685
- from pathlib import Path
686
-
687
- data = await request.json()
688
-
689
- # Extract log data
690
- browser_id = data.get("browser_id", "unknown")
691
- timestamp = data.get("timestamp", datetime.utcnow().isoformat())
692
- level = data.get("level", "INFO")
693
- message = data.get("message", "")
694
- url = data.get("url", "")
695
- user_agent = data.get("userAgent", "")
696
-
697
- # Create log entry
698
- log_entry = {
699
- "browser_id": browser_id,
700
- "timestamp": timestamp,
701
- "level": level,
702
- "message": message,
703
- "url": url,
704
- "user_agent": user_agent,
705
- }
706
-
707
- # Save to file
708
- log_dir = Path.home() / ".claude-mpm" / "logs" / "client"
709
- log_dir.mkdir(parents=True, exist_ok=True)
710
-
711
- # Use browser ID in filename for easy filtering
712
- log_file = log_dir / f"{browser_id}.log"
713
-
714
- # Append to log file
715
- with open(log_file, "a", encoding="utf-8") as f:
716
- f.write(json.dumps(log_entry) + "\n")
717
-
718
- # Also emit to Socket.IO for real-time viewing
719
- if self.sio:
720
- await self.sio.emit("browser_log", log_entry)
721
-
722
- return web.Response(status=204) # No content
723
-
724
- except Exception as e:
725
- self.logger.error(f"Error handling browser log: {e}")
726
- return web.Response(text=str(e), status=500)
727
-
728
511
  # Register routes
729
512
  self.app.router.add_get("/", dashboard_index)
730
513
  self.app.router.add_get("/health", health_check)
@@ -732,14 +515,6 @@ class UnifiedMonitorServer:
732
515
  self.app.router.add_get("/api/config", config_handler)
733
516
  self.app.router.add_get("/api/working-directory", working_directory_handler)
734
517
  self.app.router.add_get("/api/directory", list_directory)
735
- self.app.router.add_get(
736
- "/api/browser-monitor.js", browser_monitor_script_handler
737
- )
738
- self.app.router.add_get("/api/browser-logs", api_browser_logs_handler)
739
- self.app.router.add_get(
740
- "/api/browser-logs/{filename}", api_browser_log_file_handler
741
- )
742
- self.app.router.add_post("/api/browser-log", api_browser_log_handler)
743
518
  self.app.router.add_post("/api/events", api_events_handler)
744
519
  self.app.router.add_post("/api/file", api_file_handler)
745
520
 
@@ -961,7 +736,6 @@ class UnifiedMonitorServer:
961
736
  "host": self.host,
962
737
  "port": self.port,
963
738
  "handlers": {
964
- "browser": self.browser_handler is not None,
965
739
  "code_analysis": self.code_analysis_handler is not None,
966
740
  "dashboard": self.dashboard_handler is not None,
967
741
  "file": self.file_handler is not None,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: claude-mpm
3
- Version: 4.2.43
3
+ Version: 4.2.44
4
4
  Summary: Claude Multi-Agent Project Manager - Orchestrate Claude with agent delegation and ticket tracking
5
5
  Author-email: Bob Matsuoka <bob@matsuoka.com>
6
6
  Maintainer: Claude MPM Team