vg-coder-cli 2.0.7 → 2.0.8
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/package.json +2 -1
- package/src/server/api-server.js +3 -0
- package/src/server/views/dashboard.css +488 -0
- package/src/server/views/dashboard.html +40 -888
- package/src/server/views/dashboard.js +457 -0
- package/src/server/views/js/api.js +101 -0
- package/src/server/views/js/config.js +120 -0
- package/src/server/views/js/handlers.js +214 -0
- package/src/server/views/js/main.js +72 -0
- package/src/server/views/js/utils.js +72 -0
- package/vg-coder-cli-2.0.8.tgz +0 -0
- package/vg-coder-cli-1.0.17.tgz +0 -0
- package/vg-coder-cli-2.0.4.tgz +0 -0
- package/vg-coder-cli-2.0.5.tgz +0 -0
- package/vg-coder-cli-2.0.6.tgz +0 -0
- package/vg-coder-cli-2.0.7.tgz +0 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
// Event Handlers & Business Logic
|
|
2
|
+
import { SYSTEM_PROMPT } from './config.js';
|
|
3
|
+
import { analyzeProject, executeScript, copyAsFile, copyToClipboard, readFromClipboard } from './api.js';
|
|
4
|
+
import { showToast, showLoading, resetButton, showResponse, showCopiedState } from './utils.js';
|
|
5
|
+
|
|
6
|
+
// State management
|
|
7
|
+
let lastAnalyzeResult = null;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Toggle system prompt section
|
|
11
|
+
*/
|
|
12
|
+
export function toggleSystemPrompt() {
|
|
13
|
+
const content = document.getElementById('system-prompt-content');
|
|
14
|
+
const icon = document.getElementById('toggle-icon');
|
|
15
|
+
content.classList.toggle('open');
|
|
16
|
+
icon.classList.toggle('open');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Copy system prompt from the Header Button
|
|
21
|
+
* Stops propagation so the accordion doesn't toggle
|
|
22
|
+
*/
|
|
23
|
+
export function copySystemPromptFromHeader(event) {
|
|
24
|
+
event.stopPropagation(); // Stop accordion from toggling
|
|
25
|
+
|
|
26
|
+
// Animate button
|
|
27
|
+
const btn = event.currentTarget;
|
|
28
|
+
btn.textContent = '✓';
|
|
29
|
+
|
|
30
|
+
navigator.clipboard.writeText(SYSTEM_PROMPT).then(() => {
|
|
31
|
+
showToast('Đã copy System Prompt', 'success');
|
|
32
|
+
setTimeout(() => {
|
|
33
|
+
btn.textContent = '📋';
|
|
34
|
+
}, 2000);
|
|
35
|
+
}).catch(err => {
|
|
36
|
+
showToast('Lỗi copy: ' + err.message, 'error');
|
|
37
|
+
btn.textContent = '📋';
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Copy system prompt to clipboard (Main content button)
|
|
43
|
+
*/
|
|
44
|
+
export function copySystemPrompt() {
|
|
45
|
+
const copyBtn = event.target.closest('.btn-copy');
|
|
46
|
+
const copyIcon = document.getElementById('copy-icon');
|
|
47
|
+
const copyText = document.getElementById('copy-text');
|
|
48
|
+
|
|
49
|
+
navigator.clipboard.writeText(SYSTEM_PROMPT).then(() => {
|
|
50
|
+
showCopiedState(copyBtn, copyIcon, copyText, '📋', 'Copy System Prompt');
|
|
51
|
+
showToast('Đã copy System Prompt', 'success');
|
|
52
|
+
}).catch(err => {
|
|
53
|
+
showToast('Lỗi copy: ' + err.message, 'error');
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Handle analyze button click
|
|
59
|
+
*/
|
|
60
|
+
export async function testAnalyze() {
|
|
61
|
+
// Support both the big button .btn and the header icon .btn-icon-head
|
|
62
|
+
const btn = event.target.closest('.btn') || event.target.closest('.btn-icon-head');
|
|
63
|
+
const path = document.getElementById('analyze-path').value;
|
|
64
|
+
|
|
65
|
+
showLoading(btn, btn.innerHTML);
|
|
66
|
+
try {
|
|
67
|
+
const text = await analyzeProject(path);
|
|
68
|
+
lastAnalyzeResult = text;
|
|
69
|
+
|
|
70
|
+
// Download file
|
|
71
|
+
const blob = new Blob([text], { type: 'text/plain' });
|
|
72
|
+
const url = window.URL.createObjectURL(blob);
|
|
73
|
+
const a = document.createElement('a');
|
|
74
|
+
a.href = url;
|
|
75
|
+
a.download = 'project.txt';
|
|
76
|
+
a.click();
|
|
77
|
+
|
|
78
|
+
showResponse('analyze-response', {
|
|
79
|
+
success: true,
|
|
80
|
+
message: 'File downloaded!',
|
|
81
|
+
files: text.split('\n').filter(l => l.includes('===== FILE:')).length,
|
|
82
|
+
size: (text.length / 1024).toFixed(2) + ' KB'
|
|
83
|
+
});
|
|
84
|
+
showToast('Đã download file', 'success');
|
|
85
|
+
} catch (err) {
|
|
86
|
+
showResponse('analyze-response', { error: err.message }, true);
|
|
87
|
+
showToast('Lỗi: ' + err.message, 'error');
|
|
88
|
+
}
|
|
89
|
+
resetButton(btn);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Copy analyze result as text
|
|
94
|
+
*/
|
|
95
|
+
export async function copyAnalyzeResult() {
|
|
96
|
+
const copyBtn = event.target.closest('.btn-copy');
|
|
97
|
+
const copyIcon = document.getElementById('analyze-copy-icon');
|
|
98
|
+
const copyText = document.getElementById('analyze-copy-text');
|
|
99
|
+
|
|
100
|
+
if (!lastAnalyzeResult) {
|
|
101
|
+
// Fetch if not already analyzed
|
|
102
|
+
const path = document.getElementById('analyze-path').value;
|
|
103
|
+
showLoading(copyBtn, copyBtn.innerHTML);
|
|
104
|
+
|
|
105
|
+
try {
|
|
106
|
+
lastAnalyzeResult = await analyzeProject(path);
|
|
107
|
+
} catch (err) {
|
|
108
|
+
showToast('Lỗi: ' + err.message, 'error');
|
|
109
|
+
resetButton(copyBtn);
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
resetButton(copyBtn);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Copy to clipboard
|
|
116
|
+
try {
|
|
117
|
+
await copyToClipboard(lastAnalyzeResult);
|
|
118
|
+
showCopiedState(copyBtn, copyIcon, copyText, '📋', 'Copy Text');
|
|
119
|
+
showToast('Đã copy project.txt', 'success');
|
|
120
|
+
} catch (err) {
|
|
121
|
+
showToast('Lỗi copy: ' + err.message, 'error');
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Handle execute button click
|
|
127
|
+
*/
|
|
128
|
+
export async function testExecute() {
|
|
129
|
+
const btn = event.target.closest('.btn');
|
|
130
|
+
const bashInput = document.getElementById('execute-bash');
|
|
131
|
+
const bash = bashInput.value;
|
|
132
|
+
|
|
133
|
+
if (!bash.trim()) {
|
|
134
|
+
showToast('Vui lòng nhập bash script', 'error');
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
showLoading(btn, btn.innerHTML);
|
|
139
|
+
try {
|
|
140
|
+
const data = await executeScript(bash);
|
|
141
|
+
showResponse('execute-response', data, !data.success);
|
|
142
|
+
|
|
143
|
+
if (data.success) {
|
|
144
|
+
showToast('Thực thi thành công', 'success');
|
|
145
|
+
// Clear input on success
|
|
146
|
+
bashInput.value = '';
|
|
147
|
+
} else {
|
|
148
|
+
showToast('Thực thi thất bại', 'error');
|
|
149
|
+
}
|
|
150
|
+
} catch (err) {
|
|
151
|
+
showResponse('execute-response', { error: err.message }, true);
|
|
152
|
+
showToast('Lỗi: ' + err.message, 'error');
|
|
153
|
+
}
|
|
154
|
+
resetButton(btn);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Execute script from clipboard
|
|
159
|
+
*/
|
|
160
|
+
export async function executeFromClipboard() {
|
|
161
|
+
const btn = event.target.closest('.btn');
|
|
162
|
+
const bashInput = document.getElementById('execute-bash');
|
|
163
|
+
|
|
164
|
+
showLoading(btn, btn.innerHTML);
|
|
165
|
+
|
|
166
|
+
try {
|
|
167
|
+
const clipboardText = await readFromClipboard();
|
|
168
|
+
|
|
169
|
+
if (!clipboardText || !clipboardText.trim()) {
|
|
170
|
+
showToast('Clipboard trống!', 'error');
|
|
171
|
+
showResponse('execute-response', {
|
|
172
|
+
error: 'Clipboard is empty',
|
|
173
|
+
message: 'Please copy a bash script to clipboard first'
|
|
174
|
+
}, true);
|
|
175
|
+
resetButton(btn);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Show what we are running
|
|
180
|
+
bashInput.value = clipboardText;
|
|
181
|
+
|
|
182
|
+
const data = await executeScript(clipboardText);
|
|
183
|
+
showResponse('execute-response', data, !data.success);
|
|
184
|
+
|
|
185
|
+
if (data.success) {
|
|
186
|
+
showToast('Thực thi từ clipboard OK', 'success');
|
|
187
|
+
// Clear input on success
|
|
188
|
+
bashInput.value = '';
|
|
189
|
+
} else {
|
|
190
|
+
if (data.syntaxError) {
|
|
191
|
+
showToast('Lỗi syntax script', 'error');
|
|
192
|
+
} else {
|
|
193
|
+
showToast('Thực thi thất bại', 'error');
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
} catch (err) {
|
|
197
|
+
if (err.name === 'NotAllowedError') {
|
|
198
|
+
showToast('Không có quyền clipboard', 'error');
|
|
199
|
+
} else {
|
|
200
|
+
showResponse('execute-response', { error: err.message }, true);
|
|
201
|
+
showToast('Lỗi: ' + err.message, 'error');
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
resetButton(btn);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Make functions globally available for onclick handlers
|
|
208
|
+
window.toggleSystemPrompt = toggleSystemPrompt;
|
|
209
|
+
window.copySystemPrompt = copySystemPrompt;
|
|
210
|
+
window.copySystemPromptFromHeader = copySystemPromptFromHeader;
|
|
211
|
+
window.testAnalyze = testAnalyze;
|
|
212
|
+
window.copyAnalyzeResult = copyAnalyzeResult;
|
|
213
|
+
window.testExecute = testExecute;
|
|
214
|
+
window.executeFromClipboard = executeFromClipboard;
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Main entry point - Initialize application
|
|
2
|
+
import { SYSTEM_PROMPT } from './config.js';
|
|
3
|
+
import { checkHealth } from './api.js';
|
|
4
|
+
import './handlers.js'; // Import to register global functions
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Initialize application on DOM ready
|
|
8
|
+
*/
|
|
9
|
+
document.addEventListener('DOMContentLoaded', async () => {
|
|
10
|
+
// Load system prompt text
|
|
11
|
+
document.getElementById('prompt-text').textContent = SYSTEM_PROMPT;
|
|
12
|
+
|
|
13
|
+
// Check server status
|
|
14
|
+
await checkServerStatus();
|
|
15
|
+
|
|
16
|
+
// Initialize Theme
|
|
17
|
+
initTheme();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Check and update server status
|
|
22
|
+
*/
|
|
23
|
+
async function checkServerStatus() {
|
|
24
|
+
const statusEl = document.getElementById('status');
|
|
25
|
+
const isHealthy = await checkHealth();
|
|
26
|
+
|
|
27
|
+
if (isHealthy) {
|
|
28
|
+
statusEl.textContent = '● Online';
|
|
29
|
+
statusEl.style.background = 'rgba(52, 199, 89, 0.15)';
|
|
30
|
+
statusEl.style.color = 'var(--ios-green)';
|
|
31
|
+
} else {
|
|
32
|
+
statusEl.textContent = '● Offline';
|
|
33
|
+
statusEl.style.background = 'rgba(255, 59, 48, 0.15)';
|
|
34
|
+
statusEl.style.color = 'var(--ios-red)';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Initialize Theme Logic
|
|
40
|
+
*/
|
|
41
|
+
function initTheme() {
|
|
42
|
+
const themeBtn = document.getElementById('theme-toggle');
|
|
43
|
+
const themeIcon = document.getElementById('theme-icon');
|
|
44
|
+
|
|
45
|
+
// Get current theme from DOM (set by inline script) or localStorage
|
|
46
|
+
let currentTheme = localStorage.getItem('theme') || 'light';
|
|
47
|
+
|
|
48
|
+
// Update icon initially
|
|
49
|
+
updateThemeIcon(currentTheme);
|
|
50
|
+
|
|
51
|
+
themeBtn.addEventListener('click', () => {
|
|
52
|
+
// Toggle theme
|
|
53
|
+
const newTheme = currentTheme === 'light' ? 'dark' : 'light';
|
|
54
|
+
|
|
55
|
+
// Update DOM
|
|
56
|
+
document.documentElement.setAttribute('data-theme', newTheme);
|
|
57
|
+
localStorage.setItem('theme', newTheme);
|
|
58
|
+
|
|
59
|
+
// Update local state
|
|
60
|
+
currentTheme = newTheme;
|
|
61
|
+
updateThemeIcon(newTheme);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function updateThemeIcon(theme) {
|
|
66
|
+
const themeIcon = document.getElementById('theme-icon');
|
|
67
|
+
if (theme === 'dark') {
|
|
68
|
+
themeIcon.textContent = '☀️';
|
|
69
|
+
} else {
|
|
70
|
+
themeIcon.textContent = '🌙';
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// UI Utility Functions
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Display a toast notification
|
|
5
|
+
* @param {string} message - Message to display
|
|
6
|
+
* @param {string} type - Type of toast: 'success', 'error', 'info'
|
|
7
|
+
*/
|
|
8
|
+
export function showToast(message, type = 'success') {
|
|
9
|
+
const toast = document.getElementById('toast');
|
|
10
|
+
// Reset text content to remove potential icon junk
|
|
11
|
+
toast.textContent = message;
|
|
12
|
+
toast.className = `toast ${type}`;
|
|
13
|
+
toast.classList.add('show');
|
|
14
|
+
|
|
15
|
+
// Clear previous timeout if exists
|
|
16
|
+
if (toast.timeoutId) clearTimeout(toast.timeoutId);
|
|
17
|
+
|
|
18
|
+
toast.timeoutId = setTimeout(() => toast.classList.remove('show'), 3000);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Show loading state on button
|
|
23
|
+
* @param {HTMLElement} button - Button element
|
|
24
|
+
* @param {string} originalText - Original button HTML
|
|
25
|
+
*/
|
|
26
|
+
export function showLoading(button, originalText) {
|
|
27
|
+
button.disabled = true;
|
|
28
|
+
button.innerHTML = '<span class="loading"></span>';
|
|
29
|
+
button.dataset.originalText = originalText;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Reset button to original state
|
|
34
|
+
* @param {HTMLElement} button - Button element
|
|
35
|
+
*/
|
|
36
|
+
export function resetButton(button) {
|
|
37
|
+
button.disabled = false;
|
|
38
|
+
const originalText = button.dataset.originalText;
|
|
39
|
+
button.innerHTML = originalText;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Display API response in response area
|
|
44
|
+
* @param {string} elementId - ID of response element
|
|
45
|
+
* @param {Object} data - Response data
|
|
46
|
+
* @param {boolean} isError - Whether this is an error response
|
|
47
|
+
*/
|
|
48
|
+
export function showResponse(elementId, data, isError = false) {
|
|
49
|
+
const el = document.getElementById(elementId);
|
|
50
|
+
el.className = 'response show ' + (isError ? 'error' : 'success');
|
|
51
|
+
el.innerHTML = '<pre>' + JSON.stringify(data, null, 2) + '</pre>';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Update button state to show copied status
|
|
56
|
+
* @param {HTMLElement} button - Button element
|
|
57
|
+
* @param {HTMLElement} icon - Icon element
|
|
58
|
+
* @param {HTMLElement} text - Text element
|
|
59
|
+
* @param {string} originalIcon - Original icon text
|
|
60
|
+
* @param {string} originalText - Original button text
|
|
61
|
+
*/
|
|
62
|
+
export function showCopiedState(button, icon, text, originalIcon, originalText) {
|
|
63
|
+
button.classList.add('copied');
|
|
64
|
+
icon.textContent = '✓';
|
|
65
|
+
text.textContent = 'Copied';
|
|
66
|
+
|
|
67
|
+
setTimeout(() => {
|
|
68
|
+
button.classList.remove('copied');
|
|
69
|
+
icon.textContent = originalIcon;
|
|
70
|
+
text.textContent = originalText;
|
|
71
|
+
}, 2000);
|
|
72
|
+
}
|
|
Binary file
|
package/vg-coder-cli-1.0.17.tgz
DELETED
|
Binary file
|
package/vg-coder-cli-2.0.4.tgz
DELETED
|
Binary file
|
package/vg-coder-cli-2.0.5.tgz
DELETED
|
Binary file
|
package/vg-coder-cli-2.0.6.tgz
DELETED
|
Binary file
|
package/vg-coder-cli-2.0.7.tgz
DELETED
|
Binary file
|