claude-mpm 4.1.8__py3-none-any.whl → 4.1.11__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 (111) hide show
  1. claude_mpm/VERSION +1 -1
  2. claude_mpm/agents/INSTRUCTIONS.md +26 -1
  3. claude_mpm/agents/agents_metadata.py +57 -0
  4. claude_mpm/agents/templates/.claude-mpm/memories/README.md +17 -0
  5. claude_mpm/agents/templates/.claude-mpm/memories/engineer_memories.md +3 -0
  6. claude_mpm/agents/templates/agent-manager.json +263 -17
  7. claude_mpm/agents/templates/agentic_coder_optimizer.json +222 -0
  8. claude_mpm/agents/templates/code_analyzer.json +18 -8
  9. claude_mpm/agents/templates/engineer.json +1 -1
  10. claude_mpm/agents/templates/logs/prompts/agent_engineer_20250826_014258_728.md +39 -0
  11. claude_mpm/agents/templates/qa.json +1 -1
  12. claude_mpm/agents/templates/research.json +1 -1
  13. claude_mpm/cli/__init__.py +15 -0
  14. claude_mpm/cli/commands/__init__.py +6 -0
  15. claude_mpm/cli/commands/analyze.py +548 -0
  16. claude_mpm/cli/commands/analyze_code.py +524 -0
  17. claude_mpm/cli/commands/configure.py +78 -28
  18. claude_mpm/cli/commands/configure_tui.py +62 -60
  19. claude_mpm/cli/commands/dashboard.py +288 -0
  20. claude_mpm/cli/commands/debug.py +1386 -0
  21. claude_mpm/cli/commands/mpm_init.py +427 -0
  22. claude_mpm/cli/commands/mpm_init_handler.py +83 -0
  23. claude_mpm/cli/parsers/analyze_code_parser.py +170 -0
  24. claude_mpm/cli/parsers/analyze_parser.py +135 -0
  25. claude_mpm/cli/parsers/base_parser.py +44 -0
  26. claude_mpm/cli/parsers/dashboard_parser.py +113 -0
  27. claude_mpm/cli/parsers/debug_parser.py +319 -0
  28. claude_mpm/cli/parsers/mpm_init_parser.py +122 -0
  29. claude_mpm/constants.py +13 -1
  30. claude_mpm/core/framework_loader.py +148 -6
  31. claude_mpm/core/log_manager.py +16 -13
  32. claude_mpm/core/logger.py +1 -1
  33. claude_mpm/core/unified_agent_registry.py +1 -1
  34. claude_mpm/dashboard/.claude-mpm/socketio-instances.json +1 -0
  35. claude_mpm/dashboard/analysis_runner.py +455 -0
  36. claude_mpm/dashboard/static/built/components/activity-tree.js +2 -0
  37. claude_mpm/dashboard/static/built/components/agent-inference.js +1 -1
  38. claude_mpm/dashboard/static/built/components/code-tree.js +2 -0
  39. claude_mpm/dashboard/static/built/components/code-viewer.js +2 -0
  40. claude_mpm/dashboard/static/built/components/event-viewer.js +1 -1
  41. claude_mpm/dashboard/static/built/components/file-tool-tracker.js +1 -1
  42. claude_mpm/dashboard/static/built/components/module-viewer.js +1 -1
  43. claude_mpm/dashboard/static/built/components/session-manager.js +1 -1
  44. claude_mpm/dashboard/static/built/components/working-directory.js +1 -1
  45. claude_mpm/dashboard/static/built/dashboard.js +1 -1
  46. claude_mpm/dashboard/static/built/socket-client.js +1 -1
  47. claude_mpm/dashboard/static/css/activity.css +549 -0
  48. claude_mpm/dashboard/static/css/code-tree.css +1175 -0
  49. claude_mpm/dashboard/static/css/dashboard.css +245 -0
  50. claude_mpm/dashboard/static/dist/components/activity-tree.js +2 -0
  51. claude_mpm/dashboard/static/dist/components/code-tree.js +2 -0
  52. claude_mpm/dashboard/static/dist/components/code-viewer.js +2 -0
  53. claude_mpm/dashboard/static/dist/components/event-viewer.js +1 -1
  54. claude_mpm/dashboard/static/dist/components/session-manager.js +1 -1
  55. claude_mpm/dashboard/static/dist/components/working-directory.js +1 -1
  56. claude_mpm/dashboard/static/dist/dashboard.js +1 -1
  57. claude_mpm/dashboard/static/dist/socket-client.js +1 -1
  58. claude_mpm/dashboard/static/js/components/activity-tree.js +1338 -0
  59. claude_mpm/dashboard/static/js/components/code-tree.js +2535 -0
  60. claude_mpm/dashboard/static/js/components/code-viewer.js +480 -0
  61. claude_mpm/dashboard/static/js/components/event-viewer.js +59 -9
  62. claude_mpm/dashboard/static/js/components/session-manager.js +40 -4
  63. claude_mpm/dashboard/static/js/components/socket-manager.js +12 -0
  64. claude_mpm/dashboard/static/js/components/ui-state-manager.js +4 -0
  65. claude_mpm/dashboard/static/js/components/working-directory.js +17 -1
  66. claude_mpm/dashboard/static/js/dashboard.js +51 -0
  67. claude_mpm/dashboard/static/js/socket-client.js +465 -29
  68. claude_mpm/dashboard/templates/index.html +182 -4
  69. claude_mpm/hooks/claude_hooks/hook_handler.py +182 -5
  70. claude_mpm/hooks/claude_hooks/installer.py +386 -113
  71. claude_mpm/scripts/claude-hook-handler.sh +161 -0
  72. claude_mpm/scripts/socketio_daemon.py +121 -8
  73. claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +2 -2
  74. claude_mpm/services/agents/deployment/agent_record_service.py +1 -2
  75. claude_mpm/services/agents/memory/memory_format_service.py +1 -3
  76. claude_mpm/services/cli/agent_cleanup_service.py +1 -5
  77. claude_mpm/services/cli/agent_dependency_service.py +1 -1
  78. claude_mpm/services/cli/agent_validation_service.py +3 -4
  79. claude_mpm/services/cli/dashboard_launcher.py +2 -3
  80. claude_mpm/services/cli/startup_checker.py +0 -11
  81. claude_mpm/services/core/cache_manager.py +1 -3
  82. claude_mpm/services/core/path_resolver.py +1 -4
  83. claude_mpm/services/core/service_container.py +2 -2
  84. claude_mpm/services/diagnostics/checks/instructions_check.py +1 -2
  85. claude_mpm/services/infrastructure/monitoring/__init__.py +11 -11
  86. claude_mpm/services/infrastructure/monitoring.py +11 -11
  87. claude_mpm/services/project/architecture_analyzer.py +1 -1
  88. claude_mpm/services/project/dependency_analyzer.py +4 -4
  89. claude_mpm/services/project/language_analyzer.py +3 -3
  90. claude_mpm/services/project/metrics_collector.py +3 -6
  91. claude_mpm/services/socketio/event_normalizer.py +64 -0
  92. claude_mpm/services/socketio/handlers/__init__.py +2 -0
  93. claude_mpm/services/socketio/handlers/code_analysis.py +672 -0
  94. claude_mpm/services/socketio/handlers/registry.py +2 -0
  95. claude_mpm/services/socketio/server/connection_manager.py +6 -4
  96. claude_mpm/services/socketio/server/core.py +100 -11
  97. claude_mpm/services/socketio/server/main.py +8 -2
  98. claude_mpm/services/visualization/__init__.py +19 -0
  99. claude_mpm/services/visualization/mermaid_generator.py +938 -0
  100. claude_mpm/tools/__main__.py +208 -0
  101. claude_mpm/tools/code_tree_analyzer.py +1596 -0
  102. claude_mpm/tools/code_tree_builder.py +631 -0
  103. claude_mpm/tools/code_tree_events.py +416 -0
  104. claude_mpm/tools/socketio_debug.py +671 -0
  105. {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/METADATA +2 -1
  106. {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/RECORD +110 -74
  107. claude_mpm/agents/schema/agent_schema.json +0 -314
  108. {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/WHEEL +0 -0
  109. {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/entry_points.txt +0 -0
  110. {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/licenses/LICENSE +0 -0
  111. {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.11.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,480 @@
1
+ /**
2
+ * Code Viewer Component
3
+ *
4
+ * Modal window for displaying source code with syntax highlighting.
5
+ * Supports navigation between parent/child nodes and shows code metrics.
6
+ */
7
+
8
+ class CodeViewer {
9
+ constructor() {
10
+ this.modal = null;
11
+ this.currentNode = null;
12
+ this.socket = null;
13
+ this.initialized = false;
14
+ this.codeCache = new Map();
15
+ }
16
+
17
+ /**
18
+ * Initialize the code viewer
19
+ */
20
+ initialize() {
21
+ if (this.initialized) {
22
+ return;
23
+ }
24
+
25
+ this.createModal();
26
+ this.setupEventHandlers();
27
+ this.subscribeToEvents();
28
+
29
+ this.initialized = true;
30
+ console.log('Code viewer initialized');
31
+ }
32
+
33
+ /**
34
+ * Create modal DOM structure
35
+ */
36
+ createModal() {
37
+ const modalHtml = `
38
+ <div class="code-viewer-modal" id="code-viewer-modal">
39
+ <div class="code-viewer-content">
40
+ <div class="code-viewer-header">
41
+ <div class="code-viewer-title" id="code-viewer-title">
42
+ Loading...
43
+ </div>
44
+ <div class="code-viewer-info">
45
+ <span id="code-viewer-type">Type: --</span>
46
+ <span id="code-viewer-lines">Lines: --</span>
47
+ <span id="code-viewer-complexity">Complexity: --</span>
48
+ </div>
49
+ <button class="code-viewer-close" id="code-viewer-close">×</button>
50
+ </div>
51
+ <div class="code-viewer-body">
52
+ <pre class="code-viewer-code line-numbers" id="code-viewer-code">
53
+ <code class="language-python" id="code-viewer-code-content"></code>
54
+ </pre>
55
+ </div>
56
+ <div class="code-viewer-navigation">
57
+ <div class="nav-group">
58
+ <button class="code-nav-button" id="code-nav-parent" disabled>
59
+ ⬆️ Parent
60
+ </button>
61
+ <button class="code-nav-button" id="code-nav-prev" disabled>
62
+ ⬅️ Previous
63
+ </button>
64
+ <button class="code-nav-button" id="code-nav-next" disabled>
65
+ ➡️ Next
66
+ </button>
67
+ </div>
68
+ <div class="nav-info">
69
+ <span id="code-nav-position">-- / --</span>
70
+ </div>
71
+ <div class="nav-actions">
72
+ <button class="code-nav-button" id="code-copy">
73
+ 📋 Copy
74
+ </button>
75
+ <button class="code-nav-button" id="code-open-file">
76
+ 📂 Open File
77
+ </button>
78
+ </div>
79
+ </div>
80
+ </div>
81
+ </div>
82
+ `;
83
+
84
+ // Add modal to body
85
+ document.body.insertAdjacentHTML('beforeend', modalHtml);
86
+ this.modal = document.getElementById('code-viewer-modal');
87
+ }
88
+
89
+ /**
90
+ * Setup event handlers
91
+ */
92
+ setupEventHandlers() {
93
+ // Close button
94
+ document.getElementById('code-viewer-close').addEventListener('click', () => {
95
+ this.hide();
96
+ });
97
+
98
+ // Close on backdrop click
99
+ this.modal.addEventListener('click', (e) => {
100
+ if (e.target === this.modal) {
101
+ this.hide();
102
+ }
103
+ });
104
+
105
+ // Close on ESC key
106
+ document.addEventListener('keydown', (e) => {
107
+ if (e.key === 'Escape' && this.modal.classList.contains('show')) {
108
+ this.hide();
109
+ }
110
+ });
111
+
112
+ // Navigation buttons
113
+ document.getElementById('code-nav-parent').addEventListener('click', () => {
114
+ this.navigateToParent();
115
+ });
116
+
117
+ document.getElementById('code-nav-prev').addEventListener('click', () => {
118
+ this.navigateToPrevious();
119
+ });
120
+
121
+ document.getElementById('code-nav-next').addEventListener('click', () => {
122
+ this.navigateToNext();
123
+ });
124
+
125
+ // Action buttons
126
+ document.getElementById('code-copy').addEventListener('click', () => {
127
+ this.copyCode();
128
+ });
129
+
130
+ document.getElementById('code-open-file').addEventListener('click', () => {
131
+ this.openInEditor();
132
+ });
133
+ }
134
+
135
+ /**
136
+ * Subscribe to Socket.IO events
137
+ */
138
+ subscribeToEvents() {
139
+ if (window.socket) {
140
+ this.socket = window.socket;
141
+
142
+ // Listen for code content responses
143
+ this.socket.on('code:content:response', (data) => {
144
+ this.handleCodeContent(data);
145
+ });
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Show the code viewer with node data
151
+ */
152
+ show(nodeData) {
153
+ if (!this.initialized) {
154
+ this.initialize();
155
+ }
156
+
157
+ this.currentNode = nodeData;
158
+ this.modal.classList.add('show');
159
+
160
+ // Update header
161
+ this.updateHeader(nodeData);
162
+
163
+ // Load code content
164
+ this.loadCode(nodeData);
165
+
166
+ // Update navigation
167
+ this.updateNavigation(nodeData);
168
+ }
169
+
170
+ /**
171
+ * Hide the code viewer
172
+ */
173
+ hide() {
174
+ this.modal.classList.remove('show');
175
+ this.currentNode = null;
176
+ }
177
+
178
+ /**
179
+ * Update modal header
180
+ */
181
+ updateHeader(nodeData) {
182
+ // Update title
183
+ const title = document.getElementById('code-viewer-title');
184
+ title.textContent = `${nodeData.name} (${nodeData.path || 'Unknown'})`;
185
+
186
+ // Update info
187
+ document.getElementById('code-viewer-type').textContent = `Type: ${nodeData.type}`;
188
+ document.getElementById('code-viewer-lines').textContent = `Lines: ${nodeData.lines || '--'}`;
189
+ document.getElementById('code-viewer-complexity').textContent = `Complexity: ${nodeData.complexity || '--'}`;
190
+ }
191
+
192
+ /**
193
+ * Load code content
194
+ */
195
+ loadCode(nodeData) {
196
+ const codeContent = document.getElementById('code-viewer-code-content');
197
+
198
+ // Check cache first
199
+ const cacheKey = `${nodeData.path}:${nodeData.line}`;
200
+ if (this.codeCache.has(cacheKey)) {
201
+ this.displayCode(this.codeCache.get(cacheKey));
202
+ return;
203
+ }
204
+
205
+ // Show loading state
206
+ codeContent.textContent = 'Loading code...';
207
+
208
+ // Request code from server
209
+ if (this.socket) {
210
+ this.socket.emit('code:content:request', {
211
+ path: nodeData.path,
212
+ line: nodeData.line,
213
+ type: nodeData.type,
214
+ name: nodeData.name
215
+ });
216
+ } else {
217
+ // Fallback: show mock code for demo
218
+ this.displayMockCode(nodeData);
219
+ }
220
+ }
221
+
222
+ /**
223
+ * Handle code content response
224
+ */
225
+ handleCodeContent(data) {
226
+ if (!data.success) {
227
+ this.displayError(data.error || 'Failed to load code');
228
+ return;
229
+ }
230
+
231
+ // Cache the content
232
+ const cacheKey = `${data.path}:${data.line}`;
233
+ this.codeCache.set(cacheKey, data.content);
234
+
235
+ // Display the code
236
+ this.displayCode(data.content);
237
+ }
238
+
239
+ /**
240
+ * Display code with syntax highlighting
241
+ */
242
+ displayCode(code) {
243
+ const codeContent = document.getElementById('code-viewer-code-content');
244
+ const codeElement = document.getElementById('code-viewer-code');
245
+
246
+ // Set the code content
247
+ codeContent.textContent = code;
248
+
249
+ // Update language class based on file extension
250
+ const language = this.detectLanguage(this.currentNode.path);
251
+ codeContent.className = `language-${language}`;
252
+
253
+ // Apply Prism syntax highlighting
254
+ if (window.Prism) {
255
+ Prism.highlightElement(codeContent);
256
+
257
+ // Add line numbers if plugin is available
258
+ if (Prism.plugins && Prism.plugins.lineNumbers) {
259
+ Prism.plugins.lineNumbers.resize(codeElement);
260
+ }
261
+ }
262
+ }
263
+
264
+ /**
265
+ * Display mock code for demo purposes
266
+ */
267
+ displayMockCode(nodeData) {
268
+ let mockCode = '';
269
+
270
+ switch (nodeData.type) {
271
+ case 'class':
272
+ mockCode = `class ${nodeData.name}:
273
+ """
274
+ ${nodeData.docstring || 'A sample class implementation.'}
275
+ """
276
+
277
+ def __init__(self):
278
+ """Initialize the ${nodeData.name} class."""
279
+ self._data = {}
280
+ self._initialized = False
281
+
282
+ def process(self, input_data):
283
+ """Process the input data."""
284
+ if not self._initialized:
285
+ self._initialize()
286
+ return self._transform(input_data)
287
+
288
+ def _initialize(self):
289
+ """Initialize internal state."""
290
+ self._initialized = True
291
+
292
+ def _transform(self, data):
293
+ """Transform the data."""
294
+ return data`;
295
+ break;
296
+
297
+ case 'function':
298
+ mockCode = `def ${nodeData.name}(${nodeData.params ? nodeData.params.join(', ') : ''}):
299
+ """
300
+ ${nodeData.docstring || 'A sample function implementation.'}
301
+
302
+ Args:
303
+ ${nodeData.params ? nodeData.params.map(p => `${p}: Description of ${p}`).join('\n ') : 'None'}
304
+
305
+ Returns:
306
+ ${nodeData.returns || 'None'}: Return value description
307
+ """
308
+ # Implementation here
309
+ result = None
310
+
311
+ # Process logic
312
+ for item in range(10):
313
+ result = process_item(item)
314
+
315
+ return result`;
316
+ break;
317
+
318
+ case 'method':
319
+ mockCode = ` def ${nodeData.name}(self${nodeData.params ? ', ' + nodeData.params.join(', ') : ''}):
320
+ """
321
+ ${nodeData.docstring || 'A sample method implementation.'}
322
+ """
323
+ # Method implementation
324
+ self._validate()
325
+ result = self._process()
326
+ return result`;
327
+ break;
328
+
329
+ default:
330
+ mockCode = `# ${nodeData.name}
331
+ # Type: ${nodeData.type}
332
+ # Path: ${nodeData.path || 'Unknown'}
333
+ # Line: ${nodeData.line || 'Unknown'}
334
+
335
+ # Code content would appear here
336
+ # This is a placeholder for demonstration purposes`;
337
+ }
338
+
339
+ this.displayCode(mockCode);
340
+ }
341
+
342
+ /**
343
+ * Display error message
344
+ */
345
+ displayError(message) {
346
+ const codeContent = document.getElementById('code-viewer-code-content');
347
+ codeContent.textContent = `# Error loading code\n# ${message}`;
348
+ codeContent.className = 'language-python';
349
+ }
350
+
351
+ /**
352
+ * Detect language from file path
353
+ */
354
+ detectLanguage(path) {
355
+ if (!path) return 'python';
356
+
357
+ const ext = path.split('.').pop().toLowerCase();
358
+ const languageMap = {
359
+ 'py': 'python',
360
+ 'js': 'javascript',
361
+ 'ts': 'typescript',
362
+ 'jsx': 'jsx',
363
+ 'tsx': 'tsx',
364
+ 'css': 'css',
365
+ 'html': 'html',
366
+ 'json': 'json',
367
+ 'yaml': 'yaml',
368
+ 'yml': 'yaml',
369
+ 'md': 'markdown',
370
+ 'sh': 'bash',
371
+ 'bash': 'bash',
372
+ 'sql': 'sql',
373
+ 'go': 'go',
374
+ 'rs': 'rust',
375
+ 'cpp': 'cpp',
376
+ 'c': 'c',
377
+ 'h': 'c',
378
+ 'hpp': 'cpp',
379
+ 'java': 'java',
380
+ 'rb': 'ruby',
381
+ 'php': 'php'
382
+ };
383
+
384
+ return languageMap[ext] || 'plaintext';
385
+ }
386
+
387
+ /**
388
+ * Update navigation buttons
389
+ */
390
+ updateNavigation(nodeData) {
391
+ // For now, disable navigation buttons
392
+ // In a real implementation, these would navigate through the AST
393
+ document.getElementById('code-nav-parent').disabled = true;
394
+ document.getElementById('code-nav-prev').disabled = true;
395
+ document.getElementById('code-nav-next').disabled = true;
396
+ document.getElementById('code-nav-position').textContent = '1 / 1';
397
+ }
398
+
399
+ /**
400
+ * Navigate to parent node
401
+ */
402
+ navigateToParent() {
403
+ console.log('Navigate to parent node');
404
+ // Implementation would load parent node's code
405
+ }
406
+
407
+ /**
408
+ * Navigate to previous sibling
409
+ */
410
+ navigateToPrevious() {
411
+ console.log('Navigate to previous sibling');
412
+ // Implementation would load previous sibling's code
413
+ }
414
+
415
+ /**
416
+ * Navigate to next sibling
417
+ */
418
+ navigateToNext() {
419
+ console.log('Navigate to next sibling');
420
+ // Implementation would load next sibling's code
421
+ }
422
+
423
+ /**
424
+ * Copy code to clipboard
425
+ */
426
+ async copyCode() {
427
+ const codeContent = document.getElementById('code-viewer-code-content');
428
+ const code = codeContent.textContent;
429
+
430
+ try {
431
+ await navigator.clipboard.writeText(code);
432
+
433
+ // Show feedback
434
+ const button = document.getElementById('code-copy');
435
+ const originalText = button.textContent;
436
+ button.textContent = '✅ Copied!';
437
+ setTimeout(() => {
438
+ button.textContent = originalText;
439
+ }, 2000);
440
+ } catch (err) {
441
+ console.error('Failed to copy code:', err);
442
+ alert('Failed to copy code to clipboard');
443
+ }
444
+ }
445
+
446
+ /**
447
+ * Open file in editor
448
+ */
449
+ openInEditor() {
450
+ if (!this.currentNode || !this.currentNode.path) {
451
+ alert('File path not available');
452
+ return;
453
+ }
454
+
455
+ // Emit event to open file
456
+ if (this.socket) {
457
+ this.socket.emit('file:open', {
458
+ path: this.currentNode.path,
459
+ line: this.currentNode.line
460
+ });
461
+ }
462
+
463
+ console.log('Opening file in editor:', this.currentNode.path);
464
+ }
465
+ }
466
+
467
+ // Create singleton instance
468
+ const codeViewer = new CodeViewer();
469
+
470
+ // Export for use in other modules
471
+ if (typeof window !== 'undefined') {
472
+ window.CodeViewer = codeViewer;
473
+
474
+ // Initialize when DOM is ready
475
+ document.addEventListener('DOMContentLoaded', () => {
476
+ codeViewer.initialize();
477
+ });
478
+ }
479
+
480
+ export default codeViewer;
@@ -39,7 +39,6 @@ class EventViewer {
39
39
 
40
40
  // Subscribe to socket events
41
41
  this.socketClient.onEventUpdate((events, sessions) => {
42
- console.log('EventViewer received event update:', events?.length || 0, 'events');
43
42
  // Ensure we always have a valid events array
44
43
  this.events = Array.isArray(events) ? events : [];
45
44
  this.updateDisplay();
@@ -76,7 +75,6 @@ class EventViewer {
76
75
  setupKeyboardNavigation() {
77
76
  // Keyboard navigation is now handled by Dashboard.setupUnifiedKeyboardNavigation()
78
77
  // This method is kept for backward compatibility but does nothing
79
- console.log('EventViewer: Keyboard navigation handled by unified Dashboard system');
80
78
  }
81
79
 
82
80
  /**
@@ -110,7 +108,10 @@ class EventViewer {
110
108
  }
111
109
 
112
110
  this.filteredEvents = this.events.filter(event => {
113
- // Search filter
111
+ // NO AUTOMATIC FILTERING - All events are shown by default for complete visibility
112
+ // Users can apply their own filters using the search and type filter controls
113
+
114
+ // User-controlled search filter
114
115
  if (this.searchFilter) {
115
116
  const searchableText = [
116
117
  event.type || '',
@@ -123,7 +124,7 @@ class EventViewer {
123
124
  }
124
125
  }
125
126
 
126
- // Type filter - now handles full hook types (like "hook.user_prompt") and main types
127
+ // User-controlled type filter - handles full hook types (like "hook.user_prompt") and main types
127
128
  if (this.typeFilter) {
128
129
  // Use the same logic as formatEventType to get the full event type
129
130
  const eventType = event.type && event.type.trim() !== '' ? event.type : '';
@@ -133,13 +134,14 @@ class EventViewer {
133
134
  }
134
135
  }
135
136
 
136
- // Session filter
137
+ // User-controlled session filter
137
138
  if (this.sessionFilter && this.sessionFilter !== '') {
138
139
  if (!event.data || event.data.session_id !== this.sessionFilter) {
139
140
  return false;
140
141
  }
141
142
  }
142
143
 
144
+ // Allow all events through unless filtered by user controls
143
145
  return true;
144
146
  });
145
147
 
@@ -211,7 +213,6 @@ class EventViewer {
211
213
  * Update the display with current events
212
214
  */
213
215
  updateDisplay() {
214
- console.log('EventViewer updating display with', this.events?.length || 0, 'events');
215
216
  this.updateEventTypeDropdown();
216
217
  this.applyFilters();
217
218
  }
@@ -223,6 +224,9 @@ class EventViewer {
223
224
  const eventsList = document.getElementById('events-list');
224
225
  if (!eventsList) return;
225
226
 
227
+ // Check if user is at bottom BEFORE rendering (for autoscroll decision)
228
+ const wasAtBottom = (eventsList.scrollTop + eventsList.clientHeight >= eventsList.scrollHeight - 10);
229
+
226
230
  if (this.filteredEvents.length === 0) {
227
231
  eventsList.innerHTML = `
228
232
  <div class="no-events">
@@ -270,9 +274,12 @@ class EventViewer {
270
274
  window.dashboard.tabNavigation.events.items = this.filteredEventElements;
271
275
  }
272
276
 
273
- // Auto-scroll to bottom if enabled
274
- if (this.autoScroll && this.filteredEvents.length > 0) {
275
- eventsList.scrollTop = eventsList.scrollHeight;
277
+ // Auto-scroll only if user was already at bottom before rendering
278
+ if (this.filteredEvents.length > 0 && wasAtBottom && this.autoScroll) {
279
+ // Use requestAnimationFrame to ensure DOM has updated
280
+ requestAnimationFrame(() => {
281
+ eventsList.scrollTop = eventsList.scrollHeight;
282
+ });
276
283
  }
277
284
  }
278
285
 
@@ -326,6 +333,8 @@ class EventViewer {
326
333
  return this.formatMemoryEvent(event);
327
334
  case 'log':
328
335
  return this.formatLogEvent(event);
336
+ case 'code':
337
+ return this.formatCodeEvent(event);
329
338
  default:
330
339
  return this.formatGenericEvent(event);
331
340
  }
@@ -469,6 +478,47 @@ class EventViewer {
469
478
  return `<strong>[${level.toUpperCase()}]</strong> ${truncated}`;
470
479
  }
471
480
 
481
+ /**
482
+ * Format code analysis event data
483
+ */
484
+ formatCodeEvent(event) {
485
+ const data = event.data || {};
486
+
487
+ // Handle different code event subtypes
488
+ if (event.subtype === 'progress') {
489
+ const message = data.message || 'Processing...';
490
+ const percentage = data.percentage;
491
+ if (percentage !== undefined) {
492
+ return `<strong>Progress:</strong> ${message} (${Math.round(percentage)}%)`;
493
+ }
494
+ return `<strong>Progress:</strong> ${message}`;
495
+ } else if (event.subtype === 'analysis:queued') {
496
+ return `<strong>Queued:</strong> Analysis for ${data.path || 'Unknown path'}`;
497
+ } else if (event.subtype === 'analysis:start') {
498
+ return `<strong>Started:</strong> Analyzing ${data.path || 'Unknown path'}`;
499
+ } else if (event.subtype === 'analysis:complete') {
500
+ const duration = data.duration ? ` (${data.duration.toFixed(2)}s)` : '';
501
+ return `<strong>Complete:</strong> Analysis finished${duration}`;
502
+ } else if (event.subtype === 'analysis:error') {
503
+ return `<strong>Error:</strong> ${data.message || 'Analysis failed'}`;
504
+ } else if (event.subtype === 'analysis:cancelled') {
505
+ return `<strong>Cancelled:</strong> Analysis stopped for ${data.path || 'Unknown path'}`;
506
+ } else if (event.subtype === 'file:start') {
507
+ return `<strong>File:</strong> Processing ${data.file || 'Unknown file'}`;
508
+ } else if (event.subtype === 'file:complete') {
509
+ const nodes = data.nodes_count !== undefined ? ` (${data.nodes_count} nodes)` : '';
510
+ return `<strong>File done:</strong> ${data.file || 'Unknown file'}${nodes}`;
511
+ } else if (event.subtype === 'node:found') {
512
+ return `<strong>Node:</strong> Found ${data.node_type || 'element'} "${data.name || 'unnamed'}"`;
513
+ } else if (event.subtype === 'error') {
514
+ return `<strong>Error:</strong> ${data.error || 'Unknown error'} in ${data.file || 'file'}`;
515
+ }
516
+
517
+ // Generic fallback for code events
518
+ const json = JSON.stringify(data);
519
+ return `<strong>Code:</strong> ${json.length > 100 ? json.substring(0, 100) + '...' : json}`;
520
+ }
521
+
472
522
  /**
473
523
  * Format generic event data
474
524
  */
@@ -65,6 +65,8 @@ class SessionManager {
65
65
  setupSocketListeners() {
66
66
  // Listen for socket event updates
67
67
  this.socketClient.onEventUpdate((events, sessions) => {
68
+ // Log the sessions data to debug
69
+ console.log('[SESSION-MANAGER] Received sessions update:', sessions);
68
70
  this.sessions = sessions;
69
71
  this.updateSessionSelect();
70
72
  // Update footer info when new events arrive
@@ -90,9 +92,28 @@ class SessionManager {
90
92
  // Store current selection
91
93
  const currentSelection = sessionSelect.value;
92
94
 
93
- // Clear existing options except default ones
95
+ // Get the default working directory from various sources
96
+ let defaultWorkingDir = '/Users/masa/Projects/claude-mpm';
97
+
98
+ // Try to get from working directory manager
99
+ if (window.dashboard && window.dashboard.workingDirectoryManager) {
100
+ defaultWorkingDir = window.dashboard.workingDirectoryManager.getDefaultWorkingDir();
101
+ } else {
102
+ // Fallback: Try to get from header display element
103
+ const headerWorkingDir = document.getElementById('working-dir-path');
104
+ if (headerWorkingDir?.textContent?.trim()) {
105
+ const headerPath = headerWorkingDir.textContent.trim();
106
+ if (headerPath !== 'Loading...' && headerPath !== 'Unknown') {
107
+ defaultWorkingDir = headerPath;
108
+ }
109
+ }
110
+ }
111
+
112
+ console.log('[SESSION-MANAGER] Using default working directory:', defaultWorkingDir);
113
+
114
+ // Update "All Sessions" option to show working directory
94
115
  sessionSelect.innerHTML = `
95
- <option value="">All Sessions</option>
116
+ <option value="">${defaultWorkingDir} | All Sessions</option>
96
117
  `;
97
118
 
98
119
  // Add sessions from the sessions map
@@ -108,8 +129,23 @@ class SessionManager {
108
129
  const startTime = new Date(session.startTime || session.last_activity).toLocaleString();
109
130
  const eventCount = session.eventCount || session.event_count || 0;
110
131
  const isActive = session.id === this.currentSessionId;
111
-
112
- option.textContent = `${session.id.substring(0, 8)}... (${eventCount} events, ${startTime})${isActive ? ' [ACTIVE]' : ''}`;
132
+
133
+ // Extract working directory from session or events
134
+ let workingDir = session.working_directory || session.workingDirectory || '';
135
+
136
+ // Log for debugging
137
+ console.log(`[SESSION-DROPDOWN] Session ${session.id.substring(0, 8)} working_directory:`, workingDir);
138
+
139
+ if (!workingDir) {
140
+ const sessionData = this.extractSessionInfoFromEvents(session.id);
141
+ workingDir = sessionData.workingDir || defaultWorkingDir;
142
+ console.log(`[SESSION-DROPDOWN] Extracted working directory from events:`, workingDir);
143
+ }
144
+
145
+ // Format display: working_directory | session_id...
146
+ const shortId = session.id.substring(0, 8);
147
+ const dirDisplay = workingDir || defaultWorkingDir;
148
+ option.textContent = `${dirDisplay} | ${shortId}...${isActive ? ' [ACTIVE]' : ''}`;
113
149
  sessionSelect.appendChild(option);
114
150
  });
115
151
  }