vg-coder-cli 2.0.34 → 2.0.36
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.
- package/README.md +1 -0
- package/dist/vg-coder-bundle.js +3 -3
- package/package.json +1 -2
- package/src/server/api-server.js +130 -0
- package/src/server/views/css/commands-panel.css +75 -0
- package/src/server/views/css/editor.css +1 -1
- package/src/server/views/css/git-panel.css +361 -0
- package/src/server/views/css/git-view.css +1 -77
- package/src/server/views/css/project-panel.css +242 -0
- package/src/server/views/css/shortcuts-help.css +165 -0
- package/src/server/views/css/tool-window.css +267 -0
- package/src/server/views/dashboard.css +1 -1
- package/src/server/views/dashboard.html +78 -102
- package/src/server/views/js/api.js +26 -0
- package/src/server/views/js/event-protocol.js +1 -0
- package/src/server/views/js/features/bubble-features/copy-prompt-feature.js +14 -0
- package/src/server/views/js/features/bubble-features/index.js +6 -1
- package/src/server/views/js/features/commands-panel.js +63 -0
- package/src/server/views/js/features/git-panel.js +481 -0
- package/src/server/views/js/features/git-view.js +79 -307
- package/src/server/views/js/features/keyboard-shortcuts.js +333 -0
- package/src/server/views/js/features/project-panel.js +452 -0
- package/src/server/views/js/features/resize.js +7 -10
- package/src/server/views/js/features/terminal.js +74 -1
- package/src/server/views/js/features/tool-window.js +154 -0
- package/src/server/views/js/handlers.js +32 -5
- package/src/server/views/js/main.js +17 -31
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { getById, qsa } from '../utils.js';
|
|
2
|
+
|
|
3
|
+
let activePanel = null;
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Initialize Tool Window system
|
|
7
|
+
*/
|
|
8
|
+
export function initToolWindow() {
|
|
9
|
+
const toolWindowBar = getById('tool-window-bar');
|
|
10
|
+
if (!toolWindowBar) {
|
|
11
|
+
console.warn('[ToolWindow] Tool window bar not found');
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
// Attach event listeners to all tool window icons
|
|
16
|
+
const icons = qsa('.tool-window-icon');
|
|
17
|
+
icons.forEach(icon => {
|
|
18
|
+
icon.addEventListener('click', () => {
|
|
19
|
+
const panelId = icon.dataset.panel;
|
|
20
|
+
if (panelId) {
|
|
21
|
+
togglePanel(panelId);
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Open Project panel by default after a short delay
|
|
27
|
+
// This ensures all panel listeners are registered first
|
|
28
|
+
setTimeout(() => {
|
|
29
|
+
togglePanel('project');
|
|
30
|
+
}, 100);
|
|
31
|
+
|
|
32
|
+
console.log('[ToolWindow] Initialized with Project panel active');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Toggle a specific panel
|
|
37
|
+
* @param {string} panelId - Panel ID to toggle (e.g., 'project', 'git')
|
|
38
|
+
*/
|
|
39
|
+
export function togglePanel(panelId) {
|
|
40
|
+
const panel = getById(`tool-panel-${panelId}`);
|
|
41
|
+
const container = getById('tool-panel-container');
|
|
42
|
+
const icon = qsa(`.tool-window-icon[data-panel="${panelId}"]`)[0];
|
|
43
|
+
|
|
44
|
+
if (!panel || !container) {
|
|
45
|
+
console.error('[ToolWindow] Panel or container not found:', panelId);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// If clicking the same active panel, close it
|
|
50
|
+
if (activePanel === panelId) {
|
|
51
|
+
closeAllPanels();
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Close all panels first
|
|
56
|
+
closeAllPanels();
|
|
57
|
+
|
|
58
|
+
// Open the new panel
|
|
59
|
+
setActivePanel(panelId);
|
|
60
|
+
container.classList.add('expanded');
|
|
61
|
+
panel.classList.add('active');
|
|
62
|
+
if (icon) icon.classList.add('active');
|
|
63
|
+
|
|
64
|
+
activePanel = panelId;
|
|
65
|
+
|
|
66
|
+
// Trigger panel-specific initialization if needed
|
|
67
|
+
triggerPanelInit(panelId);
|
|
68
|
+
|
|
69
|
+
console.log('[ToolWindow] Opened panel:', panelId);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Close all open panels
|
|
74
|
+
*/
|
|
75
|
+
export function closeAllPanels() {
|
|
76
|
+
const container = getById('tool-panel-container');
|
|
77
|
+
const panels = qsa('.tool-panel');
|
|
78
|
+
const icons = qsa('.tool-window-icon');
|
|
79
|
+
|
|
80
|
+
if (container) {
|
|
81
|
+
container.classList.remove('expanded');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
panels.forEach(panel => {
|
|
85
|
+
panel.classList.remove('active');
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
icons.forEach(icon => {
|
|
89
|
+
icon.classList.remove('active');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
activePanel = null;
|
|
93
|
+
|
|
94
|
+
console.log('[ToolWindow] Closed all panels');
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Set a panel as active (internal use)
|
|
99
|
+
* @param {string} panelId - Panel ID
|
|
100
|
+
*/
|
|
101
|
+
function setActivePanel(panelId) {
|
|
102
|
+
const panels = qsa('.tool-panel');
|
|
103
|
+
panels.forEach(panel => {
|
|
104
|
+
if (panel.id === `tool-panel-${panelId}`) {
|
|
105
|
+
panel.classList.add('active');
|
|
106
|
+
} else {
|
|
107
|
+
panel.classList.remove('active');
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Trigger initialization for panel-specific features
|
|
114
|
+
* @param {string} panelId - Panel ID
|
|
115
|
+
*/
|
|
116
|
+
function triggerPanelInit(panelId) {
|
|
117
|
+
// Dispatch custom event that panel modules can listen to
|
|
118
|
+
const event = new CustomEvent('tool-panel-opened', {
|
|
119
|
+
detail: { panelId }
|
|
120
|
+
});
|
|
121
|
+
document.dispatchEvent(event);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Get the currently active panel ID
|
|
126
|
+
* @returns {string|null} Active panel ID or null
|
|
127
|
+
*/
|
|
128
|
+
export function getActivePanel() {
|
|
129
|
+
return activePanel;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Register a callback for when a panel is closed
|
|
134
|
+
* @param {Function} callback - Callback function
|
|
135
|
+
*/
|
|
136
|
+
export function onPanelClose(callback) {
|
|
137
|
+
const container = getById('tool-panel-container');
|
|
138
|
+
if (container) {
|
|
139
|
+
const observer = new MutationObserver((mutations) => {
|
|
140
|
+
mutations.forEach((mutation) => {
|
|
141
|
+
if (mutation.attributeName === 'class') {
|
|
142
|
+
if (!container.classList.contains('expanded')) {
|
|
143
|
+
callback();
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
observer.observe(container, { attributes: true });
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Expose to window for HTML onclick if needed
|
|
153
|
+
window.toggleToolPanel = togglePanel;
|
|
154
|
+
window.closeToolPanels = closeAllPanels;
|
|
@@ -36,6 +36,17 @@ export function initEventHandlers() {
|
|
|
36
36
|
}
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
+
// Copy System Prompt
|
|
40
|
+
globalDispatcher.on(EVENT_TYPES.COPY_PROMPT, async (event) => {
|
|
41
|
+
console.log('[Handlers] Copy Prompt event received:', event);
|
|
42
|
+
try {
|
|
43
|
+
await navigator.clipboard.writeText(SYSTEM_PROMPT);
|
|
44
|
+
showToast('📋 Copied System Prompt', 'success');
|
|
45
|
+
} catch (err) {
|
|
46
|
+
showToast('Failed to copy: ' + err.message, 'error');
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
39
50
|
console.log('[Handlers] Event handlers initialized');
|
|
40
51
|
}
|
|
41
52
|
|
|
@@ -159,7 +170,8 @@ export async function testExecute(event) {
|
|
|
159
170
|
export async function executeFromClipboard(event) {
|
|
160
171
|
const btn = event?.target?.closest('.btn');
|
|
161
172
|
const bashInput = getById('execute-bash');
|
|
162
|
-
|
|
173
|
+
|
|
174
|
+
// Don't return early if bashInput is missing - it's optional when called from bubble menu
|
|
163
175
|
|
|
164
176
|
if (btn) showLoading(btn, btn.innerHTML);
|
|
165
177
|
try {
|
|
@@ -169,13 +181,25 @@ export async function executeFromClipboard(event) {
|
|
|
169
181
|
if (btn) resetButton(btn);
|
|
170
182
|
return;
|
|
171
183
|
}
|
|
172
|
-
|
|
184
|
+
|
|
185
|
+
// Only populate bashInput if it exists (when called from dashboard)
|
|
186
|
+
if (bashInput) {
|
|
187
|
+
bashInput.value = clipboardText;
|
|
188
|
+
}
|
|
189
|
+
|
|
173
190
|
const data = await executeScript(clipboardText);
|
|
174
|
-
|
|
191
|
+
|
|
192
|
+
// Only show response in execute-response container if it exists
|
|
193
|
+
const responseContainer = getById('execute-response');
|
|
194
|
+
if (responseContainer) {
|
|
195
|
+
showResponse('execute-response', data, !data.success);
|
|
196
|
+
}
|
|
175
197
|
|
|
176
198
|
if (data.success) {
|
|
177
199
|
showToast('Thực thi OK', 'success');
|
|
178
|
-
bashInput
|
|
200
|
+
if (bashInput) {
|
|
201
|
+
bashInput.value = '';
|
|
202
|
+
}
|
|
179
203
|
} else {
|
|
180
204
|
data.syntaxError ? showToast('Lỗi syntax script', 'error') : showToast('Thực thi thất bại', 'error');
|
|
181
205
|
}
|
|
@@ -183,7 +207,10 @@ export async function executeFromClipboard(event) {
|
|
|
183
207
|
if (err.name === 'NotAllowedError') {
|
|
184
208
|
showToast('Không có quyền clipboard', 'error');
|
|
185
209
|
} else {
|
|
186
|
-
|
|
210
|
+
const responseContainer = getById('execute-response');
|
|
211
|
+
if (responseContainer) {
|
|
212
|
+
showResponse('execute-response', { error: err.message }, true);
|
|
213
|
+
}
|
|
187
214
|
showToast('Lỗi: ' + err.message, 'error');
|
|
188
215
|
}
|
|
189
216
|
}
|
|
@@ -8,9 +8,15 @@ import { initEditorTabs } from './features/editor-tabs.js';
|
|
|
8
8
|
// REMOVED: initMonaco
|
|
9
9
|
import { initResizeHandler } from './features/resize.js';
|
|
10
10
|
import { initSavedCommands } from './features/commands.js';
|
|
11
|
-
import { initProjectSwitcher } from './features/project-switcher.js';
|
|
12
11
|
import './features/structure.js';
|
|
13
12
|
import { initBubble } from './features/bubble.js';
|
|
13
|
+
import { initKeyboardShortcuts } from './features/keyboard-shortcuts.js';
|
|
14
|
+
|
|
15
|
+
// NEW: Import Tool Window modules
|
|
16
|
+
import { initToolWindow } from './features/tool-window.js';
|
|
17
|
+
import { initProjectPanel } from './features/project-panel.js';
|
|
18
|
+
import { initGitPanel } from './features/git-panel.js';
|
|
19
|
+
import { initCommandsPanel } from './features/commands-panel.js';
|
|
14
20
|
|
|
15
21
|
export async function initMain() {
|
|
16
22
|
console.log('VG Coder: Starting Main Logic...');
|
|
@@ -19,8 +25,6 @@ export async function initMain() {
|
|
|
19
25
|
const promptEl = getById('prompt-text');
|
|
20
26
|
if (promptEl) promptEl.textContent = SYSTEM_PROMPT;
|
|
21
27
|
|
|
22
|
-
await checkServerStatus();
|
|
23
|
-
await loadProjectInfo();
|
|
24
28
|
|
|
25
29
|
initTheme();
|
|
26
30
|
loadExtensionPath();
|
|
@@ -28,15 +32,24 @@ export async function initMain() {
|
|
|
28
32
|
// Initialize event handlers FIRST (before bubble which dispatches events)
|
|
29
33
|
initEventHandlers();
|
|
30
34
|
|
|
35
|
+
// NEW: Initialize Tool Window system
|
|
36
|
+
initToolWindow();
|
|
37
|
+
initProjectPanel();
|
|
38
|
+
initGitPanel();
|
|
39
|
+
initCommandsPanel();
|
|
40
|
+
|
|
31
41
|
initGitView();
|
|
32
42
|
initTerminal();
|
|
33
43
|
initEditorTabs();
|
|
34
44
|
initResizeHandler();
|
|
35
45
|
initSavedCommands();
|
|
36
|
-
|
|
46
|
+
// initProjectSwitcher(); // REMOVED: project-panel.js now handles project polling
|
|
37
47
|
|
|
38
48
|
// Init Bubble (will use event protocol)
|
|
39
49
|
initBubble();
|
|
50
|
+
|
|
51
|
+
// Initialize keyboard shortcuts (global hotkeys for Shadow DOM)
|
|
52
|
+
initKeyboardShortcuts();
|
|
40
53
|
|
|
41
54
|
console.log('✅ VG Coder: Initialization Complete');
|
|
42
55
|
} catch (e) {
|
|
@@ -44,11 +57,9 @@ export async function initMain() {
|
|
|
44
57
|
}
|
|
45
58
|
}
|
|
46
59
|
|
|
47
|
-
// ... (Giữ nguyên các hàm helper khác: switchProject, loadProjectInfo, initTheme...)
|
|
48
60
|
// Để ngắn gọn, tôi copy lại phần còn lại của main.js
|
|
49
61
|
window.addEventListener('project-switched', async (event) => {
|
|
50
62
|
const { projectId, projectName } = event.detail;
|
|
51
|
-
await loadProjectInfo();
|
|
52
63
|
if (window.updateTerminalVisibility) window.updateTerminalVisibility(projectId);
|
|
53
64
|
if (window.loadSavedCommands) await window.loadSavedCommands();
|
|
54
65
|
const treeContainer = getById('structure-tree');
|
|
@@ -57,31 +68,6 @@ window.addEventListener('project-switched', async (event) => {
|
|
|
57
68
|
if (treeContent) treeContent.innerHTML = '';
|
|
58
69
|
});
|
|
59
70
|
|
|
60
|
-
async function checkServerStatus() {
|
|
61
|
-
const statusEl = getById('status');
|
|
62
|
-
if (!statusEl) return;
|
|
63
|
-
const isHealthy = await checkHealth();
|
|
64
|
-
if (isHealthy) {
|
|
65
|
-
statusEl.textContent = '●';
|
|
66
|
-
statusEl.style.background = 'transparent';
|
|
67
|
-
statusEl.style.color = 'var(--ios-green)';
|
|
68
|
-
} else {
|
|
69
|
-
statusEl.textContent = '●';
|
|
70
|
-
statusEl.style.background = 'transparent';
|
|
71
|
-
statusEl.style.color = 'var(--ios-red)';
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
async function loadProjectInfo() {
|
|
76
|
-
try {
|
|
77
|
-
const res = await fetch(`${API_BASE}/api/info?path=.`);
|
|
78
|
-
const data = await res.json();
|
|
79
|
-
const projectNameEl = getById('project-name');
|
|
80
|
-
const projectMetaEl = getById('project-meta');
|
|
81
|
-
if (projectNameEl) projectNameEl.textContent = data.path.split(/[\\/]/).pop();
|
|
82
|
-
if (projectMetaEl) projectMetaEl.textContent = `${data.primaryType} • ${data.path}`;
|
|
83
|
-
} catch (err) {}
|
|
84
|
-
}
|
|
85
71
|
|
|
86
72
|
function initTheme() {
|
|
87
73
|
const themeBtn = getById('theme-toggle');
|