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.
- claude_mpm/VERSION +1 -1
- claude_mpm/agents/BASE_PM.md +75 -12
- claude_mpm/agents/INSTRUCTIONS.md +80 -10
- claude_mpm/core/api_validator.py +330 -0
- claude_mpm/core/framework_loader.py +22 -0
- claude_mpm/dashboard/static/js/components/code-viewer.js +88 -13
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +1 -23
- claude_mpm/dashboard/static/js/dashboard.js +0 -16
- claude_mpm/dashboard/templates/index.html +3 -29
- claude_mpm/services/monitor/server.py +0 -226
- {claude_mpm-4.2.43.dist-info → claude_mpm-4.2.44.dist-info}/METADATA +1 -1
- {claude_mpm-4.2.43.dist-info → claude_mpm-4.2.44.dist-info}/RECORD +16 -20
- claude_mpm/commands/mpm-browser-monitor.md +0 -370
- claude_mpm/commands/mpm-monitor.md +0 -177
- claude_mpm/dashboard/static/js/browser-console-monitor.js +0 -495
- claude_mpm/dashboard/static/js/components/browser-log-viewer.js +0 -763
- claude_mpm/services/monitor/handlers/browser.py +0 -451
- {claude_mpm-4.2.43.dist-info → claude_mpm-4.2.44.dist-info}/WHEEL +0 -0
- {claude_mpm-4.2.43.dist-info → claude_mpm-4.2.44.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.2.43.dist-info → claude_mpm-4.2.44.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.2.43.dist-info → claude_mpm-4.2.44.dist-info}/top_level.txt +0 -0
@@ -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
|
-
|
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
|
-
|
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
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
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
|
-
|
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
|
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
|
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')
|
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,
|