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.
Files changed (39) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/BASE_ENGINEER.md +114 -1
  3. claude_mpm/agents/BASE_OPS.md +156 -1
  4. claude_mpm/agents/INSTRUCTIONS.md +120 -11
  5. claude_mpm/agents/WORKFLOW.md +160 -10
  6. claude_mpm/agents/templates/agentic-coder-optimizer.json +17 -12
  7. claude_mpm/agents/templates/react_engineer.json +217 -0
  8. claude_mpm/agents/templates/web_qa.json +40 -4
  9. claude_mpm/cli/__init__.py +3 -5
  10. claude_mpm/commands/mpm-browser-monitor.md +370 -0
  11. claude_mpm/commands/mpm-monitor.md +177 -0
  12. claude_mpm/dashboard/static/built/components/code-viewer.js +1076 -2
  13. claude_mpm/dashboard/static/built/components/ui-state-manager.js +465 -2
  14. claude_mpm/dashboard/static/css/dashboard.css +2 -0
  15. claude_mpm/dashboard/static/js/browser-console-monitor.js +495 -0
  16. claude_mpm/dashboard/static/js/components/browser-log-viewer.js +763 -0
  17. claude_mpm/dashboard/static/js/components/code-viewer.js +931 -340
  18. claude_mpm/dashboard/static/js/components/diff-viewer.js +891 -0
  19. claude_mpm/dashboard/static/js/components/file-change-tracker.js +443 -0
  20. claude_mpm/dashboard/static/js/components/file-change-viewer.js +690 -0
  21. claude_mpm/dashboard/static/js/components/ui-state-manager.js +307 -19
  22. claude_mpm/dashboard/static/js/socket-client.js +2 -2
  23. claude_mpm/dashboard/static/test-browser-monitor.html +470 -0
  24. claude_mpm/dashboard/templates/index.html +62 -99
  25. claude_mpm/services/cli/unified_dashboard_manager.py +1 -1
  26. claude_mpm/services/monitor/daemon.py +69 -36
  27. claude_mpm/services/monitor/daemon_manager.py +186 -29
  28. claude_mpm/services/monitor/handlers/browser.py +451 -0
  29. claude_mpm/services/monitor/server.py +272 -5
  30. {claude_mpm-4.2.39.dist-info → claude_mpm-4.2.42.dist-info}/METADATA +1 -1
  31. {claude_mpm-4.2.39.dist-info → claude_mpm-4.2.42.dist-info}/RECORD +35 -29
  32. claude_mpm/agents/templates/agentic-coder-optimizer.md +0 -44
  33. claude_mpm/agents/templates/agentic_coder_optimizer.json +0 -238
  34. claude_mpm/agents/templates/test-non-mpm.json +0 -20
  35. claude_mpm/dashboard/static/dist/components/code-viewer.js +0 -2
  36. {claude_mpm-4.2.39.dist-info → claude_mpm-4.2.42.dist-info}/WHEEL +0 -0
  37. {claude_mpm-4.2.39.dist-info → claude_mpm-4.2.42.dist-info}/entry_points.txt +0 -0
  38. {claude_mpm-4.2.39.dist-info → claude_mpm-4.2.42.dist-info}/licenses/LICENSE +0 -0
  39. {claude_mpm-4.2.39.dist-info → claude_mpm-4.2.42.dist-info}/top_level.txt +0 -0
@@ -14,8 +14,31 @@
14
14
  */
15
15
  class UIStateManager {
16
16
  constructor() {
17
- // Current active tab
18
- this.currentTab = 'events';
17
+ // Hash to tab mapping
18
+ this.hashToTab = {
19
+ '#events': 'events',
20
+ '#agents': 'agents',
21
+ '#tools': 'tools',
22
+ '#files': 'files',
23
+ '#activity': 'activity',
24
+ '#file_tree': 'claude-tree',
25
+ '#browser_logs': 'browser-logs',
26
+ '': 'events', // default
27
+ };
28
+
29
+ // Tab to hash mapping (reverse lookup)
30
+ this.tabToHash = {
31
+ 'events': '#events',
32
+ 'agents': '#agents',
33
+ 'tools': '#tools',
34
+ 'files': '#files',
35
+ 'activity': '#activity',
36
+ 'claude-tree': '#file_tree',
37
+ 'browser-logs': '#browser_logs'
38
+ };
39
+
40
+ // Current active tab - will be set based on URL hash
41
+ this.currentTab = this.getTabFromHash();
19
42
 
20
43
  // Auto-scroll behavior
21
44
  this.autoScroll = true;
@@ -37,30 +60,64 @@ class UIStateManager {
37
60
  };
38
61
 
39
62
  this.setupEventHandlers();
40
- console.log('UI state manager initialized');
63
+ console.log('UI state manager initialized with hash navigation');
64
+
65
+ // Initialize with current hash
66
+ this.handleHashChange();
67
+ }
68
+
69
+ /**
70
+ * Get tab name from current URL hash
71
+ * @returns {string} - Tab name based on hash
72
+ */
73
+ getTabFromHash() {
74
+ const hash = window.location.hash || '';
75
+ return this.hashToTab[hash] || 'events';
41
76
  }
42
77
 
43
78
  /**
44
79
  * Set up event handlers for UI interactions
45
80
  */
46
81
  setupEventHandlers() {
47
- this.setupTabNavigation();
82
+ this.setupHashNavigation();
48
83
  this.setupUnifiedKeyboardNavigation();
49
84
  }
50
85
 
51
86
  /**
52
- * Set up tab navigation event listeners
87
+ * Set up hash-based navigation
53
88
  */
54
- setupTabNavigation() {
55
- // Tab buttons
56
- document.querySelectorAll('.tab-button').forEach(button => {
57
- button.addEventListener('click', () => {
58
- const tabName = this.getTabNameFromButton(button);
59
- this.switchTab(tabName);
60
- });
89
+ setupHashNavigation() {
90
+ // Handle hash changes
91
+ window.addEventListener('hashchange', (e) => {
92
+ console.log('[Hash Navigation] Hash changed from', new URL(e.oldURL).hash, 'to', window.location.hash);
93
+ this.handleHashChange();
94
+ });
95
+
96
+ // Handle initial page load
97
+ document.addEventListener('DOMContentLoaded', () => {
98
+ console.log('[Hash Navigation] Initial hash:', window.location.hash);
99
+ this.handleHashChange();
61
100
  });
62
101
  }
63
102
 
103
+ /**
104
+ * Handle hash change events
105
+ */
106
+ handleHashChange() {
107
+ const hash = window.location.hash || '';
108
+ const tabName = this.hashToTab[hash] || 'events';
109
+ console.log('[Hash Navigation] Switching to tab:', tabName, 'from hash:', hash);
110
+ this.switchTab(tabName, false); // false = don't update hash (we're responding to hash change)
111
+ }
112
+
113
+ /**
114
+ * DEPRECATED: Tab navigation is now handled by hash navigation
115
+ * This method is kept for backward compatibility but does nothing
116
+ */
117
+ setupTabNavigation() {
118
+ console.log('[Hash Navigation] setupTabNavigation is deprecated - using hash navigation instead');
119
+ }
120
+
64
121
  /**
65
122
  * Set up unified keyboard navigation across all tabs
66
123
  */
@@ -90,12 +147,19 @@ class UIStateManager {
90
147
  * @returns {string} - Tab name
91
148
  */
92
149
  getTabNameFromButton(button) {
150
+ // First check for data-tab attribute
151
+ const dataTab = button.getAttribute('data-tab');
152
+ if (dataTab) return dataTab;
153
+
154
+ // Fallback to text content matching
93
155
  const text = button.textContent.toLowerCase();
94
156
  if (text.includes('events')) return 'events';
95
157
  if (text.includes('activity')) return 'activity';
96
158
  if (text.includes('agents')) return 'agents';
97
159
  if (text.includes('tools')) return 'tools';
160
+ if (text.includes('browser')) return 'browser-logs'; // Added browser logs support
98
161
  if (text.includes('files')) return 'files';
162
+ if (text.includes('file tree')) return 'claude-tree';
99
163
  if (text.includes('code')) return 'code';
100
164
  if (text.includes('sessions')) return 'sessions';
101
165
  if (text.includes('system')) return 'system';
@@ -105,28 +169,70 @@ class UIStateManager {
105
169
  /**
106
170
  * Switch to specified tab
107
171
  * @param {string} tabName - Name of tab to switch to
172
+ * @param {boolean} updateHash - Whether to update URL hash (default: true)
108
173
  */
109
- switchTab(tabName) {
110
- console.log(`[DEBUG] switchTab called with tabName: ${tabName}`);
174
+ switchTab(tabName, updateHash = true) {
175
+ console.log(`[Hash Navigation] switchTab called with tabName: ${tabName}, updateHash: ${updateHash}`);
176
+
177
+ // Update URL hash if requested (when triggered by user action, not hash change)
178
+ if (updateHash && this.tabToHash[tabName]) {
179
+ const newHash = this.tabToHash[tabName];
180
+ if (window.location.hash !== newHash) {
181
+ console.log(`[Hash Navigation] Updating hash to: ${newHash}`);
182
+ window.location.hash = newHash;
183
+ return; // The hashchange event will trigger switchTab again
184
+ }
185
+ }
186
+
111
187
  const previousTab = this.currentTab;
112
188
  this.currentTab = tabName;
113
189
 
114
- // Update tab button active states
115
- document.querySelectorAll('.tab-button').forEach(btn => {
190
+ // Update tab button active states - ensure ALL tabs are deselected first
191
+ const allTabButtons = document.querySelectorAll('.tab-button');
192
+ allTabButtons.forEach(btn => {
116
193
  btn.classList.remove('active');
117
- if (this.getTabNameFromButton(btn) === tabName) {
194
+ });
195
+
196
+ // Now add active class ONLY to the selected tab
197
+ allTabButtons.forEach(btn => {
198
+ const btnTabName = this.getTabNameFromButton(btn);
199
+ if (btnTabName === tabName) {
118
200
  btn.classList.add('active');
201
+ console.log(`[DEBUG] Set active on button with data-tab: ${btn.getAttribute('data-tab')}`);
119
202
  }
120
203
  });
121
204
 
122
- // Show/hide tab content using CSS classes
123
- document.querySelectorAll('.tab-content').forEach(content => {
205
+ // Show/hide tab content using CSS classes - ensure ALL are hidden first
206
+ const allTabContents = document.querySelectorAll('.tab-content');
207
+ allTabContents.forEach(content => {
124
208
  content.classList.remove('active');
125
209
  });
126
210
 
211
+ // Now show ONLY the selected tab content
127
212
  const activeTab = document.getElementById(`${tabName}-tab`);
128
213
  if (activeTab) {
129
214
  activeTab.classList.add('active');
215
+ console.log(`[DEBUG] Set active on content: ${tabName}-tab`);
216
+
217
+ // Special handling for File Tree tab - ensure it never shows events
218
+ if (tabName === 'claude-tree') {
219
+ const claudeTreeContainer = document.getElementById('claude-tree-container');
220
+ if (claudeTreeContainer) {
221
+ // Check if events list somehow got into this container
222
+ const eventsList = claudeTreeContainer.querySelector('#events-list');
223
+ if (eventsList) {
224
+ console.warn('[UIStateManager] Found events-list in File Tree container, removing it!');
225
+ eventsList.remove();
226
+ }
227
+
228
+ // Check for event items
229
+ const eventItems = claudeTreeContainer.querySelectorAll('.event-item');
230
+ if (eventItems.length > 0) {
231
+ console.warn('[UIStateManager] Found event items in File Tree container, clearing!');
232
+ eventItems.forEach(item => item.remove());
233
+ }
234
+ }
235
+ }
130
236
  }
131
237
 
132
238
  // Clear previous selections when switching tabs
@@ -145,6 +251,188 @@ class UIStateManager {
145
251
  if (this.autoScroll) {
146
252
  this.scrollCurrentTabToBottom();
147
253
  }
254
+
255
+ // Special handling for File Tree tab - trigger the tree render
256
+ // But DON'T let it manipulate tabs itself
257
+ if (tabName === 'claude-tree' && window.CodeViewer) {
258
+ // Call a new method that only renders content, not tab switching
259
+ if (window.CodeViewer.renderContent) {
260
+ window.CodeViewer.renderContent();
261
+ } else {
262
+ // Fallback to show() but it should be fixed to not switch tabs
263
+ window.CodeViewer.show();
264
+ }
265
+ }
266
+
267
+ // EXTREME NUCLEAR HANDLING for Browser Logs tab - FORCE COMPLETE ISOLATION
268
+ if (tabName === 'browser-logs') {
269
+ console.error('[UI-STATE v3 EXTREME] 🚨🚨🚨 SWITCHING TO BROWSER LOGS - EXTREME NUCLEAR MODE');
270
+ console.error('[UI-STATE v3 EXTREME] Stack trace:', new Error().stack);
271
+
272
+ // EXTREME DIAGNOSTIC: Check what's trying to render
273
+ const container = document.getElementById('browser-logs-container');
274
+ if (container) {
275
+ console.error('[UI-STATE v3 EXTREME] Container found, current innerHTML length:', container.innerHTML.length);
276
+ console.error('[UI-STATE v3 EXTREME] Container classes:', container.className);
277
+ console.error('[UI-STATE v3 EXTREME] Container children count:', container.children.length);
278
+
279
+ // EXTREME: Stop ALL event propagation
280
+ const stopAllEvents = (e) => {
281
+ e.stopPropagation();
282
+ e.stopImmediatePropagation();
283
+ e.preventDefault();
284
+ };
285
+
286
+ // EXTREME: Block EventViewer from touching this container
287
+ if (window.eventViewer) {
288
+ console.error('[UI-STATE v3 EXTREME] 🚨 EventViewer exists - DISABLING IT');
289
+ // Temporarily override EventViewer's renderEvents method
290
+ const originalRender = window.eventViewer.renderEvents;
291
+ window.eventViewer.renderEvents = function() {
292
+ const targetEl = document.getElementById('events-list');
293
+ // Only allow rendering if target is NOT in browser-logs-tab
294
+ if (targetEl && !targetEl.closest('#browser-logs-tab')) {
295
+ return originalRender.call(this);
296
+ }
297
+ console.error('[UI-STATE v3 EXTREME] BLOCKED EventViewer.renderEvents in Browser Logs tab!');
298
+ };
299
+ }
300
+
301
+ // EXTREME CLEAR: Multiple passes to ensure complete clearing
302
+ for (let i = 0; i < 3; i++) {
303
+ container.innerHTML = '';
304
+ container.textContent = '';
305
+ while (container.firstChild) {
306
+ container.removeChild(container.firstChild);
307
+ }
308
+ }
309
+
310
+ // Reset all attributes and classes
311
+ container.className = '';
312
+ container.removeAttribute('data-events');
313
+ container.removeAttribute('data-component');
314
+ container.setAttribute('data-component', 'browser-logs-only');
315
+ container.setAttribute('data-no-events', 'true');
316
+
317
+ // EXTREME: Set a guard flag
318
+ container.dataset.browserLogsGuard = 'active';
319
+
320
+ // EXTREME: Override container's innerHTML setter temporarily
321
+ const originalInnerHTML = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML');
322
+ Object.defineProperty(container, 'innerHTML', {
323
+ set: function(value) {
324
+ if (value && typeof value === 'string' &&
325
+ (value.includes('[hook]') || value.includes('event-item') ||
326
+ value.includes('hook.pre_tool') || value.includes('hook.post_tool'))) {
327
+ console.error('[UI-STATE v3 EXTREME] 🚨 BLOCKED CONTAMINATED innerHTML:', value.substring(0, 100));
328
+ return;
329
+ }
330
+ originalInnerHTML.set.call(this, value);
331
+ },
332
+ get: function() {
333
+ return originalInnerHTML.get.call(this);
334
+ },
335
+ configurable: true
336
+ });
337
+
338
+ // Check if BrowserLogViewer exists
339
+ if (typeof BrowserLogViewer !== 'undefined') {
340
+ // ALWAYS recreate to ensure clean state
341
+ if (window.browserLogViewer) {
342
+ console.error('[UI-STATE v3 EXTREME] Destroying old BrowserLogViewer instance');
343
+ if (window.browserLogViewer.destroy) {
344
+ window.browserLogViewer.destroy();
345
+ }
346
+ window.browserLogViewer = null;
347
+ }
348
+
349
+ // Create fresh instance with extreme verification
350
+ console.error('[UI-STATE v3 EXTREME] Creating NEW BrowserLogViewer v3.0 EXTREME instance');
351
+ window.browserLogViewer = new BrowserLogViewer(container);
352
+ console.error('[UI-STATE v3 EXTREME] ✅ BrowserLogViewer v3.0 EXTREME INITIALIZED');
353
+
354
+ // Force immediate render
355
+ if (window.browserLogViewer.render) {
356
+ window.browserLogViewer.render();
357
+ }
358
+ } else {
359
+ // Fallback: Show hardcoded message if viewer not loaded
360
+ console.error('[UI-STATE v3 EXTREME] BrowserLogViewer not found - showing fallback');
361
+ // Restore innerHTML setter for fallback message
362
+ Object.defineProperty(container, 'innerHTML', originalInnerHTML);
363
+ container.innerHTML = `
364
+ <div style="padding: 20px; text-align: center; background: #f0f0f0; border: 3px solid red;">
365
+ <h1 style="color: red;">🚨 BROWSER LOGS ONLY 🚨</h1>
366
+ <h2 style="color: green;">NO HOOK EVENTS ALLOWED</h2>
367
+ <p style="color: red; font-weight: bold; font-size: 18px;">⚠️ Hook events ([hook]) are FORCEFULLY BLOCKED ⚠️</p>
368
+ <p>This tab shows ONLY browser console logs.</p>
369
+ <p style="color: blue;">Browser Log Viewer v3.0 EXTREME is loading...</p>
370
+ </div>
371
+ `;
372
+ }
373
+
374
+ // EXTREME: Multiple contamination checks
375
+ const checkContamination = () => {
376
+ const contamination = container.querySelectorAll('.event-item, .events-list, [class*="event"]');
377
+ if (contamination.length > 0) {
378
+ console.error(`[UI-STATE v3 EXTREME] 🚨 CONTAMINATION DETECTED (${contamination.length} items) - NUKING!`);
379
+ contamination.forEach(item => {
380
+ console.error('[UI-STATE v3 EXTREME] Removing contaminated element:', item.className);
381
+ item.remove();
382
+ });
383
+ if (window.browserLogViewer && window.browserLogViewer.render) {
384
+ window.browserLogViewer.render();
385
+ }
386
+ }
387
+
388
+ // Check text content for hook events
389
+ if (container.textContent.includes('[hook]') ||
390
+ container.textContent.includes('hook.pre_tool')) {
391
+ console.error('[UI-STATE v3 EXTREME] 🚨 TEXT CONTAMINATION DETECTED!');
392
+ if (window.browserLogViewer) {
393
+ container.innerHTML = '';
394
+ window.browserLogViewer.render();
395
+ }
396
+ }
397
+ };
398
+
399
+ // Run contamination checks multiple times
400
+ setTimeout(checkContamination, 50);
401
+ setTimeout(checkContamination, 100);
402
+ setTimeout(checkContamination, 200);
403
+ setTimeout(checkContamination, 500);
404
+
405
+ // EXTREME: Monitor for mutations
406
+ const observer = new MutationObserver((mutations) => {
407
+ for (const mutation of mutations) {
408
+ if (mutation.type === 'childList') {
409
+ for (const node of mutation.addedNodes) {
410
+ if (node.nodeType === Node.ELEMENT_NODE) {
411
+ const element = node;
412
+ if (element.classList?.contains('event-item') ||
413
+ element.textContent?.includes('[hook]')) {
414
+ console.error('[UI-STATE v3 EXTREME] 🚨 MUTATION DETECTED - BLOCKING!');
415
+ element.remove();
416
+ }
417
+ }
418
+ }
419
+ }
420
+ }
421
+ });
422
+
423
+ observer.observe(container, {
424
+ childList: true,
425
+ subtree: true,
426
+ characterData: true
427
+ });
428
+
429
+ // Store observer for cleanup
430
+ container.dataset.mutationObserver = 'active';
431
+ window.browserLogsMutationObserver = observer;
432
+ } else {
433
+ console.error('[UI-STATE v3 EXTREME] 🚨 BROWSER LOGS CONTAINER NOT FOUND!');
434
+ }
435
+ }
148
436
  }, 100);
149
437
  }
150
438
 
@@ -351,8 +351,8 @@ class SocketClient {
351
351
  timeout: 30000, // Increased connection timeout to 30 seconds
352
352
  forceNew: true,
353
353
  transports: ['websocket', 'polling'],
354
- pingInterval: 30000, // Increased ping interval for stability
355
- pingTimeout: 60000 // Much longer timeout for better stability
354
+ // Remove client-side ping configuration - let server control this
355
+ // The server now properly configures: ping_interval=30s, ping_timeout=60s
356
356
  });
357
357
 
358
358
  this.setupSocketHandlers();