claude-mpm 4.2.40__py3-none-any.whl → 4.2.43__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 (36) 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/commands/mpm-browser-monitor.md +370 -0
  10. claude_mpm/commands/mpm-monitor.md +177 -0
  11. claude_mpm/dashboard/static/built/components/code-viewer.js +1076 -2
  12. claude_mpm/dashboard/static/built/components/ui-state-manager.js +465 -2
  13. claude_mpm/dashboard/static/css/dashboard.css +2 -0
  14. claude_mpm/dashboard/static/js/browser-console-monitor.js +495 -0
  15. claude_mpm/dashboard/static/js/components/browser-log-viewer.js +763 -0
  16. claude_mpm/dashboard/static/js/components/code-viewer.js +931 -340
  17. claude_mpm/dashboard/static/js/components/diff-viewer.js +891 -0
  18. claude_mpm/dashboard/static/js/components/file-change-tracker.js +443 -0
  19. claude_mpm/dashboard/static/js/components/file-change-viewer.js +690 -0
  20. claude_mpm/dashboard/static/js/components/ui-state-manager.js +156 -19
  21. claude_mpm/dashboard/static/js/dashboard.js +16 -0
  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 +64 -99
  25. claude_mpm/services/monitor/handlers/browser.py +451 -0
  26. claude_mpm/services/monitor/server.py +267 -4
  27. {claude_mpm-4.2.40.dist-info → claude_mpm-4.2.43.dist-info}/METADATA +1 -1
  28. {claude_mpm-4.2.40.dist-info → claude_mpm-4.2.43.dist-info}/RECORD +32 -26
  29. claude_mpm/agents/templates/agentic-coder-optimizer.md +0 -44
  30. claude_mpm/agents/templates/agentic_coder_optimizer.json +0 -238
  31. claude_mpm/agents/templates/test-non-mpm.json +0 -20
  32. claude_mpm/dashboard/static/dist/components/code-viewer.js +0 -2
  33. {claude_mpm-4.2.40.dist-info → claude_mpm-4.2.43.dist-info}/WHEEL +0 -0
  34. {claude_mpm-4.2.40.dist-info → claude_mpm-4.2.43.dist-info}/entry_points.txt +0 -0
  35. {claude_mpm-4.2.40.dist-info → claude_mpm-4.2.43.dist-info}/licenses/LICENSE +0 -0
  36. {claude_mpm-4.2.40.dist-info → claude_mpm-4.2.43.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,37 @@ 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
+ // 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
+ }
148
285
  }, 100);
149
286
  }
150
287
 
@@ -493,6 +493,22 @@ 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;
496
512
  }
497
513
 
498
514
  // Update selection UI if we have a selected card
@@ -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();