claude-mpm 3.4.13__py3-none-any.whl → 3.4.14__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 (27) hide show
  1. claude_mpm/dashboard/index.html +13 -0
  2. claude_mpm/dashboard/static/css/dashboard.css +2722 -0
  3. claude_mpm/dashboard/static/js/components/agent-inference.js +619 -0
  4. claude_mpm/dashboard/static/js/components/event-processor.js +641 -0
  5. claude_mpm/dashboard/static/js/components/event-viewer.js +914 -0
  6. claude_mpm/dashboard/static/js/components/export-manager.js +362 -0
  7. claude_mpm/dashboard/static/js/components/file-tool-tracker.js +611 -0
  8. claude_mpm/dashboard/static/js/components/hud-library-loader.js +211 -0
  9. claude_mpm/dashboard/static/js/components/hud-manager.js +671 -0
  10. claude_mpm/dashboard/static/js/components/hud-visualizer.js +1718 -0
  11. claude_mpm/dashboard/static/js/components/module-viewer.js +2701 -0
  12. claude_mpm/dashboard/static/js/components/session-manager.js +520 -0
  13. claude_mpm/dashboard/static/js/components/socket-manager.js +343 -0
  14. claude_mpm/dashboard/static/js/components/ui-state-manager.js +427 -0
  15. claude_mpm/dashboard/static/js/components/working-directory.js +866 -0
  16. claude_mpm/dashboard/static/js/dashboard-original.js +4134 -0
  17. claude_mpm/dashboard/static/js/dashboard.js +1978 -0
  18. claude_mpm/dashboard/static/js/socket-client.js +537 -0
  19. claude_mpm/dashboard/templates/index.html +346 -0
  20. claude_mpm/dashboard/test_dashboard.html +372 -0
  21. claude_mpm/services/socketio_server.py +41 -5
  22. {claude_mpm-3.4.13.dist-info → claude_mpm-3.4.14.dist-info}/METADATA +2 -1
  23. {claude_mpm-3.4.13.dist-info → claude_mpm-3.4.14.dist-info}/RECORD +27 -7
  24. {claude_mpm-3.4.13.dist-info → claude_mpm-3.4.14.dist-info}/WHEEL +0 -0
  25. {claude_mpm-3.4.13.dist-info → claude_mpm-3.4.14.dist-info}/entry_points.txt +0 -0
  26. {claude_mpm-3.4.13.dist-info → claude_mpm-3.4.14.dist-info}/licenses/LICENSE +0 -0
  27. {claude_mpm-3.4.13.dist-info → claude_mpm-3.4.14.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,427 @@
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
+ const text = button.textContent.toLowerCase();
94
+ if (text.includes('events')) return 'events';
95
+ if (text.includes('agents')) return 'agents';
96
+ if (text.includes('tools')) return 'tools';
97
+ if (text.includes('files')) return 'files';
98
+ return 'events';
99
+ }
100
+
101
+ /**
102
+ * Switch to specified tab
103
+ * @param {string} tabName - Name of tab to switch to
104
+ */
105
+ switchTab(tabName) {
106
+ console.log(`[DEBUG] switchTab called with tabName: ${tabName}`);
107
+ const previousTab = this.currentTab;
108
+ this.currentTab = tabName;
109
+
110
+ // Update tab button active states
111
+ document.querySelectorAll('.tab-button').forEach(btn => {
112
+ btn.classList.remove('active');
113
+ if (this.getTabNameFromButton(btn) === tabName) {
114
+ btn.classList.add('active');
115
+ }
116
+ });
117
+
118
+ // Show/hide tab content using CSS classes
119
+ document.querySelectorAll('.tab-content').forEach(content => {
120
+ content.classList.remove('active');
121
+ });
122
+
123
+ const activeTab = document.getElementById(`${tabName}-tab`);
124
+ if (activeTab) {
125
+ activeTab.classList.add('active');
126
+ }
127
+
128
+ // Clear previous selections when switching tabs
129
+ this.clearUnifiedSelection();
130
+
131
+ // Trigger tab change event for other modules
132
+ document.dispatchEvent(new CustomEvent('tabChanged', {
133
+ detail: {
134
+ newTab: tabName,
135
+ previousTab: previousTab
136
+ }
137
+ }));
138
+
139
+ // Auto-scroll to bottom after a brief delay to ensure content is rendered
140
+ setTimeout(() => {
141
+ if (this.autoScroll) {
142
+ this.scrollCurrentTabToBottom();
143
+ }
144
+ }, 100);
145
+ }
146
+
147
+ /**
148
+ * Handle unified arrow navigation across tabs
149
+ * @param {number} direction - Navigation direction (1 for down, -1 for up)
150
+ */
151
+ handleUnifiedArrowNavigation(direction) {
152
+ const tabNav = this.tabNavigation[this.currentTab];
153
+ if (!tabNav) return;
154
+
155
+ let newIndex = tabNav.selectedIndex + direction;
156
+
157
+ // Handle bounds
158
+ if (tabNav.items.length === 0) return;
159
+
160
+ if (newIndex < 0) {
161
+ newIndex = tabNav.items.length - 1;
162
+ } else if (newIndex >= tabNav.items.length) {
163
+ newIndex = 0;
164
+ }
165
+
166
+ this.selectCardByIndex(this.currentTab, newIndex);
167
+ }
168
+
169
+ /**
170
+ * Handle unified Enter key across all tabs
171
+ */
172
+ handleUnifiedEnterKey() {
173
+ const tabNav = this.tabNavigation[this.currentTab];
174
+ if (!tabNav || tabNav.selectedIndex === -1) return;
175
+
176
+ const selectedElement = tabNav.items[tabNav.selectedIndex];
177
+ if (selectedElement && selectedElement.onclick) {
178
+ selectedElement.onclick();
179
+ }
180
+ }
181
+
182
+ /**
183
+ * Clear all unified selection states
184
+ */
185
+ clearUnifiedSelection() {
186
+ // Clear all tab navigation states
187
+ Object.keys(this.tabNavigation).forEach(tabName => {
188
+ this.tabNavigation[tabName].selectedIndex = -1;
189
+ });
190
+
191
+ // Clear card selection
192
+ this.clearCardSelection();
193
+ }
194
+
195
+ /**
196
+ * Update tab navigation items for current tab
197
+ * Should be called after tab content is rendered
198
+ */
199
+ updateTabNavigationItems() {
200
+ const tabNav = this.tabNavigation[this.currentTab];
201
+ if (!tabNav) return;
202
+
203
+ let containerSelector;
204
+ switch (this.currentTab) {
205
+ case 'events':
206
+ containerSelector = '#events-list .event-item';
207
+ break;
208
+ case 'agents':
209
+ containerSelector = '#agents-list .event-item';
210
+ break;
211
+ case 'tools':
212
+ containerSelector = '#tools-list .event-item';
213
+ break;
214
+ case 'files':
215
+ containerSelector = '#files-list .event-item';
216
+ break;
217
+ }
218
+
219
+ if (containerSelector) {
220
+ tabNav.items = Array.from(document.querySelectorAll(containerSelector));
221
+ }
222
+ }
223
+
224
+ /**
225
+ * Select card by index for specified tab
226
+ * @param {string} tabName - Tab name
227
+ * @param {number} index - Index of item to select
228
+ */
229
+ selectCardByIndex(tabName, index) {
230
+ const tabNav = this.tabNavigation[tabName];
231
+ if (!tabNav || index < 0 || index >= tabNav.items.length) return;
232
+
233
+ // Update navigation state
234
+ tabNav.selectedIndex = index;
235
+
236
+ // Update visual selection
237
+ this.updateUnifiedSelectionUI();
238
+
239
+ // If this is a different tab selection, record the card selection
240
+ const selectedElement = tabNav.items[index];
241
+ if (selectedElement) {
242
+ // Extract data from the element to populate selectedCard
243
+ this.selectCard(tabName, index, this.getCardType(tabName), index);
244
+ }
245
+
246
+ // Show details for the selected item
247
+ this.showCardDetails(tabName, index);
248
+ }
249
+
250
+ /**
251
+ * Update visual selection UI for unified navigation
252
+ */
253
+ updateUnifiedSelectionUI() {
254
+ // Clear all existing selections
255
+ document.querySelectorAll('.event-item.keyboard-selected').forEach(el => {
256
+ el.classList.remove('keyboard-selected');
257
+ });
258
+
259
+ // Apply selection to current tab's selected item
260
+ const tabNav = this.tabNavigation[this.currentTab];
261
+ if (tabNav && tabNav.selectedIndex !== -1 && tabNav.items[tabNav.selectedIndex]) {
262
+ tabNav.items[tabNav.selectedIndex].classList.add('keyboard-selected');
263
+ }
264
+ }
265
+
266
+ /**
267
+ * Show card details for specified tab and index
268
+ * @param {string} tabName - Tab name
269
+ * @param {number} index - Item index
270
+ */
271
+ showCardDetails(tabName, index) {
272
+ // Dispatch event for other modules to handle
273
+ document.dispatchEvent(new CustomEvent('showCardDetails', {
274
+ detail: {
275
+ tabName: tabName,
276
+ index: index
277
+ }
278
+ }));
279
+ }
280
+
281
+ /**
282
+ * Select a specific card
283
+ * @param {string} tabName - Tab name
284
+ * @param {number} index - Item index
285
+ * @param {string} type - Item type
286
+ * @param {*} data - Item data
287
+ */
288
+ selectCard(tabName, index, type, data) {
289
+ // Clear previous selection
290
+ this.clearCardSelection();
291
+
292
+ // Update selection state
293
+ this.selectedCard = {
294
+ tab: tabName,
295
+ index: index,
296
+ type: type,
297
+ data: data
298
+ };
299
+
300
+ this.updateCardSelectionUI();
301
+
302
+ console.log('Card selected:', this.selectedCard);
303
+ }
304
+
305
+ /**
306
+ * Clear card selection
307
+ */
308
+ clearCardSelection() {
309
+ // Clear visual selection from all tabs
310
+ document.querySelectorAll('.event-item.selected, .file-item.selected').forEach(el => {
311
+ el.classList.remove('selected');
312
+ });
313
+
314
+ // Reset selection state
315
+ this.selectedCard = {
316
+ tab: null,
317
+ index: null,
318
+ type: null,
319
+ data: null
320
+ };
321
+ }
322
+
323
+ /**
324
+ * Update card selection UI
325
+ */
326
+ updateCardSelectionUI() {
327
+ if (!this.selectedCard.tab || this.selectedCard.index === null) return;
328
+
329
+ // Get the list container for the selected tab
330
+ let listContainer;
331
+ switch (this.selectedCard.tab) {
332
+ case 'events':
333
+ listContainer = document.getElementById('events-list');
334
+ break;
335
+ case 'agents':
336
+ listContainer = document.getElementById('agents-list');
337
+ break;
338
+ case 'tools':
339
+ listContainer = document.getElementById('tools-list');
340
+ break;
341
+ case 'files':
342
+ listContainer = document.getElementById('files-list');
343
+ break;
344
+ }
345
+
346
+ if (listContainer) {
347
+ const items = listContainer.querySelectorAll('.event-item, .file-item');
348
+ if (items[this.selectedCard.index]) {
349
+ items[this.selectedCard.index].classList.add('selected');
350
+ }
351
+ }
352
+ }
353
+
354
+ /**
355
+ * Get card type based on tab name
356
+ * @param {string} tabName - Tab name
357
+ * @returns {string} - Card type
358
+ */
359
+ getCardType(tabName) {
360
+ switch (tabName) {
361
+ case 'events': return 'event';
362
+ case 'agents': return 'agent';
363
+ case 'tools': return 'tool';
364
+ case 'files': return 'file';
365
+ default: return 'unknown';
366
+ }
367
+ }
368
+
369
+ /**
370
+ * Scroll current tab to bottom
371
+ */
372
+ scrollCurrentTabToBottom() {
373
+ const tabId = `${this.currentTab}-list`;
374
+ const element = document.getElementById(tabId);
375
+ if (element && this.autoScroll) {
376
+ element.scrollTop = element.scrollHeight;
377
+ }
378
+ }
379
+
380
+ /**
381
+ * Clear selection for cleanup
382
+ */
383
+ clearSelection() {
384
+ this.clearCardSelection();
385
+ this.clearUnifiedSelection();
386
+ }
387
+
388
+ /**
389
+ * Get current tab name
390
+ * @returns {string} - Current tab name
391
+ */
392
+ getCurrentTab() {
393
+ return this.currentTab;
394
+ }
395
+
396
+ /**
397
+ * Get selected card info
398
+ * @returns {Object} - Selected card state
399
+ */
400
+ getSelectedCard() {
401
+ return { ...this.selectedCard };
402
+ }
403
+
404
+ /**
405
+ * Get tab navigation state
406
+ * @returns {Object} - Tab navigation state
407
+ */
408
+ getTabNavigation() {
409
+ return { ...this.tabNavigation };
410
+ }
411
+
412
+ /**
413
+ * Set auto-scroll behavior
414
+ * @param {boolean} enabled - Whether to enable auto-scroll
415
+ */
416
+ setAutoScroll(enabled) {
417
+ this.autoScroll = enabled;
418
+ }
419
+
420
+ /**
421
+ * Get auto-scroll state
422
+ * @returns {boolean} - Auto-scroll enabled state
423
+ */
424
+ getAutoScroll() {
425
+ return this.autoScroll;
426
+ }
427
+ }