claude-mpm 4.2.39__py3-none-any.whl → 4.2.42__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_ENGINEER.md +114 -1
- claude_mpm/agents/BASE_OPS.md +156 -1
- claude_mpm/agents/INSTRUCTIONS.md +120 -11
- claude_mpm/agents/WORKFLOW.md +160 -10
- claude_mpm/agents/templates/agentic-coder-optimizer.json +17 -12
- claude_mpm/agents/templates/react_engineer.json +217 -0
- claude_mpm/agents/templates/web_qa.json +40 -4
- claude_mpm/cli/__init__.py +3 -5
- claude_mpm/commands/mpm-browser-monitor.md +370 -0
- claude_mpm/commands/mpm-monitor.md +177 -0
- claude_mpm/dashboard/static/built/components/code-viewer.js +1076 -2
- claude_mpm/dashboard/static/built/components/ui-state-manager.js +465 -2
- claude_mpm/dashboard/static/css/dashboard.css +2 -0
- claude_mpm/dashboard/static/js/browser-console-monitor.js +495 -0
- claude_mpm/dashboard/static/js/components/browser-log-viewer.js +763 -0
- claude_mpm/dashboard/static/js/components/code-viewer.js +931 -340
- claude_mpm/dashboard/static/js/components/diff-viewer.js +891 -0
- claude_mpm/dashboard/static/js/components/file-change-tracker.js +443 -0
- claude_mpm/dashboard/static/js/components/file-change-viewer.js +690 -0
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +307 -19
- claude_mpm/dashboard/static/js/socket-client.js +2 -2
- claude_mpm/dashboard/static/test-browser-monitor.html +470 -0
- claude_mpm/dashboard/templates/index.html +62 -99
- claude_mpm/services/cli/unified_dashboard_manager.py +1 -1
- claude_mpm/services/monitor/daemon.py +69 -36
- claude_mpm/services/monitor/daemon_manager.py +186 -29
- claude_mpm/services/monitor/handlers/browser.py +451 -0
- claude_mpm/services/monitor/server.py +272 -5
- {claude_mpm-4.2.39.dist-info → claude_mpm-4.2.42.dist-info}/METADATA +1 -1
- {claude_mpm-4.2.39.dist-info → claude_mpm-4.2.42.dist-info}/RECORD +35 -29
- claude_mpm/agents/templates/agentic-coder-optimizer.md +0 -44
- claude_mpm/agents/templates/agentic_coder_optimizer.json +0 -238
- claude_mpm/agents/templates/test-non-mpm.json +0 -20
- claude_mpm/dashboard/static/dist/components/code-viewer.js +0 -2
- {claude_mpm-4.2.39.dist-info → claude_mpm-4.2.42.dist-info}/WHEEL +0 -0
- {claude_mpm-4.2.39.dist-info → claude_mpm-4.2.42.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.2.39.dist-info → claude_mpm-4.2.42.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.2.39.dist-info → claude_mpm-4.2.42.dist-info}/top_level.txt +0 -0
@@ -18,6 +18,9 @@
|
|
18
18
|
|
19
19
|
<!-- D3.js for Activity Tree Visualization -->
|
20
20
|
<script src="https://d3js.org/d3.v7.min.js"></script>
|
21
|
+
|
22
|
+
<!-- Font Awesome for icons -->
|
23
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
|
21
24
|
|
22
25
|
<!-- Syntax Highlighting - Prism.js -->
|
23
26
|
<link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" rel="stylesheet">
|
@@ -239,18 +242,19 @@
|
|
239
242
|
|
240
243
|
<!-- Right: Tabbed Content -->
|
241
244
|
<div class="events-container">
|
242
|
-
<!-- Tab Navigation -->
|
245
|
+
<!-- Tab Navigation - Using hash-based navigation -->
|
243
246
|
<div class="tab-nav">
|
244
|
-
<
|
245
|
-
<
|
246
|
-
<
|
247
|
-
<
|
248
|
-
<
|
249
|
-
<
|
247
|
+
<a href="#events" class="tab-button" data-tab="events">📊 Events</a>
|
248
|
+
<a href="#agents" class="tab-button" data-tab="agents">🤖 Agents</a>
|
249
|
+
<a href="#tools" class="tab-button" data-tab="tools">🔧 Tools</a>
|
250
|
+
<a href="#files" class="tab-button" data-tab="files">📁 Files</a>
|
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>
|
250
254
|
</div>
|
251
255
|
|
252
256
|
<!-- Events Tab -->
|
253
|
-
<div class="tab-content
|
257
|
+
<div class="tab-content" id="events-tab">
|
254
258
|
<div class="tab-filters">
|
255
259
|
<input type="text" id="events-search-input" placeholder="Search events...">
|
256
260
|
<select id="events-type-filter">
|
@@ -385,76 +389,18 @@
|
|
385
389
|
</div>
|
386
390
|
</div>
|
387
391
|
|
388
|
-
<!--
|
389
|
-
<div class="tab-content" id="
|
390
|
-
<div
|
391
|
-
|
392
|
-
<div id="code-tree-container" class="code-tree-container">
|
393
|
-
<!-- Top-left corner: Language selector -->
|
394
|
-
<div class="tree-corner-controls top-left">
|
395
|
-
<div class="control-group">
|
396
|
-
<label class="control-label">Languages:</label>
|
397
|
-
<div class="checkbox-group">
|
398
|
-
<label class="checkbox-label"><input type="checkbox" class="language-checkbox" value="python" checked> Python</label>
|
399
|
-
<label class="checkbox-label"><input type="checkbox" class="language-checkbox" value="javascript" checked> JS</label>
|
400
|
-
<label class="checkbox-label"><input type="checkbox" class="language-checkbox" value="typescript" checked> TS</label>
|
401
|
-
</div>
|
402
|
-
</div>
|
403
|
-
</div>
|
404
|
-
|
405
|
-
<!-- Top-right corner: Layout and search -->
|
406
|
-
<div class="tree-corner-controls top-right">
|
407
|
-
<div class="control-group">
|
408
|
-
<select id="code-layout" class="select-compact">
|
409
|
-
<option value="tree">Tree</option>
|
410
|
-
<option value="radial">Radial</option>
|
411
|
-
</select>
|
412
|
-
<input type="text" id="code-search" placeholder="Search..." class="search-compact">
|
413
|
-
</div>
|
414
|
-
</div>
|
415
|
-
|
416
|
-
<!-- Bottom-left corner: Stats and Status -->
|
417
|
-
<div class="tree-corner-controls bottom-left">
|
418
|
-
<div class="stats-display" id="code-stats">
|
419
|
-
<span id="stats-files">0 files</span> •
|
420
|
-
<span id="stats-classes">0 classes</span> •
|
421
|
-
<span id="stats-functions">0 functions</span> •
|
422
|
-
<span id="stats-methods">0 methods</span>
|
423
|
-
</div>
|
424
|
-
<div class="status-display" id="code-breadcrumb">
|
425
|
-
<div class="breadcrumb-ticker" id="breadcrumb-ticker">
|
426
|
-
<span id="breadcrumb-content">Ready to analyze...</span>
|
427
|
-
</div>
|
428
|
-
</div>
|
429
|
-
</div>
|
430
|
-
|
431
|
-
<!-- Bottom-right corner: Ignore patterns -->
|
432
|
-
<div class="tree-corner-controls bottom-right">
|
433
|
-
<div class="control-group">
|
434
|
-
<label class="control-label">Ignore:</label>
|
435
|
-
<input type="text" id="ignore-patterns" placeholder="test*, *.spec.js, node_modules" class="input-compact">
|
436
|
-
</div>
|
437
|
-
</div>
|
438
|
-
<div id="code-tree"></div>
|
439
|
-
<!-- Collapsible legend -->
|
440
|
-
<div class="tree-legend collapsed" id="tree-legend" style="display: none;">
|
441
|
-
<button class="legend-close" onclick="document.getElementById('tree-legend').style.display='none'">✕</button>
|
442
|
-
<div class="legend-content">
|
443
|
-
<div class="legend-column">
|
444
|
-
<div class="legend-item"><span class="legend-icon">📦</span> Module</div>
|
445
|
-
<div class="legend-item"><span class="legend-icon">🏛️</span> Class</div>
|
446
|
-
<div class="legend-item"><span class="legend-icon">⚡</span> Function</div>
|
447
|
-
<div class="legend-item"><span class="legend-icon">🔧</span> Method</div>
|
448
|
-
</div>
|
449
|
-
<div class="legend-column">
|
450
|
-
<div class="legend-item"><span class="legend-icon complexity-low">●</span> Low</div>
|
451
|
-
<div class="legend-item"><span class="legend-icon complexity-medium">●</span> Med</div>
|
452
|
-
<div class="legend-item"><span class="legend-icon complexity-high">●</span> High</div>
|
453
|
-
</div>
|
454
|
-
</div>
|
455
|
-
</div>
|
456
|
-
</div>
|
392
|
+
<!-- File Tree Tab -->
|
393
|
+
<div class="tab-content active" id="claude-tree-tab">
|
394
|
+
<div id="claude-tree-container" style="width: 100%; height: 100%;">
|
395
|
+
<!-- File activity tree will be rendered here by code-viewer.js -->
|
457
396
|
</div>
|
397
|
+
</div>
|
398
|
+
|
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 -->
|
458
404
|
</div>
|
459
405
|
</div>
|
460
406
|
|
@@ -463,26 +409,6 @@
|
|
463
409
|
</div>
|
464
410
|
</div>
|
465
411
|
|
466
|
-
<!-- Code Viewer Modal -->
|
467
|
-
<div id="code-viewer-modal" class="modal" style="display: none;">
|
468
|
-
<div class="modal-content">
|
469
|
-
<div class="modal-header">
|
470
|
-
<h2 id="code-viewer-title">Code Viewer</h2>
|
471
|
-
<button class="close" onclick="closeCodeViewer()">×</button>
|
472
|
-
</div>
|
473
|
-
<div class="modal-body">
|
474
|
-
<pre><code id="code-viewer-content"></code></pre>
|
475
|
-
</div>
|
476
|
-
<div class="modal-footer">
|
477
|
-
<div class="code-viewer-info">
|
478
|
-
<span id="code-viewer-path"></span>
|
479
|
-
<span id="code-viewer-lines"></span>
|
480
|
-
<span id="code-viewer-language"></span>
|
481
|
-
</div>
|
482
|
-
<button onclick="closeCodeViewer()">Close</button>
|
483
|
-
</div>
|
484
|
-
</div>
|
485
|
-
</div>
|
486
412
|
|
487
413
|
<!-- Footer -->
|
488
414
|
<div class="footer">
|
@@ -571,19 +497,56 @@
|
|
571
497
|
.then(() => loadModule('/static/js/components/code-tree/tree-constants.js'))
|
572
498
|
.then(() => loadModule('/static/js/components/code-tree/tree-search.js'))
|
573
499
|
.then(() => loadModule('/static/js/components/code-tree/tree-breadcrumb.js'))
|
500
|
+
.then(() => {
|
501
|
+
// Load UI State Manager v2 from source with nuclear browser log handling
|
502
|
+
return loadModule('/static/js/components/ui-state-manager.js?v=2.0-NUCLEAR');
|
503
|
+
})
|
574
504
|
.then(() => {
|
575
505
|
// Now load main components in parallel
|
576
506
|
return Promise.all([
|
577
507
|
loadModule('/static/dist/dashboard.js'),
|
578
508
|
loadModule('/static/dist/components/activity-tree.js'),
|
579
509
|
loadModule('/static/js/components/code-tree.js'), // TEMPORARY: Direct source for debugging
|
580
|
-
loadModule('/static/
|
581
|
-
loadModule('/static/dist/components/file-viewer.js') // File viewer for viewing file contents
|
510
|
+
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
|
+
loadModule('/static/js/components/browser-log-viewer.js?v=2.0-NUCLEAR') // Browser console log viewer v2.0 NUCLEAR
|
513
|
+
.then(() => {
|
514
|
+
// Initialize BrowserLogViewer v2.0 immediately after loading
|
515
|
+
if (typeof BrowserLogViewer !== 'undefined') {
|
516
|
+
const container = document.getElementById('browser-logs-container');
|
517
|
+
if (container && !window.browserLogViewer) {
|
518
|
+
console.error('[Main] Initializing BrowserLogViewer v2.0 NUCLEAR...');
|
519
|
+
window.browserLogViewer = new BrowserLogViewer(container);
|
520
|
+
console.error('[Main] BrowserLogViewer v2.0 NUCLEAR initialized successfully');
|
521
|
+
} else {
|
522
|
+
console.error('[Main] BrowserLogViewer v2.0 already initialized or container not found');
|
523
|
+
}
|
524
|
+
} else {
|
525
|
+
console.error('[Main] BrowserLogViewer class not found - script may not have loaded');
|
526
|
+
}
|
527
|
+
})
|
582
528
|
]);
|
583
529
|
})
|
584
530
|
.then(() => {
|
585
531
|
console.log('All dashboard modules loaded successfully');
|
586
532
|
|
533
|
+
// CodeViewer will auto-initialize and handle tab switching internally
|
534
|
+
|
535
|
+
// Browser Log Viewer initialization is now handled by UIStateManager
|
536
|
+
// This prevents duplicate event handlers and tab selection conflicts
|
537
|
+
|
538
|
+
// Hash navigation will handle default tab based on URL
|
539
|
+
// If no hash, default will be 'events' as per hashToTab mapping
|
540
|
+
// To start with File Tree, we can set hash if not present
|
541
|
+
setTimeout(() => {
|
542
|
+
if (!window.location.hash) {
|
543
|
+
console.log('No hash present, setting default to File Tree tab...');
|
544
|
+
window.location.hash = '#file_tree';
|
545
|
+
} else {
|
546
|
+
console.log('Hash present:', window.location.hash);
|
547
|
+
}
|
548
|
+
}, 500);
|
549
|
+
|
587
550
|
// Give modules time to execute and initialize dashboard
|
588
551
|
setTimeout(() => {
|
589
552
|
console.log('Checking dashboard initialization...');
|
@@ -133,7 +133,7 @@ class UnifiedDashboardManager(IUnifiedDashboardManager):
|
|
133
133
|
if background:
|
134
134
|
# The daemon.start() method will handle cleanup when force_restart=True
|
135
135
|
# We don't need pre-emptive cleanup here as it causes race conditions
|
136
|
-
|
136
|
+
|
137
137
|
# Try to start daemon with retry on port conflicts
|
138
138
|
max_retries = 3
|
139
139
|
retry_count = 0
|
@@ -157,35 +157,67 @@ class UnifiedMonitorDaemon:
|
|
157
157
|
)
|
158
158
|
return False
|
159
159
|
|
160
|
-
#
|
161
|
-
|
162
|
-
|
163
|
-
#
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
160
|
+
# Use subprocess approach for clean daemon startup (v4.2.40)
|
161
|
+
# This avoids all fork() + threading issues by starting in a fresh process
|
162
|
+
# The daemon_manager.use_subprocess_daemon() now checks for CLAUDE_MPM_SUBPROCESS_DAEMON
|
163
|
+
# environment variable to prevent infinite recursion
|
164
|
+
if self.daemon_manager.use_subprocess_daemon():
|
165
|
+
# Start using subprocess - this returns immediately in parent
|
166
|
+
success = self.daemon_manager.start_daemon_subprocess()
|
167
|
+
return success
|
168
|
+
|
169
|
+
# Check if we're in subprocess mode (environment variable set)
|
170
|
+
if os.environ.get("CLAUDE_MPM_SUBPROCESS_DAEMON") == "1":
|
171
|
+
# We're in a subprocess started by start_daemon_subprocess
|
172
|
+
# We need to write the PID file ourselves since parent didn't
|
173
|
+
self.logger.info("Running in subprocess daemon mode, writing PID file")
|
174
|
+
self.daemon_manager.write_pid_file()
|
175
|
+
|
176
|
+
# Setup signal handlers for graceful shutdown
|
177
|
+
self._setup_signal_handlers()
|
178
|
+
|
179
|
+
# Start the server (this will run until shutdown)
|
180
|
+
try:
|
181
|
+
result = self._run_server()
|
182
|
+
if not result:
|
183
|
+
self.logger.error("Failed to start server in subprocess mode")
|
184
|
+
return result
|
185
|
+
except Exception as e:
|
186
|
+
self.logger.error(f"Server startup exception in subprocess: {e}")
|
187
|
+
raise
|
188
|
+
else:
|
189
|
+
# Legacy fork approach (kept for compatibility but not used by default)
|
190
|
+
# Wait for any pre-warming threads to complete before forking
|
191
|
+
self._wait_for_prewarm_completion()
|
192
|
+
|
193
|
+
# Use daemon manager's daemonize which includes cleanup
|
194
|
+
# DO NOT reset startup_status_file - it's needed for parent-child communication!
|
195
|
+
# self.daemon_manager.startup_status_file = None # BUG: This breaks communication
|
196
|
+
success = self.daemon_manager.daemonize()
|
197
|
+
if not success:
|
198
|
+
return False
|
169
199
|
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
200
|
+
# We're now in the daemon process
|
201
|
+
# Update our PID references and status file
|
202
|
+
self.lifecycle.pid_file = self.daemon_manager.pid_file
|
203
|
+
self.lifecycle.startup_status_file = self.daemon_manager.startup_status_file
|
174
204
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
205
|
+
# Start the server in daemon mode
|
206
|
+
try:
|
207
|
+
result = self._run_server()
|
208
|
+
if not result:
|
209
|
+
# Report failure before exiting
|
210
|
+
self.daemon_manager._report_startup_error("Failed to start server")
|
211
|
+
else:
|
212
|
+
# Report success
|
213
|
+
self.daemon_manager._report_startup_success()
|
214
|
+
return result
|
215
|
+
except Exception as e:
|
216
|
+
# Report any exceptions during startup
|
217
|
+
self.daemon_manager._report_startup_error(
|
218
|
+
f"Server startup exception: {e}"
|
219
|
+
)
|
220
|
+
raise
|
189
221
|
|
190
222
|
def _start_foreground(self, force_restart: bool = False) -> bool:
|
191
223
|
"""Start in foreground mode.
|
@@ -602,29 +634,30 @@ class UnifiedMonitorDaemon:
|
|
602
634
|
self.logger.info(
|
603
635
|
f"Waiting for {len(active_threads)} background threads to complete before forking"
|
604
636
|
)
|
605
|
-
|
637
|
+
|
606
638
|
# List thread names for debugging
|
607
639
|
thread_names = [t.name for t in active_threads]
|
608
640
|
self.logger.debug(f"Active threads: {thread_names}")
|
609
641
|
|
610
642
|
# Wait for threads to complete or timeout
|
611
643
|
while time.time() - start_time < timeout:
|
612
|
-
remaining_threads = [
|
613
|
-
t for t in active_threads if t.is_alive()
|
614
|
-
]
|
644
|
+
remaining_threads = [t for t in active_threads if t.is_alive()]
|
615
645
|
if not remaining_threads:
|
616
646
|
self.logger.debug("All threads completed")
|
617
647
|
break
|
618
|
-
|
648
|
+
|
619
649
|
# Log remaining threads periodically
|
620
650
|
if int(time.time() - start_time) % 1 == 0:
|
621
|
-
self.logger.debug(
|
622
|
-
|
651
|
+
self.logger.debug(
|
652
|
+
f"{len(remaining_threads)} threads still active"
|
653
|
+
)
|
654
|
+
|
623
655
|
time.sleep(0.1)
|
624
|
-
|
656
|
+
|
625
657
|
# Final check
|
626
658
|
final_threads = [
|
627
|
-
t
|
659
|
+
t
|
660
|
+
for t in threading.enumerate()
|
628
661
|
if t.is_alive() and t != threading.current_thread()
|
629
662
|
]
|
630
663
|
if final_threads:
|