claude-mpm 4.2.44__py3-none-any.whl → 4.2.51__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_PM.md +43 -1
- claude_mpm/agents/INSTRUCTIONS.md +75 -1
- claude_mpm/agents/WORKFLOW.md +46 -1
- claude_mpm/agents/frontmatter_validator.py +20 -12
- claude_mpm/agents/templates/nextjs_engineer.json +277 -0
- claude_mpm/agents/templates/python_engineer.json +289 -0
- claude_mpm/agents/templates/react_engineer.json +11 -3
- claude_mpm/agents/templates/security.json +50 -9
- claude_mpm/cli/commands/agents.py +2 -2
- claude_mpm/cli/commands/uninstall.py +1 -2
- claude_mpm/cli/interactive/agent_wizard.py +3 -3
- claude_mpm/cli/parsers/agent_manager_parser.py +3 -3
- claude_mpm/cli/parsers/agents_parser.py +1 -1
- claude_mpm/constants.py +1 -1
- claude_mpm/core/error_handler.py +2 -4
- claude_mpm/core/file_utils.py +4 -12
- claude_mpm/core/log_manager.py +8 -5
- claude_mpm/core/logger.py +1 -1
- claude_mpm/core/logging_utils.py +6 -6
- claude_mpm/core/unified_agent_registry.py +18 -4
- claude_mpm/dashboard/react/components/DataInspector/DataInspector.module.css +188 -0
- claude_mpm/dashboard/react/components/EventViewer/EventViewer.module.css +156 -0
- claude_mpm/dashboard/react/components/shared/ConnectionStatus.module.css +38 -0
- claude_mpm/dashboard/react/components/shared/FilterBar.module.css +92 -0
- claude_mpm/dashboard/static/archive/activity_dashboard_fixed.html +248 -0
- claude_mpm/dashboard/static/archive/activity_dashboard_test.html +61 -0
- claude_mpm/dashboard/static/archive/test_activity_connection.html +179 -0
- claude_mpm/dashboard/static/archive/test_claude_tree_tab.html +68 -0
- claude_mpm/dashboard/static/archive/test_dashboard.html +409 -0
- claude_mpm/dashboard/static/archive/test_dashboard_fixed.html +519 -0
- claude_mpm/dashboard/static/archive/test_dashboard_verification.html +181 -0
- claude_mpm/dashboard/static/archive/test_file_data.html +315 -0
- claude_mpm/dashboard/static/archive/test_file_tree_empty_state.html +243 -0
- claude_mpm/dashboard/static/archive/test_file_tree_fix.html +234 -0
- claude_mpm/dashboard/static/archive/test_file_tree_rename.html +117 -0
- claude_mpm/dashboard/static/archive/test_file_tree_tab.html +115 -0
- claude_mpm/dashboard/static/archive/test_file_viewer.html +224 -0
- claude_mpm/dashboard/static/archive/test_final_activity.html +220 -0
- claude_mpm/dashboard/static/archive/test_tab_fix.html +139 -0
- claude_mpm/dashboard/static/built/assets/events.DjpNxWNo.css +1 -0
- claude_mpm/dashboard/static/built/components/activity-tree.js +1 -1
- claude_mpm/dashboard/static/built/components/agent-hierarchy.js +777 -0
- claude_mpm/dashboard/static/built/components/agent-inference.js +1 -1
- claude_mpm/dashboard/static/built/components/build-tracker.js +333 -0
- claude_mpm/dashboard/static/built/components/code-simple.js +857 -0
- claude_mpm/dashboard/static/built/components/code-tree/tree-breadcrumb.js +353 -0
- claude_mpm/dashboard/static/built/components/code-tree/tree-constants.js +235 -0
- claude_mpm/dashboard/static/built/components/code-tree/tree-search.js +409 -0
- claude_mpm/dashboard/static/built/components/code-tree/tree-utils.js +435 -0
- claude_mpm/dashboard/static/built/components/code-viewer.js +2 -1076
- claude_mpm/dashboard/static/built/components/connection-debug.js +654 -0
- claude_mpm/dashboard/static/built/components/diff-viewer.js +891 -0
- claude_mpm/dashboard/static/built/components/event-processor.js +1 -1
- claude_mpm/dashboard/static/built/components/event-viewer.js +1 -1
- claude_mpm/dashboard/static/built/components/export-manager.js +1 -1
- claude_mpm/dashboard/static/built/components/file-change-tracker.js +443 -0
- claude_mpm/dashboard/static/built/components/file-change-viewer.js +690 -0
- claude_mpm/dashboard/static/built/components/file-tool-tracker.js +1 -1
- claude_mpm/dashboard/static/built/components/module-viewer.js +1 -1
- claude_mpm/dashboard/static/built/components/nav-bar.js +145 -0
- claude_mpm/dashboard/static/built/components/page-structure.js +429 -0
- claude_mpm/dashboard/static/built/components/session-manager.js +1 -1
- claude_mpm/dashboard/static/built/components/ui-state-manager.js +2 -465
- claude_mpm/dashboard/static/built/components/working-directory.js +1 -1
- claude_mpm/dashboard/static/built/connection-manager.js +536 -0
- claude_mpm/dashboard/static/built/dashboard.js +1 -1
- claude_mpm/dashboard/static/built/extension-error-handler.js +164 -0
- claude_mpm/dashboard/static/built/react/events.js +30 -0
- claude_mpm/dashboard/static/built/shared/dom-helpers.js +396 -0
- claude_mpm/dashboard/static/built/shared/event-bus.js +330 -0
- claude_mpm/dashboard/static/built/shared/event-filter-service.js +540 -0
- claude_mpm/dashboard/static/built/shared/logger.js +385 -0
- claude_mpm/dashboard/static/built/shared/page-structure.js +251 -0
- claude_mpm/dashboard/static/built/shared/tooltip-service.js +253 -0
- claude_mpm/dashboard/static/built/socket-client.js +1 -1
- claude_mpm/dashboard/static/built/tab-isolation-fix.js +185 -0
- claude_mpm/dashboard/static/css/dashboard.css +28 -5
- claude_mpm/dashboard/static/dist/assets/events.DjpNxWNo.css +1 -0
- claude_mpm/dashboard/static/dist/components/activity-tree.js +1 -1
- claude_mpm/dashboard/static/dist/components/agent-inference.js +1 -1
- claude_mpm/dashboard/static/dist/components/code-viewer.js +2 -0
- claude_mpm/dashboard/static/dist/components/event-processor.js +1 -1
- claude_mpm/dashboard/static/dist/components/event-viewer.js +1 -1
- claude_mpm/dashboard/static/dist/components/export-manager.js +1 -1
- claude_mpm/dashboard/static/dist/components/file-tool-tracker.js +1 -1
- claude_mpm/dashboard/static/dist/components/module-viewer.js +1 -1
- claude_mpm/dashboard/static/dist/components/session-manager.js +1 -1
- claude_mpm/dashboard/static/dist/components/working-directory.js +1 -1
- claude_mpm/dashboard/static/dist/dashboard.js +1 -1
- claude_mpm/dashboard/static/dist/react/events.js +30 -0
- claude_mpm/dashboard/static/dist/socket-client.js +1 -1
- claude_mpm/dashboard/static/events.html +607 -0
- claude_mpm/dashboard/static/index.html +713 -0
- claude_mpm/dashboard/static/js/components/activity-tree.js +3 -17
- claude_mpm/dashboard/static/js/components/agent-hierarchy.js +4 -1
- claude_mpm/dashboard/static/js/components/agent-inference.js +3 -0
- claude_mpm/dashboard/static/js/components/build-tracker.js +8 -0
- claude_mpm/dashboard/static/js/components/code-viewer.js +306 -66
- claude_mpm/dashboard/static/js/components/event-processor.js +3 -0
- claude_mpm/dashboard/static/js/components/event-viewer.js +39 -2
- claude_mpm/dashboard/static/js/components/export-manager.js +3 -0
- claude_mpm/dashboard/static/js/components/file-tool-tracker.js +30 -10
- claude_mpm/dashboard/static/js/components/socket-manager.js +4 -0
- claude_mpm/dashboard/static/js/components/ui-state-manager.js +285 -85
- claude_mpm/dashboard/static/js/components/working-directory.js +3 -0
- claude_mpm/dashboard/static/js/dashboard.js +61 -33
- claude_mpm/dashboard/static/js/socket-client.js +12 -8
- claude_mpm/dashboard/static/js/stores/dashboard-store.js +562 -0
- claude_mpm/dashboard/static/js/tab-isolation-fix.js +185 -0
- claude_mpm/dashboard/static/legacy/activity.html +736 -0
- claude_mpm/dashboard/static/legacy/agents.html +786 -0
- claude_mpm/dashboard/static/legacy/files.html +747 -0
- claude_mpm/dashboard/static/legacy/tools.html +831 -0
- claude_mpm/dashboard/static/monitors-index.html +218 -0
- claude_mpm/dashboard/static/monitors.html +431 -0
- claude_mpm/dashboard/static/production/events.html +659 -0
- claude_mpm/dashboard/static/production/main.html +715 -0
- claude_mpm/dashboard/static/production/monitors.html +483 -0
- claude_mpm/dashboard/static/socket.io.min.js +7 -0
- claude_mpm/dashboard/static/socket.io.v4.8.1.backup.js +7 -0
- claude_mpm/dashboard/static/test-archive/dashboard.html +635 -0
- claude_mpm/dashboard/static/test-archive/debug-events.html +147 -0
- claude_mpm/dashboard/static/test-archive/test-navigation.html +256 -0
- claude_mpm/dashboard/static/test-archive/test-react-exports.html +180 -0
- claude_mpm/dashboard/templates/index.html +79 -9
- claude_mpm/hooks/claude_hooks/services/connection_manager_http.py +1 -1
- claude_mpm/services/agents/deployment/agent_discovery_service.py +3 -0
- claude_mpm/services/agents/deployment/agent_template_builder.py +25 -8
- claude_mpm/services/agents/deployment/agent_validator.py +3 -0
- claude_mpm/services/agents/deployment/validation/template_validator.py +13 -4
- claude_mpm/services/agents/local_template_manager.py +2 -6
- claude_mpm/services/monitor/daemon.py +1 -2
- claude_mpm/services/monitor/daemon_manager.py +2 -5
- claude_mpm/services/monitor/event_emitter.py +2 -2
- claude_mpm/services/monitor/handlers/code_analysis.py +4 -6
- claude_mpm/services/monitor/handlers/hooks.py +2 -4
- claude_mpm/services/monitor/server.py +27 -4
- claude_mpm/tools/code_tree_analyzer.py +2 -2
- {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/METADATA +1 -1
- {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/RECORD +146 -81
- claude_mpm/dashboard/static/test-browser-monitor.html +0 -470
- claude_mpm/dashboard/static/test-simple.html +0 -97
- /claude_mpm/dashboard/static/{test_debug.html → test-archive/test_debug.html} +0 -0
- {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/WHEEL +0 -0
- {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/entry_points.txt +0 -0
- {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/licenses/LICENSE +0 -0
- {claude_mpm-4.2.44.dist-info → claude_mpm-4.2.51.dist-info}/top_level.txt +0 -0
@@ -1,465 +1,2 @@
|
|
1
|
-
|
2
|
-
|
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;
|
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 +1,2 @@
|
|
1
|
-
class e{constructor(e){this.socketManager=e,this.currentWorkingDir=null,this.footerDirObserver=null,this._updatingFooter=!1,this.setupEventHandlers(),this.initialize(),console.log("Working directory manager initialized")}initialize(){this.initializeWorkingDirectory(),this.watchFooterDirectory()}setupEventHandlers(){const e=document.getElementById("change-dir-btn"),t=document.getElementById("working-dir-path");if(e&&e.addEventListener("click",()=>{this.showChangeDirDialog()}),t&&t.addEventListener("click",e=>{e.shiftKey?this.showChangeDirDialog():this.showWorkingDirectoryViewer()}),document.addEventListener("sessionChanged",e=>{const t=e.detail.sessionId;console.log("[WORKING-DIR-DEBUG] sessionChanged event received, sessionId:",this.repr(t)),t&&this.loadWorkingDirectoryForSession(t)}),this.socketManager&&this.socketManager.getSocket){const e=this.socketManager.getSocket();e&&(console.log("[WORKING-DIR-DEBUG] Setting up git_branch_response listener"),e.on("git_branch_response",e=>{console.log("[GIT-BRANCH-DEBUG] Received git_branch_response:",e),this.handleGitBranchResponse(e)}))}}initializeWorkingDirectory(){const e=document.getElementById("working-dir-path");e&&!e.textContent.trim()&&(e.textContent="Loading...");const t=document.getElementById("session-select");t&&t.value&&"all"!==t.value?this.loadWorkingDirectoryForSession(t.value):this.setWorkingDirectory(this.getDefaultWorkingDir())}watchFooterDirectory(){const e=document.getElementById("footer-working-dir");e&&(this.footerDirObserver=new MutationObserver(t=>{this._updatingFooter||t.forEach(t=>{if("childList"===t.type||"characterData"===t.type){const t=e.textContent.trim();console.log("Footer directory changed to:",t),t&&t!==this.currentWorkingDir&&(console.log("Syncing working directory from footer change"),this.setWorkingDirectory(t))}})}),this.footerDirObserver.observe(e,{childList:!0,characterData:!0,subtree:!0}),console.log("Started watching footer directory for changes"))}loadWorkingDirectoryForSession(e){if(console.log("[WORKING-DIR-DEBUG] loadWorkingDirectoryForSession called with sessionId:",this.repr(e)),!e||"all"===e){console.log('[WORKING-DIR-DEBUG] No sessionId or sessionId is "all", using default working dir');const e=this.getDefaultWorkingDir();return console.log("[WORKING-DIR-DEBUG] Default working dir:",this.repr(e)),void this.setWorkingDirectory(e)}const t=JSON.parse(localStorage.getItem("sessionWorkingDirs")||"{}");console.log("[WORKING-DIR-DEBUG] Session directories from localStorage:",t);const r=t[e],o=this.getDefaultWorkingDir(),i=r||o;console.log("[WORKING-DIR-DEBUG] Directory selection:",{sessionId:e,sessionDir:this.repr(r),defaultDir:this.repr(o),finalDir:this.repr(i)}),this.setWorkingDirectory(i)}setWorkingDirectory(e){console.log("[WORKING-DIR-DEBUG] setWorkingDirectory called with:",this.repr(e)),this.currentWorkingDir=e;const t=document.getElementById("working-dir-path");t?(console.log("[WORKING-DIR-DEBUG] Updating UI path element to:",e),t.textContent=e):console.warn("[WORKING-DIR-DEBUG] working-dir-path element not found");const r=document.getElementById("footer-working-dir");if(r){const t=r.textContent;console.log("[WORKING-DIR-DEBUG] Footer directory current text:",this.repr(t),"new text:",this.repr(e)),t!==e?(this._updatingFooter=!0,r.textContent=e,console.log("[WORKING-DIR-DEBUG] Updated footer directory to:",e),setTimeout(()=>{this._updatingFooter=!1,console.log("[WORKING-DIR-DEBUG] Cleared _updatingFooter flag")},100)):console.log("[WORKING-DIR-DEBUG] Footer directory already has correct text")}else console.warn("[WORKING-DIR-DEBUG] footer-working-dir element not found");const o=document.getElementById("session-select");if(o&&o.value&&"all"!==o.value){const t=o.value,r=JSON.parse(localStorage.getItem("sessionWorkingDirs")||"{}");r[t]=e,localStorage.setItem("sessionWorkingDirs",JSON.stringify(r)),console.log(`[WORKING-DIR-DEBUG] Saved working directory for session ${t}:`,e)}else console.log('[WORKING-DIR-DEBUG] No session selected or session is "all", not saving to localStorage');console.log("[WORKING-DIR-DEBUG] About to call updateGitBranch with:",this.repr(e)),this.validateDirectoryPath(e)?this.updateGitBranch(e):console.log("[WORKING-DIR-DEBUG] Skipping git branch update for invalid directory:",this.repr(e)),document.dispatchEvent(new CustomEvent("workingDirectoryChanged",{detail:{directory:e}})),console.log("[WORKING-DIR-DEBUG] Working directory set to:",e)}updateGitBranch(e){if(console.log("[GIT-BRANCH-DEBUG] updateGitBranch called with dir:",this.repr(e),"type:",typeof e),!this.socketManager||!this.socketManager.isConnected()){console.log("[GIT-BRANCH-DEBUG] Not connected to socket server");const e=document.getElementById("footer-git-branch");return void(e&&(e.textContent="Not Connected",e.style.display="inline"))}const t=this.validateDirectoryPath(e),r="Loading..."===e||"Loading"===e,o="Unknown"===e,i=!e||"string"==typeof e&&""===e.trim();if(console.log("[GIT-BRANCH-DEBUG] Validation results:",{dir:e,isValidPath:t,isLoadingState:r,isUnknown:o,isEmptyOrWhitespace:i,shouldReject:!t||r||o||i}),!t||r||o||i){console.warn("[GIT-BRANCH-DEBUG] Invalid working directory for git branch request:",e);const t=document.getElementById("footer-git-branch");return void(t&&(t.textContent=r?"Loading...":o||i?"No Directory":"Invalid Directory",t.style.display="inline"))}const n=this.socketManager.getSocket();n?(console.log("[GIT-BRANCH-DEBUG] Requesting git branch for directory:",e),console.log("[GIT-BRANCH-DEBUG] Socket state:",{connected:n.connected,id:n.id}),n.emit("get_git_branch",e)):console.error("[GIT-BRANCH-DEBUG] No socket available for git branch request")}getDefaultWorkingDir(){if(console.log("[WORKING-DIR-DEBUG] getDefaultWorkingDir called"),this.currentWorkingDir&&this.validateDirectoryPath(this.currentWorkingDir))return console.log("[WORKING-DIR-DEBUG] Using current working directory:",this.currentWorkingDir),this.currentWorkingDir;const e=document.querySelector(".working-dir-text");if(e?.textContent?.trim()){const t=e.textContent.trim();if("Loading..."!==t&&"Unknown"!==t&&this.validateDirectoryPath(t))return console.log("[WORKING-DIR-DEBUG] Using header working directory:",t),t}const t=document.getElementById("footer-working-dir");if(t?.textContent?.trim()){const e=t.textContent.trim();console.log("[WORKING-DIR-DEBUG] Footer path found:",this.repr(e));const r="Unknown"===e,o=this.validateDirectoryPath(e);if(console.log("[WORKING-DIR-DEBUG] Footer path validation:",{footerPath:this.repr(e),isUnknown:r,isValid:o,shouldUse:!r&&o}),!r&&o)return console.log("[WORKING-DIR-DEBUG] Using footer path as default:",e),e}else console.log("[WORKING-DIR-DEBUG] No footer directory element or no text content");if(window.socketClient&&window.socketClient.events){const e=window.socketClient.events.filter(e=>e.data&&(e.data.working_directory||e.data.cwd||e.data.working_dir)).reverse();if(e.length>0){const t=e[0],r=t.data.working_directory||t.data.cwd||t.data.working_dir;return console.log("[WORKING-DIR-DEBUG] Using working directory from recent event:",r),r}}const r=document.getElementById("working-dir-path");if(r?.textContent?.trim()){const e=r.textContent.trim();if(console.log("[WORKING-DIR-DEBUG] Found working-dir-path element text:",this.repr(e)),"Unknown"!==e&&this.validateDirectoryPath(e))return console.log("[WORKING-DIR-DEBUG] Using working-dir-path as fallback:",e),e}const o=(window.location.hostname,"/");return console.log("[WORKING-DIR-DEBUG] Using generic fallback directory:",this.repr(o)),o}showChangeDirDialog(){const e=prompt("Enter new working directory:",this.currentWorkingDir||"");e&&""!==e.trim()&&this.setWorkingDirectory(e.trim())}showWorkingDirectoryViewer(){this.createDirectoryViewerOverlay()}createDirectoryViewerOverlay(){this.removeDirectoryViewerOverlay();const e=document.querySelector(".working-dir-display");if(!e)return;const t=document.createElement("div");t.id="directory-viewer-overlay",t.className="directory-viewer-overlay",t.innerHTML=`\n <div class="directory-viewer-content">\n <div class="directory-viewer-header">\n <h3 class="directory-viewer-title">\n 📁 ${this.currentWorkingDir||"Working Directory"}\n </h3>\n <button class="close-btn" onclick="workingDirectoryManager.removeDirectoryViewerOverlay()">✕</button>\n </div>\n <div class="directory-viewer-body">\n <div class="loading-indicator">Loading directory contents...</div>\n </div>\n <div class="directory-viewer-footer">\n <span class="directory-hint">Click file to view • Shift+Click directory path to change</span>\n </div>\n </div>\n `;const r=e.getBoundingClientRect();t.style.cssText=`\n position: fixed;\n top: ${r.bottom+5}px;\n left: ${r.left}px;\n min-width: 400px;\n max-width: 600px;\n max-height: 400px;\n z-index: 1001;\n background: white;\n border-radius: 8px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);\n border: 1px solid #e2e8f0;\n `,document.body.appendChild(t),this.loadDirectoryContents(),setTimeout(()=>{document.addEventListener("click",this.handleOutsideClick.bind(this),!0)},100)}removeDirectoryViewerOverlay(){const e=document.getElementById("directory-viewer-overlay");e&&(e.remove(),document.removeEventListener("click",this.handleOutsideClick.bind(this),!0))}handleOutsideClick(e){const t=document.getElementById("directory-viewer-overlay"),r=document.getElementById("working-dir-path");t&&!t.contains(e.target)&&e.target!==r&&this.removeDirectoryViewerOverlay()}loadDirectoryContents(){if(!this.socketManager||!this.socketManager.isConnected())return void this.showDirectoryError("Not connected to server");const e=this.socketManager.getSocket();if(!e)return void this.showDirectoryError("No socket connection available");e.emit("get_directory_listing",{directory:this.currentWorkingDir,limit:50});const t=r=>{e.off("directory_listing_response",t),this.handleDirectoryListingResponse(r)};e.on("directory_listing_response",t),setTimeout(()=>{e.off("directory_listing_response",t);const r=document.getElementById("directory-viewer-overlay");r&&r.querySelector(".loading-indicator")&&this.showDirectoryError("Request timeout")},5e3)}handleDirectoryListingResponse(e){const t=document.querySelector(".directory-viewer-body");if(!t)return;if(!e.success)return void this.showDirectoryError(e.error||"Failed to load directory");const r=e.files||[],o=e.directories||[];let i="";if(this.currentWorkingDir&&"/"!==this.currentWorkingDir){const e=this.currentWorkingDir.split("/").slice(0,-1).join("/")||"/";i+=`\n <div class="file-item directory-item" onclick="workingDirectoryManager.setWorkingDirectory('${e}')">\n <span class="file-icon">📁</span>\n <span class="file-name">..</span>\n <span class="file-type">parent directory</span>\n </div>\n `}o.forEach(e=>{const t=`${this.currentWorkingDir}/${e}`.replace(/\/+/g,"/");i+=`\n <div class="file-item directory-item" onclick="workingDirectoryManager.setWorkingDirectory('${t}')">\n <span class="file-icon">📁</span>\n <span class="file-name">${e}</span>\n <span class="file-type">directory</span>\n </div>\n `}),r.forEach(e=>{const t=`${this.currentWorkingDir}/${e}`.replace(/\/+/g,"/"),r=e.split(".").pop().toLowerCase(),o=this.getFileIcon(r);i+=`\n <div class="file-item" onclick="workingDirectoryManager.viewFile('${t}')">\n <span class="file-icon">${o}</span>\n <span class="file-name">${e}</span>\n <span class="file-type">${r}</span>\n </div>\n `}),""===i&&(i='<div class="no-files">Empty directory</div>'),t.innerHTML=i}showDirectoryError(e){const t=document.querySelector(".directory-viewer-body");t&&(t.innerHTML=`\n <div class="directory-error">\n <span class="error-icon">⚠️</span>\n <span class="error-message">${e}</span>\n </div>\n `)}getFileIcon(e){return{js:"📄",py:"🐍",html:"🌐",css:"🎨",json:"📋",md:"📝",txt:"📝",yml:"⚙️",yaml:"⚙️",xml:"📄",pdf:"📕",png:"🖼️",jpg:"🖼️",jpeg:"🖼️",gif:"🖼️",svg:"🖼️",zip:"📦",tar:"📦",gz:"📦",sh:"🔧",bat:"🔧",exe:"⚙️",dll:"⚙️"}[e]||"📄"}viewFile(e){this.removeDirectoryViewerOverlay(),window.showFileViewerModal?window.showFileViewerModal(e):console.warn("File viewer modal function not available")}getCurrentWorkingDir(){return this.currentWorkingDir}getSessionDirectories(){return JSON.parse(localStorage.getItem("sessionWorkingDirs")||"{}")}setSessionDirectory(e,t){const r=this.getSessionDirectories();r[e]=t,localStorage.setItem("sessionWorkingDirs",JSON.stringify(r));const o=document.getElementById("session-select");o&&o.value===e&&this.setWorkingDirectory(t)}removeSessionDirectory(e){const t=this.getSessionDirectories();delete t[e],localStorage.setItem("sessionWorkingDirs",JSON.stringify(t))}clearAllSessionDirectories(){localStorage.removeItem("sessionWorkingDirs")}extractWorkingDirectoryFromPair(e){return e.pre?.working_dir?e.pre.working_dir:e.post?.working_dir?e.post.working_dir:e.pre?.data?.working_dir?e.pre.data.working_dir:e.post?.data?.working_dir?e.post.data.working_dir:this.currentWorkingDir||this.getDefaultWorkingDir()}validateDirectoryPath(e){if(!e||"string"!=typeof e)return!1;const t=e.trim();if(0===t.length)return!1;if(t.includes("\0"))return!1;return!["Loading...","Loading","Unknown","undefined","null","Not Connected","Invalid Directory","No Directory"].includes(t)&&(!(!t.startsWith("/")&&!/^[A-Za-z]:/.test(t))||!!(t.startsWith("./")||t.startsWith("../")||/^[a-zA-Z0-9._-]+/.test(t)))}handleGitBranchResponse(e){console.log("[GIT-BRANCH-DEBUG] handleGitBranchResponse called with:",e);const t=document.getElementById("footer-git-branch");if(t){if(e.success)console.log("[GIT-BRANCH-DEBUG] Git branch request successful, branch:",e.branch),t.textContent=e.branch,t.style.display="inline",t.classList.remove("git-error"),t.classList.add("git-success");else{let r="Git Error";const o=e.error||"Unknown error";r=o.includes("Directory not found")||o.includes("does not exist")?"Dir Not Found":o.includes("Not a directory")?"Invalid Path":o.includes("Not a git repository")?"No Git Repo":o.includes("git")?"Git Error":"Unknown",console.log("[GIT-BRANCH-DEBUG] Git branch request failed:",o,"- showing as:",r),t.textContent=r,t.style.display="inline",t.classList.remove("git-success"),t.classList.add("git-error")}e.original_working_dir&&console.log("[GIT-BRANCH-DEBUG] Server received original working_dir:",this.repr(e.original_working_dir)),e.working_dir&&console.log("[GIT-BRANCH-DEBUG] Server used working_dir:",this.repr(e.working_dir)),e.git_error&&console.log("[GIT-BRANCH-DEBUG] Git command stderr:",e.git_error)}else console.warn("[GIT-BRANCH-DEBUG] footer-git-branch element not found")}isWorkingDirectoryReady(){const e=this.getCurrentWorkingDir();return this.validateDirectoryPath(e)&&"Loading..."!==e&&"Unknown"!==e}whenDirectoryReady(e,t=5e3){const r=Date.now(),o=()=>{this.isWorkingDirectoryReady()?e():Date.now()-r<t?setTimeout(o,100):console.warn("[WORKING-DIR-DEBUG] Timeout waiting for directory to be ready")};o()}repr(e){return null===e?"null":void 0===e?"undefined":"string"==typeof e?`"${e}"`:String(e)}cleanup(){this.footerDirObserver&&(this.footerDirObserver.disconnect(),this.footerDirObserver=null),console.log("Working directory manager cleaned up")}}export{e as W};
|
1
|
+
window.WorkingDirectoryManager=class{constructor(e){this.socketManager=e,this.currentWorkingDir=null,this.footerDirObserver=null,this._updatingFooter=!1,this.setupEventHandlers(),this.initialize(),console.log("Working directory manager initialized")}initialize(){this.initializeWorkingDirectory(),this.watchFooterDirectory()}setupEventHandlers(){const e=document.getElementById("change-dir-btn"),t=document.getElementById("working-dir-path");if(e&&e.addEventListener("click",()=>{this.showChangeDirDialog()}),t&&t.addEventListener("click",e=>{e.shiftKey?this.showChangeDirDialog():this.showWorkingDirectoryViewer()}),document.addEventListener("sessionChanged",e=>{const t=e.detail.sessionId;console.log("[WORKING-DIR-DEBUG] sessionChanged event received, sessionId:",this.repr(t)),t&&this.loadWorkingDirectoryForSession(t)}),this.socketManager&&this.socketManager.getSocket){const e=this.socketManager.getSocket();e&&(console.log("[WORKING-DIR-DEBUG] Setting up git_branch_response listener"),e.on("git_branch_response",e=>{console.log("[GIT-BRANCH-DEBUG] Received git_branch_response:",e),this.handleGitBranchResponse(e)}))}}initializeWorkingDirectory(){const e=document.getElementById("working-dir-path");e&&!e.textContent.trim()&&(e.textContent="Loading...");const t=document.getElementById("session-select");t&&t.value&&"all"!==t.value?this.loadWorkingDirectoryForSession(t.value):this.setWorkingDirectory(this.getDefaultWorkingDir())}watchFooterDirectory(){const e=document.getElementById("footer-working-dir");e&&(this.footerDirObserver=new MutationObserver(t=>{this._updatingFooter||t.forEach(t=>{if("childList"===t.type||"characterData"===t.type){const t=e.textContent.trim();console.log("Footer directory changed to:",t),t&&t!==this.currentWorkingDir&&(console.log("Syncing working directory from footer change"),this.setWorkingDirectory(t))}})}),this.footerDirObserver.observe(e,{childList:!0,characterData:!0,subtree:!0}),console.log("Started watching footer directory for changes"))}loadWorkingDirectoryForSession(e){if(console.log("[WORKING-DIR-DEBUG] loadWorkingDirectoryForSession called with sessionId:",this.repr(e)),!e||"all"===e){console.log('[WORKING-DIR-DEBUG] No sessionId or sessionId is "all", using default working dir');const e=this.getDefaultWorkingDir();return console.log("[WORKING-DIR-DEBUG] Default working dir:",this.repr(e)),void this.setWorkingDirectory(e)}const t=JSON.parse(localStorage.getItem("sessionWorkingDirs")||"{}");console.log("[WORKING-DIR-DEBUG] Session directories from localStorage:",t);const r=t[e],o=this.getDefaultWorkingDir(),i=r||o;console.log("[WORKING-DIR-DEBUG] Directory selection:",{sessionId:e,sessionDir:this.repr(r),defaultDir:this.repr(o),finalDir:this.repr(i)}),this.setWorkingDirectory(i)}setWorkingDirectory(e){console.log("[WORKING-DIR-DEBUG] setWorkingDirectory called with:",this.repr(e)),this.currentWorkingDir=e,e&&this.validateDirectoryPath(e)&&(sessionStorage.setItem("currentWorkingDirectory",e),console.log("[WORKING-DIR-DEBUG] Stored working directory in session storage:",e));const t=document.getElementById("working-dir-path");t?(console.log("[WORKING-DIR-DEBUG] Updating UI path element to:",e),t.textContent=e):console.warn("[WORKING-DIR-DEBUG] working-dir-path element not found");const r=document.getElementById("footer-working-dir");if(r){const t=r.textContent;console.log("[WORKING-DIR-DEBUG] Footer directory current text:",this.repr(t),"new text:",this.repr(e)),t!==e?(this._updatingFooter=!0,r.textContent=e,console.log("[WORKING-DIR-DEBUG] Updated footer directory to:",e),setTimeout(()=>{this._updatingFooter=!1,console.log("[WORKING-DIR-DEBUG] Cleared _updatingFooter flag")},100)):console.log("[WORKING-DIR-DEBUG] Footer directory already has correct text")}else console.warn("[WORKING-DIR-DEBUG] footer-working-dir element not found");const o=document.getElementById("session-select");if(o&&o.value&&"all"!==o.value){const t=o.value,r=JSON.parse(localStorage.getItem("sessionWorkingDirs")||"{}");r[t]=e,localStorage.setItem("sessionWorkingDirs",JSON.stringify(r)),console.log(`[WORKING-DIR-DEBUG] Saved working directory for session ${t}:`,e)}else console.log('[WORKING-DIR-DEBUG] No session selected or session is "all", not saving to localStorage');console.log("[WORKING-DIR-DEBUG] About to call updateGitBranch with:",this.repr(e)),this.validateDirectoryPath(e)?this.updateGitBranch(e):console.log("[WORKING-DIR-DEBUG] Skipping git branch update for invalid directory:",this.repr(e)),document.dispatchEvent(new CustomEvent("workingDirectoryChanged",{detail:{directory:e}})),console.log("[WORKING-DIR-DEBUG] Working directory set to:",e)}updateGitBranch(e){if(console.log("[GIT-BRANCH-DEBUG] updateGitBranch called with dir:",this.repr(e),"type:",typeof e),!this.socketManager||!this.socketManager.isConnected()){console.log("[GIT-BRANCH-DEBUG] Not connected to socket server");const e=document.getElementById("footer-git-branch");return void(e&&(e.textContent="Not Connected",e.style.display="inline"))}const t=this.validateDirectoryPath(e),r="Loading..."===e||"Loading"===e,o="Unknown"===e,i=!e||"string"==typeof e&&""===e.trim();if(console.log("[GIT-BRANCH-DEBUG] Validation results:",{dir:e,isValidPath:t,isLoadingState:r,isUnknown:o,isEmptyOrWhitespace:i,shouldReject:!t||r||o||i}),!t||r||o||i){console.warn("[GIT-BRANCH-DEBUG] Invalid working directory for git branch request:",e);const t=document.getElementById("footer-git-branch");return void(t&&(t.textContent=r?"Loading...":o||i?"No Directory":"Invalid Directory",t.style.display="inline"))}const n=this.socketManager.getSocket();n?(console.log("[GIT-BRANCH-DEBUG] Requesting git branch for directory:",e),console.log("[GIT-BRANCH-DEBUG] Socket state:",{connected:n.connected,id:n.id}),n.emit("get_git_branch",e)):console.error("[GIT-BRANCH-DEBUG] No socket available for git branch request")}getDefaultWorkingDir(){if(console.log("[WORKING-DIR-DEBUG] getDefaultWorkingDir called"),this.currentWorkingDir&&this.validateDirectoryPath(this.currentWorkingDir))return console.log("[WORKING-DIR-DEBUG] Using current working directory:",this.currentWorkingDir),this.currentWorkingDir;const e=document.querySelector(".working-dir-text");if(e?.textContent?.trim()){const t=e.textContent.trim();if("Loading..."!==t&&"Unknown"!==t&&this.validateDirectoryPath(t))return console.log("[WORKING-DIR-DEBUG] Using header working directory:",t),t}const t=document.getElementById("footer-working-dir");if(t?.textContent?.trim()){const e=t.textContent.trim();console.log("[WORKING-DIR-DEBUG] Footer path found:",this.repr(e));const r="Unknown"===e,o=this.validateDirectoryPath(e);if(console.log("[WORKING-DIR-DEBUG] Footer path validation:",{footerPath:this.repr(e),isUnknown:r,isValid:o,shouldUse:!r&&o}),!r&&o)return console.log("[WORKING-DIR-DEBUG] Using footer path as default:",e),e}else console.log("[WORKING-DIR-DEBUG] No footer directory element or no text content");if(window.socketClient&&window.socketClient.events){const e=window.socketClient.events.filter(e=>e.data&&(e.data.working_directory||e.data.cwd||e.data.working_dir)).reverse();if(e.length>0){const t=e[0],r=t.data.working_directory||t.data.cwd||t.data.working_dir;return console.log("[WORKING-DIR-DEBUG] Using working directory from recent event:",r),r}}const r=document.getElementById("working-dir-path");if(r?.textContent?.trim()){const e=r.textContent.trim();if(console.log("[WORKING-DIR-DEBUG] Found working-dir-path element text:",this.repr(e)),"Unknown"!==e&&this.validateDirectoryPath(e))return console.log("[WORKING-DIR-DEBUG] Using working-dir-path as fallback:",e),e}const o=sessionStorage.getItem("currentWorkingDirectory");if(o&&this.validateDirectoryPath(o))return console.log("[WORKING-DIR-DEBUG] Using session storage working directory:",this.repr(o)),o;const i=window.processWorkingDirectory||process?.cwd?.()||null;if(i&&this.validateDirectoryPath(i))return console.log("[WORKING-DIR-DEBUG] Using process working directory:",this.repr(i)),i;const n=window.homeDirectory||process?.env?.HOME||process?.env?.USERPROFILE||null||process?.cwd?.()||os?.homedir?.()||"/Users/masa";return console.log("[WORKING-DIR-DEBUG] Using fallback directory (home or cwd):",this.repr(n)),n}showChangeDirDialog(){const e=prompt("Enter new working directory:",this.currentWorkingDir||"");e&&""!==e.trim()&&this.setWorkingDirectory(e.trim())}showWorkingDirectoryViewer(){this.createDirectoryViewerOverlay()}createDirectoryViewerOverlay(){this.removeDirectoryViewerOverlay();const e=document.querySelector(".working-dir-display");if(!e)return;const t=document.createElement("div");t.id="directory-viewer-overlay",t.className="directory-viewer-overlay",t.innerHTML=`\n <div class="directory-viewer-content">\n <div class="directory-viewer-header">\n <h3 class="directory-viewer-title">\n 📁 ${this.currentWorkingDir||"Working Directory"}\n </h3>\n <button class="close-btn" onclick="workingDirectoryManager.removeDirectoryViewerOverlay()">✕</button>\n </div>\n <div class="directory-viewer-body">\n <div class="loading-indicator">Loading directory contents...</div>\n </div>\n <div class="directory-viewer-footer">\n <span class="directory-hint">Click file to view • Shift+Click directory path to change</span>\n </div>\n </div>\n `;const r=e.getBoundingClientRect();t.style.cssText=`\n position: fixed;\n top: ${r.bottom+5}px;\n left: ${r.left}px;\n min-width: 400px;\n max-width: 600px;\n max-height: 400px;\n z-index: 1001;\n background: white;\n border-radius: 8px;\n box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);\n border: 1px solid #e2e8f0;\n `,document.body.appendChild(t),this.loadDirectoryContents(),setTimeout(()=>{document.addEventListener("click",this.handleOutsideClick.bind(this),!0)},100)}removeDirectoryViewerOverlay(){const e=document.getElementById("directory-viewer-overlay");e&&(e.remove(),document.removeEventListener("click",this.handleOutsideClick.bind(this),!0))}handleOutsideClick(e){const t=document.getElementById("directory-viewer-overlay"),r=document.getElementById("working-dir-path");t&&!t.contains(e.target)&&e.target!==r&&this.removeDirectoryViewerOverlay()}loadDirectoryContents(){if(!this.socketManager||!this.socketManager.isConnected())return void this.showDirectoryError("Not connected to server");const e=this.socketManager.getSocket();if(!e)return void this.showDirectoryError("No socket connection available");e.emit("get_directory_listing",{directory:this.currentWorkingDir,limit:50});const t=r=>{e.off("directory_listing_response",t),this.handleDirectoryListingResponse(r)};e.on("directory_listing_response",t),setTimeout(()=>{e.off("directory_listing_response",t);const r=document.getElementById("directory-viewer-overlay");r&&r.querySelector(".loading-indicator")&&this.showDirectoryError("Request timeout")},5e3)}handleDirectoryListingResponse(e){const t=document.querySelector(".directory-viewer-body");if(!t)return;if(!e.success)return void this.showDirectoryError(e.error||"Failed to load directory");const r=e.files||[],o=e.directories||[];let i="";if(this.currentWorkingDir&&"/"!==this.currentWorkingDir){const e=this.currentWorkingDir.split("/").slice(0,-1).join("/")||"/";i+=`\n <div class="file-item directory-item" onclick="workingDirectoryManager.setWorkingDirectory('${e}')">\n <span class="file-icon">📁</span>\n <span class="file-name">..</span>\n <span class="file-type">parent directory</span>\n </div>\n `}o.forEach(e=>{const t=`${this.currentWorkingDir}/${e}`.replace(/\/+/g,"/");i+=`\n <div class="file-item directory-item" onclick="workingDirectoryManager.setWorkingDirectory('${t}')">\n <span class="file-icon">📁</span>\n <span class="file-name">${e}</span>\n <span class="file-type">directory</span>\n </div>\n `}),r.forEach(e=>{const t=`${this.currentWorkingDir}/${e}`.replace(/\/+/g,"/"),r=e.split(".").pop().toLowerCase(),o=this.getFileIcon(r);i+=`\n <div class="file-item" onclick="workingDirectoryManager.viewFile('${t}')">\n <span class="file-icon">${o}</span>\n <span class="file-name">${e}</span>\n <span class="file-type">${r}</span>\n </div>\n `}),""===i&&(i='<div class="no-files">Empty directory</div>'),t.innerHTML=i}showDirectoryError(e){const t=document.querySelector(".directory-viewer-body");t&&(t.innerHTML=`\n <div class="directory-error">\n <span class="error-icon">⚠️</span>\n <span class="error-message">${e}</span>\n </div>\n `)}getFileIcon(e){return{js:"📄",py:"🐍",html:"🌐",css:"🎨",json:"📋",md:"📝",txt:"📝",yml:"⚙️",yaml:"⚙️",xml:"📄",pdf:"📕",png:"🖼️",jpg:"🖼️",jpeg:"🖼️",gif:"🖼️",svg:"🖼️",zip:"📦",tar:"📦",gz:"📦",sh:"🔧",bat:"🔧",exe:"⚙️",dll:"⚙️"}[e]||"📄"}viewFile(e){this.removeDirectoryViewerOverlay(),window.showFileViewerModal?window.showFileViewerModal(e):console.warn("File viewer modal function not available")}getCurrentWorkingDir(){return this.currentWorkingDir}getSessionDirectories(){return JSON.parse(localStorage.getItem("sessionWorkingDirs")||"{}")}setSessionDirectory(e,t){const r=this.getSessionDirectories();r[e]=t,localStorage.setItem("sessionWorkingDirs",JSON.stringify(r));const o=document.getElementById("session-select");o&&o.value===e&&this.setWorkingDirectory(t)}removeSessionDirectory(e){const t=this.getSessionDirectories();delete t[e],localStorage.setItem("sessionWorkingDirs",JSON.stringify(t))}clearAllSessionDirectories(){localStorage.removeItem("sessionWorkingDirs")}extractWorkingDirectoryFromPair(e){return e.pre?.working_dir?e.pre.working_dir:e.post?.working_dir?e.post.working_dir:e.pre?.data?.working_dir?e.pre.data.working_dir:e.post?.data?.working_dir?e.post.data.working_dir:this.currentWorkingDir||this.getDefaultWorkingDir()}validateDirectoryPath(e){if(!e||"string"!=typeof e)return!1;const t=e.trim();if(0===t.length)return!1;if(t.includes("\0"))return!1;return!["Loading...","Loading","Unknown","undefined","null","Not Connected","Invalid Directory","No Directory"].includes(t)&&(!(!t.startsWith("/")&&!/^[A-Za-z]:/.test(t))||!!(t.startsWith("./")||t.startsWith("../")||/^[a-zA-Z0-9._-]+/.test(t)))}handleGitBranchResponse(e){console.log("[GIT-BRANCH-DEBUG] handleGitBranchResponse called with:",e);const t=document.getElementById("footer-git-branch");if(t){if(e.success)console.log("[GIT-BRANCH-DEBUG] Git branch request successful, branch:",e.branch),t.textContent=e.branch,t.style.display="inline",t.classList.remove("git-error"),t.classList.add("git-success");else{let r="Git Error";const o=e.error||"Unknown error";r=o.includes("Directory not found")||o.includes("does not exist")?"Dir Not Found":o.includes("Not a directory")?"Invalid Path":o.includes("Not a git repository")?"No Git Repo":o.includes("git")?"Git Error":"Unknown",console.log("[GIT-BRANCH-DEBUG] Git branch request failed:",o,"- showing as:",r),t.textContent=r,t.style.display="inline",t.classList.remove("git-success"),t.classList.add("git-error")}e.original_working_dir&&console.log("[GIT-BRANCH-DEBUG] Server received original working_dir:",this.repr(e.original_working_dir)),e.working_dir&&console.log("[GIT-BRANCH-DEBUG] Server used working_dir:",this.repr(e.working_dir)),e.git_error&&console.log("[GIT-BRANCH-DEBUG] Git command stderr:",e.git_error)}else console.warn("[GIT-BRANCH-DEBUG] footer-git-branch element not found")}isWorkingDirectoryReady(){const e=this.getCurrentWorkingDir();return this.validateDirectoryPath(e)&&"Loading..."!==e&&"Unknown"!==e}whenDirectoryReady(e,t=5e3){const r=Date.now(),o=()=>{this.isWorkingDirectoryReady()?e():Date.now()-r<t?setTimeout(o,100):console.warn("[WORKING-DIR-DEBUG] Timeout waiting for directory to be ready")};o()}repr(e){return null===e?"null":void 0===e?"undefined":"string"==typeof e?`"${e}"`:String(e)}cleanup(){this.footerDirObserver&&(this.footerDirObserver.disconnect(),this.footerDirObserver=null),console.log("Working directory manager cleaned up")}};
|
2
2
|
//# sourceMappingURL=working-directory.js.map
|