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
@@ -1,2 +1,465 @@
1
- import{U as a,U as t}from"../socket-client.js";export{a as UIStateManager,t as default};
2
- //# sourceMappingURL=ui-state-manager.js.map
1
+ /**
2
+ * UI State Manager Module
3
+ *
4
+ * Manages UI state including tab switching, card selection, keyboard navigation,
5
+ * and visual feedback across the dashboard interface.
6
+ *
7
+ * WHY: Extracted from main dashboard to centralize UI state management and
8
+ * provide better separation between business logic and UI state. This makes
9
+ * the UI behavior more predictable and easier to test.
10
+ *
11
+ * DESIGN DECISION: Maintains centralized state for current tab, selected cards,
12
+ * and navigation context while providing a clean API for other modules to
13
+ * interact with UI state changes.
14
+ */
15
+ class UIStateManager {
16
+ constructor() {
17
+ // Current active tab
18
+ this.currentTab = 'events';
19
+
20
+ // Auto-scroll behavior
21
+ this.autoScroll = true;
22
+
23
+ // Selection state - tracks the currently selected card across all tabs
24
+ this.selectedCard = {
25
+ tab: null, // which tab the selection is in
26
+ index: null, // index of selected item in that tab
27
+ type: null, // 'event', 'agent', 'tool', 'file'
28
+ data: null // the actual data object
29
+ };
30
+
31
+ // Navigation state for each tab
32
+ this.tabNavigation = {
33
+ events: { selectedIndex: -1, items: [] },
34
+ agents: { selectedIndex: -1, items: [] },
35
+ tools: { selectedIndex: -1, items: [] },
36
+ files: { selectedIndex: -1, items: [] }
37
+ };
38
+
39
+ this.setupEventHandlers();
40
+ console.log('UI state manager initialized');
41
+ }
42
+
43
+ /**
44
+ * Set up event handlers for UI interactions
45
+ */
46
+ setupEventHandlers() {
47
+ this.setupTabNavigation();
48
+ this.setupUnifiedKeyboardNavigation();
49
+ }
50
+
51
+ /**
52
+ * Set up tab navigation event listeners
53
+ */
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
+ });
61
+ });
62
+ }
63
+
64
+ /**
65
+ * Set up unified keyboard navigation across all tabs
66
+ */
67
+ setupUnifiedKeyboardNavigation() {
68
+ document.addEventListener('keydown', (e) => {
69
+ // Only handle if not in an input field
70
+ if (document.activeElement &&
71
+ ['INPUT', 'TEXTAREA', 'SELECT'].includes(document.activeElement.tagName)) {
72
+ return;
73
+ }
74
+
75
+ if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
76
+ e.preventDefault();
77
+ this.handleUnifiedArrowNavigation(e.key === 'ArrowDown' ? 1 : -1);
78
+ } else if (e.key === 'Enter') {
79
+ e.preventDefault();
80
+ this.handleUnifiedEnterKey();
81
+ } else if (e.key === 'Escape') {
82
+ this.clearUnifiedSelection();
83
+ }
84
+ });
85
+ }
86
+
87
+ /**
88
+ * Get tab name from button element
89
+ * @param {HTMLElement} button - Tab button element
90
+ * @returns {string} - Tab name
91
+ */
92
+ getTabNameFromButton(button) {
93
+ // First check for data-tab attribute
94
+ const dataTab = button.getAttribute('data-tab');
95
+ if (dataTab) return dataTab;
96
+
97
+ // Fallback to text content matching
98
+ const text = button.textContent.toLowerCase();
99
+ if (text.includes('events')) return 'events';
100
+ if (text.includes('activity')) return 'activity';
101
+ if (text.includes('agents')) return 'agents';
102
+ if (text.includes('tools')) return 'tools';
103
+ if (text.includes('files')) return 'files';
104
+ if (text.includes('claude tree')) return 'claude-tree';
105
+ if (text.includes('code')) return 'code';
106
+ if (text.includes('sessions')) return 'sessions';
107
+ if (text.includes('system')) return 'system';
108
+ return 'events';
109
+ }
110
+
111
+ /**
112
+ * Switch to specified tab
113
+ * @param {string} tabName - Name of tab to switch to
114
+ */
115
+ switchTab(tabName) {
116
+ console.log(`[DEBUG] switchTab called with tabName: ${tabName}`);
117
+ const previousTab = this.currentTab;
118
+ this.currentTab = tabName;
119
+
120
+ // Update tab button active states
121
+ document.querySelectorAll('.tab-button').forEach(btn => {
122
+ btn.classList.remove('active');
123
+ if (this.getTabNameFromButton(btn) === tabName) {
124
+ btn.classList.add('active');
125
+ }
126
+ });
127
+
128
+ // Show/hide tab content using CSS classes
129
+ document.querySelectorAll('.tab-content').forEach(content => {
130
+ content.classList.remove('active');
131
+ });
132
+
133
+ const activeTab = document.getElementById(`${tabName}-tab`);
134
+ if (activeTab) {
135
+ activeTab.classList.add('active');
136
+
137
+ // Special handling for Claude Tree tab - ensure it never shows events
138
+ if (tabName === 'claude-tree') {
139
+ const claudeTreeContainer = document.getElementById('claude-tree-container');
140
+ if (claudeTreeContainer) {
141
+ // Check if events list somehow got into this container
142
+ const eventsList = claudeTreeContainer.querySelector('#events-list');
143
+ if (eventsList) {
144
+ console.warn('[UIStateManager] Found events-list in Claude Tree container, removing it!');
145
+ eventsList.remove();
146
+ }
147
+
148
+ // Check for event items
149
+ const eventItems = claudeTreeContainer.querySelectorAll('.event-item');
150
+ if (eventItems.length > 0) {
151
+ console.warn('[UIStateManager] Found event items in Claude Tree container, clearing!');
152
+ eventItems.forEach(item => item.remove());
153
+ }
154
+ }
155
+ }
156
+ }
157
+
158
+ // Clear previous selections when switching tabs
159
+ this.clearUnifiedSelection();
160
+
161
+ // Trigger tab change event for other modules
162
+ document.dispatchEvent(new CustomEvent('tabChanged', {
163
+ detail: {
164
+ newTab: tabName,
165
+ previousTab: previousTab
166
+ }
167
+ }));
168
+
169
+ // Auto-scroll to bottom after a brief delay to ensure content is rendered
170
+ setTimeout(() => {
171
+ if (this.autoScroll) {
172
+ this.scrollCurrentTabToBottom();
173
+ }
174
+
175
+ // Special handling for Claude Tree tab - trigger the tree render
176
+ if (tabName === 'claude-tree' && window.CodeViewer) {
177
+ window.CodeViewer.show();
178
+ }
179
+ }, 100);
180
+ }
181
+
182
+ /**
183
+ * Handle unified arrow navigation across tabs
184
+ * @param {number} direction - Navigation direction (1 for down, -1 for up)
185
+ */
186
+ handleUnifiedArrowNavigation(direction) {
187
+ const tabNav = this.tabNavigation[this.currentTab];
188
+ if (!tabNav) return;
189
+
190
+ let newIndex = tabNav.selectedIndex + direction;
191
+
192
+ // Handle bounds
193
+ if (tabNav.items.length === 0) return;
194
+
195
+ if (newIndex < 0) {
196
+ newIndex = tabNav.items.length - 1;
197
+ } else if (newIndex >= tabNav.items.length) {
198
+ newIndex = 0;
199
+ }
200
+
201
+ this.selectCardByIndex(this.currentTab, newIndex);
202
+ }
203
+
204
+ /**
205
+ * Handle unified Enter key across all tabs
206
+ */
207
+ handleUnifiedEnterKey() {
208
+ const tabNav = this.tabNavigation[this.currentTab];
209
+ if (!tabNav || tabNav.selectedIndex === -1) return;
210
+
211
+ const selectedElement = tabNav.items[tabNav.selectedIndex];
212
+ if (selectedElement && selectedElement.onclick) {
213
+ selectedElement.onclick();
214
+ }
215
+ }
216
+
217
+ /**
218
+ * Clear all unified selection states
219
+ */
220
+ clearUnifiedSelection() {
221
+ // Clear all tab navigation states
222
+ Object.keys(this.tabNavigation).forEach(tabName => {
223
+ this.tabNavigation[tabName].selectedIndex = -1;
224
+ });
225
+
226
+ // Clear card selection
227
+ this.clearCardSelection();
228
+ }
229
+
230
+ /**
231
+ * Update tab navigation items for current tab
232
+ * Should be called after tab content is rendered
233
+ */
234
+ updateTabNavigationItems() {
235
+ const tabNav = this.tabNavigation[this.currentTab];
236
+ if (!tabNav) return;
237
+
238
+ let containerSelector;
239
+ switch (this.currentTab) {
240
+ case 'events':
241
+ containerSelector = '#events-list .event-item';
242
+ break;
243
+ case 'agents':
244
+ containerSelector = '#agents-list .event-item';
245
+ break;
246
+ case 'tools':
247
+ containerSelector = '#tools-list .event-item';
248
+ break;
249
+ case 'files':
250
+ containerSelector = '#files-list .event-item';
251
+ break;
252
+ }
253
+
254
+ if (containerSelector) {
255
+ tabNav.items = Array.from(document.querySelectorAll(containerSelector));
256
+ }
257
+ }
258
+
259
+ /**
260
+ * Select card by index for specified tab
261
+ * @param {string} tabName - Tab name
262
+ * @param {number} index - Index of item to select
263
+ */
264
+ selectCardByIndex(tabName, index) {
265
+ const tabNav = this.tabNavigation[tabName];
266
+ if (!tabNav || index < 0 || index >= tabNav.items.length) return;
267
+
268
+ // Update navigation state
269
+ tabNav.selectedIndex = index;
270
+
271
+ // Update visual selection
272
+ this.updateUnifiedSelectionUI();
273
+
274
+ // If this is a different tab selection, record the card selection
275
+ const selectedElement = tabNav.items[index];
276
+ if (selectedElement) {
277
+ // Extract data from the element to populate selectedCard
278
+ this.selectCard(tabName, index, this.getCardType(tabName), index);
279
+ }
280
+
281
+ // Show details for the selected item
282
+ this.showCardDetails(tabName, index);
283
+ }
284
+
285
+ /**
286
+ * Update visual selection UI for unified navigation
287
+ */
288
+ updateUnifiedSelectionUI() {
289
+ // Clear all existing selections
290
+ document.querySelectorAll('.event-item.keyboard-selected').forEach(el => {
291
+ el.classList.remove('keyboard-selected');
292
+ });
293
+
294
+ // Apply selection to current tab's selected item
295
+ const tabNav = this.tabNavigation[this.currentTab];
296
+ if (tabNav && tabNav.selectedIndex !== -1 && tabNav.items[tabNav.selectedIndex]) {
297
+ tabNav.items[tabNav.selectedIndex].classList.add('keyboard-selected');
298
+ }
299
+ }
300
+
301
+ /**
302
+ * Show card details for specified tab and index
303
+ * @param {string} tabName - Tab name
304
+ * @param {number} index - Item index
305
+ */
306
+ showCardDetails(tabName, index) {
307
+ // Dispatch event for other modules to handle
308
+ document.dispatchEvent(new CustomEvent('showCardDetails', {
309
+ detail: {
310
+ tabName: tabName,
311
+ index: index
312
+ }
313
+ }));
314
+ }
315
+
316
+ /**
317
+ * Select a specific card
318
+ * @param {string} tabName - Tab name
319
+ * @param {number} index - Item index
320
+ * @param {string} type - Item type
321
+ * @param {*} data - Item data
322
+ */
323
+ selectCard(tabName, index, type, data) {
324
+ // Clear previous selection
325
+ this.clearCardSelection();
326
+
327
+ // Update selection state
328
+ this.selectedCard = {
329
+ tab: tabName,
330
+ index: index,
331
+ type: type,
332
+ data: data
333
+ };
334
+
335
+ this.updateCardSelectionUI();
336
+
337
+ console.log('Card selected:', this.selectedCard);
338
+ }
339
+
340
+ /**
341
+ * Clear card selection
342
+ */
343
+ clearCardSelection() {
344
+ // Clear visual selection from all tabs
345
+ document.querySelectorAll('.event-item.selected, .file-item.selected').forEach(el => {
346
+ el.classList.remove('selected');
347
+ });
348
+
349
+ // Reset selection state
350
+ this.selectedCard = {
351
+ tab: null,
352
+ index: null,
353
+ type: null,
354
+ data: null
355
+ };
356
+ }
357
+
358
+ /**
359
+ * Update card selection UI
360
+ */
361
+ updateCardSelectionUI() {
362
+ if (!this.selectedCard.tab || this.selectedCard.index === null) return;
363
+
364
+ // Get the list container for the selected tab
365
+ let listContainer;
366
+ switch (this.selectedCard.tab) {
367
+ case 'events':
368
+ listContainer = document.getElementById('events-list');
369
+ break;
370
+ case 'agents':
371
+ listContainer = document.getElementById('agents-list');
372
+ break;
373
+ case 'tools':
374
+ listContainer = document.getElementById('tools-list');
375
+ break;
376
+ case 'files':
377
+ listContainer = document.getElementById('files-list');
378
+ break;
379
+ }
380
+
381
+ if (listContainer) {
382
+ const items = listContainer.querySelectorAll('.event-item, .file-item');
383
+ if (items[this.selectedCard.index]) {
384
+ items[this.selectedCard.index].classList.add('selected');
385
+ }
386
+ }
387
+ }
388
+
389
+ /**
390
+ * Get card type based on tab name
391
+ * @param {string} tabName - Tab name
392
+ * @returns {string} - Card type
393
+ */
394
+ getCardType(tabName) {
395
+ switch (tabName) {
396
+ case 'events': return 'event';
397
+ case 'agents': return 'agent';
398
+ case 'tools': return 'tool';
399
+ case 'files': return 'file';
400
+ default: return 'unknown';
401
+ }
402
+ }
403
+
404
+ /**
405
+ * Scroll current tab to bottom
406
+ */
407
+ scrollCurrentTabToBottom() {
408
+ const tabId = `${this.currentTab}-list`;
409
+ const element = document.getElementById(tabId);
410
+ if (element && this.autoScroll) {
411
+ element.scrollTop = element.scrollHeight;
412
+ }
413
+ }
414
+
415
+ /**
416
+ * Clear selection for cleanup
417
+ */
418
+ clearSelection() {
419
+ this.clearCardSelection();
420
+ this.clearUnifiedSelection();
421
+ }
422
+
423
+ /**
424
+ * Get current tab name
425
+ * @returns {string} - Current tab name
426
+ */
427
+ getCurrentTab() {
428
+ return this.currentTab;
429
+ }
430
+
431
+ /**
432
+ * Get selected card info
433
+ * @returns {Object} - Selected card state
434
+ */
435
+ getSelectedCard() {
436
+ return { ...this.selectedCard };
437
+ }
438
+
439
+ /**
440
+ * Get tab navigation state
441
+ * @returns {Object} - Tab navigation state
442
+ */
443
+ getTabNavigation() {
444
+ return { ...this.tabNavigation };
445
+ }
446
+
447
+ /**
448
+ * Set auto-scroll behavior
449
+ * @param {boolean} enabled - Whether to enable auto-scroll
450
+ */
451
+ setAutoScroll(enabled) {
452
+ this.autoScroll = enabled;
453
+ }
454
+
455
+ /**
456
+ * Get auto-scroll state
457
+ * @returns {boolean} - Auto-scroll enabled state
458
+ */
459
+ getAutoScroll() {
460
+ return this.autoScroll;
461
+ }
462
+ }
463
+ // ES6 Module export
464
+ export { UIStateManager };
465
+ export default UIStateManager;
@@ -867,6 +867,7 @@ button:active {
867
867
  }
868
868
 
869
869
  .tab-button {
870
+ display: inline-block;
870
871
  padding: 10px 10px;
871
872
  background: none;
872
873
  border: none;
@@ -875,6 +876,7 @@ button:active {
875
876
  font-size: 14px;
876
877
  font-weight: 500;
877
878
  color: #64748b;
879
+ text-decoration: none;
878
880
  transition: all 0.2s;
879
881
  }
880
882