claude-mpm 4.1.8__py3-none-any.whl → 4.1.10__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 (103) 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 +4 -0
  14. claude_mpm/cli/commands/__init__.py +6 -0
  15. claude_mpm/cli/commands/analyze.py +547 -0
  16. claude_mpm/cli/commands/analyze_code.py +524 -0
  17. claude_mpm/cli/commands/configure.py +77 -28
  18. claude_mpm/cli/commands/configure_tui.py +60 -60
  19. claude_mpm/cli/commands/debug.py +1387 -0
  20. claude_mpm/cli/parsers/analyze_code_parser.py +170 -0
  21. claude_mpm/cli/parsers/analyze_parser.py +135 -0
  22. claude_mpm/cli/parsers/base_parser.py +29 -0
  23. claude_mpm/cli/parsers/debug_parser.py +319 -0
  24. claude_mpm/constants.py +3 -1
  25. claude_mpm/core/framework_loader.py +148 -6
  26. claude_mpm/core/log_manager.py +16 -13
  27. claude_mpm/core/logger.py +1 -1
  28. claude_mpm/core/unified_agent_registry.py +1 -1
  29. claude_mpm/dashboard/.claude-mpm/socketio-instances.json +1 -0
  30. claude_mpm/dashboard/analysis_runner.py +428 -0
  31. claude_mpm/dashboard/static/built/components/activity-tree.js +2 -0
  32. claude_mpm/dashboard/static/built/components/agent-inference.js +1 -1
  33. claude_mpm/dashboard/static/built/components/event-viewer.js +1 -1
  34. claude_mpm/dashboard/static/built/components/file-tool-tracker.js +1 -1
  35. claude_mpm/dashboard/static/built/components/module-viewer.js +1 -1
  36. claude_mpm/dashboard/static/built/components/session-manager.js +1 -1
  37. claude_mpm/dashboard/static/built/components/working-directory.js +1 -1
  38. claude_mpm/dashboard/static/built/dashboard.js +1 -1
  39. claude_mpm/dashboard/static/built/socket-client.js +1 -1
  40. claude_mpm/dashboard/static/css/activity.css +549 -0
  41. claude_mpm/dashboard/static/css/code-tree.css +846 -0
  42. claude_mpm/dashboard/static/css/dashboard.css +245 -0
  43. claude_mpm/dashboard/static/dist/components/activity-tree.js +2 -0
  44. claude_mpm/dashboard/static/dist/components/code-tree.js +2 -0
  45. claude_mpm/dashboard/static/dist/components/code-viewer.js +2 -0
  46. claude_mpm/dashboard/static/dist/components/event-viewer.js +1 -1
  47. claude_mpm/dashboard/static/dist/components/session-manager.js +1 -1
  48. claude_mpm/dashboard/static/dist/components/working-directory.js +1 -1
  49. claude_mpm/dashboard/static/dist/dashboard.js +1 -1
  50. claude_mpm/dashboard/static/dist/socket-client.js +1 -1
  51. claude_mpm/dashboard/static/js/components/activity-tree.js +1139 -0
  52. claude_mpm/dashboard/static/js/components/code-tree.js +1357 -0
  53. claude_mpm/dashboard/static/js/components/code-viewer.js +480 -0
  54. claude_mpm/dashboard/static/js/components/event-viewer.js +11 -0
  55. claude_mpm/dashboard/static/js/components/session-manager.js +40 -4
  56. claude_mpm/dashboard/static/js/components/socket-manager.js +12 -0
  57. claude_mpm/dashboard/static/js/components/ui-state-manager.js +4 -0
  58. claude_mpm/dashboard/static/js/components/working-directory.js +17 -1
  59. claude_mpm/dashboard/static/js/dashboard.js +39 -0
  60. claude_mpm/dashboard/static/js/socket-client.js +414 -20
  61. claude_mpm/dashboard/templates/index.html +184 -4
  62. claude_mpm/hooks/claude_hooks/hook_handler.py +182 -5
  63. claude_mpm/hooks/claude_hooks/installer.py +386 -113
  64. claude_mpm/scripts/claude-hook-handler.sh +161 -0
  65. claude_mpm/scripts/socketio_daemon.py +121 -8
  66. claude_mpm/services/agents/deployment/agent_lifecycle_manager_refactored.py +2 -2
  67. claude_mpm/services/agents/deployment/agent_record_service.py +1 -2
  68. claude_mpm/services/agents/memory/memory_format_service.py +1 -5
  69. claude_mpm/services/cli/agent_cleanup_service.py +1 -2
  70. claude_mpm/services/cli/agent_dependency_service.py +1 -1
  71. claude_mpm/services/cli/agent_validation_service.py +3 -4
  72. claude_mpm/services/cli/dashboard_launcher.py +2 -3
  73. claude_mpm/services/cli/startup_checker.py +0 -10
  74. claude_mpm/services/core/cache_manager.py +1 -2
  75. claude_mpm/services/core/path_resolver.py +1 -4
  76. claude_mpm/services/core/service_container.py +2 -2
  77. claude_mpm/services/diagnostics/checks/instructions_check.py +1 -2
  78. claude_mpm/services/infrastructure/monitoring/__init__.py +11 -11
  79. claude_mpm/services/infrastructure/monitoring.py +11 -11
  80. claude_mpm/services/project/architecture_analyzer.py +1 -1
  81. claude_mpm/services/project/dependency_analyzer.py +4 -4
  82. claude_mpm/services/project/language_analyzer.py +3 -3
  83. claude_mpm/services/project/metrics_collector.py +3 -6
  84. claude_mpm/services/socketio/handlers/__init__.py +2 -0
  85. claude_mpm/services/socketio/handlers/code_analysis.py +170 -0
  86. claude_mpm/services/socketio/handlers/registry.py +2 -0
  87. claude_mpm/services/socketio/server/connection_manager.py +4 -4
  88. claude_mpm/services/socketio/server/core.py +100 -11
  89. claude_mpm/services/socketio/server/main.py +8 -2
  90. claude_mpm/services/visualization/__init__.py +19 -0
  91. claude_mpm/services/visualization/mermaid_generator.py +938 -0
  92. claude_mpm/tools/__main__.py +208 -0
  93. claude_mpm/tools/code_tree_analyzer.py +778 -0
  94. claude_mpm/tools/code_tree_builder.py +632 -0
  95. claude_mpm/tools/code_tree_events.py +318 -0
  96. claude_mpm/tools/socketio_debug.py +671 -0
  97. {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.10.dist-info}/METADATA +1 -1
  98. {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.10.dist-info}/RECORD +102 -73
  99. claude_mpm/agents/schema/agent_schema.json +0 -314
  100. {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.10.dist-info}/WHEEL +0 -0
  101. {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.10.dist-info}/entry_points.txt +0 -0
  102. {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.10.dist-info}/licenses/LICENSE +0 -0
  103. {claude_mpm-4.1.8.dist-info → claude_mpm-4.1.10.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;
@@ -110,6 +110,17 @@ class EventViewer {
110
110
  }
111
111
 
112
112
  this.filteredEvents = this.events.filter(event => {
113
+ // Filter out info level log messages
114
+ if (event.type === 'log' && event.data && event.data.level === 'info') {
115
+ return false;
116
+ }
117
+
118
+ // Filter out code analysis events (they're shown in footer status bar)
119
+ if (event.type === 'code' ||
120
+ (event.type === 'unknown' && event.originalEventName && event.originalEventName.startsWith('code:'))) {
121
+ return false;
122
+ }
123
+
113
124
  // Search filter
114
125
  if (this.searchFilter) {
115
126
  const searchableText = [
@@ -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
  }
@@ -81,6 +81,10 @@ class SocketManager {
81
81
 
82
82
  // Set up git branch listener when connected
83
83
  if (type === 'connected' && this.socketClient && this.socketClient.socket) {
84
+ // Expose socket globally for components like CodeTree
85
+ window.socket = this.socketClient.socket;
86
+ console.log('SocketManager: Exposed socket globally as window.socket');
87
+
84
88
  this.setupGitBranchListener();
85
89
  }
86
90
  }
@@ -105,6 +109,9 @@ class SocketManager {
105
109
 
106
110
  if (this.socketClient.socket.connected) {
107
111
  console.log('SocketManager: Socket is already connected, updating status');
112
+ // Expose socket globally for components like CodeTree
113
+ window.socket = this.socketClient.socket;
114
+ console.log('SocketManager: Exposed socket globally as window.socket');
108
115
  this.updateConnectionStatus('Connected', 'connected');
109
116
  } else if (this.socketClient.isConnecting || this.socketClient.socket.connecting) {
110
117
  console.log('SocketManager: Socket is connecting, updating status');
@@ -123,6 +130,11 @@ class SocketManager {
123
130
  console.log('SocketManager: Secondary status check after 1 second');
124
131
  if (this.socketClient && this.socketClient.socket && this.socketClient.socket.connected) {
125
132
  console.log('SocketManager: Socket connected in secondary check, updating status');
133
+ // Expose socket globally if not already done
134
+ if (!window.socket) {
135
+ window.socket = this.socketClient.socket;
136
+ console.log('SocketManager: Exposed socket globally as window.socket (secondary check)');
137
+ }
126
138
  this.updateConnectionStatus('Connected', 'connected');
127
139
  }
128
140
  }, 1000);
@@ -92,9 +92,13 @@ class UIStateManager {
92
92
  getTabNameFromButton(button) {
93
93
  const text = button.textContent.toLowerCase();
94
94
  if (text.includes('events')) return 'events';
95
+ if (text.includes('activity')) return 'activity';
95
96
  if (text.includes('agents')) return 'agents';
96
97
  if (text.includes('tools')) return 'tools';
97
98
  if (text.includes('files')) return 'files';
99
+ if (text.includes('code')) return 'code';
100
+ if (text.includes('sessions')) return 'sessions';
101
+ if (text.includes('system')) return 'system';
98
102
  return 'events';
99
103
  }
100
104
 
@@ -310,8 +310,24 @@ class WorkingDirectoryManager {
310
310
  */
311
311
  getDefaultWorkingDir() {
312
312
  console.log('[WORKING-DIR-DEBUG] getDefaultWorkingDir called');
313
+
314
+ // Try to get from the current working directory if set
315
+ if (this.currentWorkingDir && this.validateDirectoryPath(this.currentWorkingDir)) {
316
+ console.log('[WORKING-DIR-DEBUG] Using current working directory:', this.currentWorkingDir);
317
+ return this.currentWorkingDir;
318
+ }
319
+
320
+ // Try to get from header display
321
+ const headerWorkingDir = document.querySelector('.working-dir-text');
322
+ if (headerWorkingDir?.textContent?.trim()) {
323
+ const headerPath = headerWorkingDir.textContent.trim();
324
+ if (headerPath !== 'Loading...' && headerPath !== 'Unknown' && this.validateDirectoryPath(headerPath)) {
325
+ console.log('[WORKING-DIR-DEBUG] Using header working directory:', headerPath);
326
+ return headerPath;
327
+ }
328
+ }
313
329
 
314
- // Try to get from footer first
330
+ // Try to get from footer
315
331
  const footerDir = document.getElementById('footer-working-dir');
316
332
  if (footerDir?.textContent?.trim()) {
317
333
  const footerPath = footerDir.textContent.trim();
@@ -372,6 +372,45 @@ class Dashboard {
372
372
  case 'events':
373
373
  // Events tab is handled by EventViewer
374
374
  break;
375
+ case 'activity':
376
+ // Trigger Activity tab rendering through the component
377
+ // Check if ActivityTree class is available (from built module)
378
+ if (window.ActivityTree && typeof window.ActivityTree === 'function') {
379
+ // Create or get instance
380
+ if (!window.activityTreeInstance) {
381
+ console.log('Creating new ActivityTree instance...');
382
+ window.activityTreeInstance = new window.ActivityTree();
383
+ }
384
+
385
+ // Initialize if needed and render
386
+ if (window.activityTreeInstance) {
387
+ if (!window.activityTreeInstance.initialized) {
388
+ console.log('Initializing ActivityTree...');
389
+ window.activityTreeInstance.initialize();
390
+ }
391
+
392
+ if (typeof window.activityTreeInstance.renderWhenVisible === 'function') {
393
+ console.log('Dashboard triggering activity tree render...');
394
+ window.activityTreeInstance.renderWhenVisible();
395
+ }
396
+ }
397
+ } else if (window.activityTree && typeof window.activityTree === 'function') {
398
+ // Fallback to legacy approach if available
399
+ const activityTreeInstance = window.activityTree();
400
+ if (activityTreeInstance && typeof activityTreeInstance.renderWhenVisible === 'function') {
401
+ console.log('Dashboard triggering activity tree render (legacy)...');
402
+ activityTreeInstance.renderWhenVisible();
403
+ }
404
+ } else {
405
+ // Module not loaded yet, retry after a delay
406
+ console.warn('Activity tree component not available, retrying in 100ms...');
407
+ setTimeout(() => {
408
+ if (this.currentTab === 'activity') {
409
+ this.renderCurrentTab();
410
+ }
411
+ }, 100);
412
+ }
413
+ break;
375
414
  case 'agents':
376
415
  this.renderAgents();
377
416
  break;