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
@@ -14,8 +14,31 @@
|
|
14
14
|
*/
|
15
15
|
class UIStateManager {
|
16
16
|
constructor() {
|
17
|
-
//
|
18
|
-
this.
|
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.
|
82
|
+
this.setupHashNavigation();
|
48
83
|
this.setupUnifiedKeyboardNavigation();
|
49
84
|
}
|
50
85
|
|
51
86
|
/**
|
52
|
-
* Set up
|
87
|
+
* Set up hash-based navigation
|
53
88
|
*/
|
54
|
-
|
55
|
-
//
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
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(`[
|
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')
|
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
|
-
|
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')
|
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
|
-
|
355
|
-
|
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();
|