vg-coder-cli 2.0.31 → 2.0.32
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/ARCHITECTURE.md +255 -0
- package/README.md +0 -11
- package/change.sh +0 -0
- package/dist/vg-coder-bundle.js +42 -0
- package/gulpfile.js +111 -0
- package/package.json +19 -11
- package/src/index.js +28 -220
- package/src/server/api-server.js +120 -428
- package/src/server/views/css/bubble.css +81 -0
- package/src/server/views/css/code-viewer.css +58 -0
- package/src/server/views/css/terminal.css +59 -155
- package/src/server/views/dashboard.css +78 -678
- package/src/server/views/dashboard.html +39 -278
- package/src/server/views/js/api.js +2 -22
- package/src/server/views/js/config.js +27 -15
- package/src/server/views/js/event-protocol.js +263 -0
- package/src/server/views/js/features/bubble-features/index.js +125 -0
- package/src/server/views/js/features/bubble-features/paste-run-feature.js +16 -0
- package/src/server/views/js/features/bubble-features/terminal-feature.js +16 -0
- package/src/server/views/js/features/bubble.js +175 -0
- package/src/server/views/js/features/code-viewer.js +90 -0
- package/src/server/views/js/features/commands.js +34 -81
- package/src/server/views/js/features/editor-tabs.js +19 -46
- package/src/server/views/js/features/git-view.js +63 -81
- package/src/server/views/js/features/iframe-manager.js +3 -97
- package/src/server/views/js/features/monaco-manager.js +19 -39
- package/src/server/views/js/features/project-switcher.js +7 -63
- package/src/server/views/js/features/resize.js +5 -16
- package/src/server/views/js/features/structure.js +38 -106
- package/src/server/views/js/features/terminal.js +102 -418
- package/src/server/views/js/handlers.js +60 -43
- package/src/server/views/js/main.js +75 -179
- package/src/server/views/js/shadow-entry.js +21 -0
- package/src/server/views/js/utils.js +48 -28
- package/src/server/views/vg-coder/_metadata/generated_indexed_rulesets/_ruleset1 +0 -0
- package/src/server/views/vg-coder/controller.js +33 -258
- package/vetgo-auto/chrome/src/utils/injector-script.ts +33 -258
- package/vetgo-auto/vg-coder.zip +0 -0
- package/src/server/views/dashboard.js +0 -457
- package/test-pty.js +0 -31
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
import { getStructure, analyzeProject, copyToClipboard, saveTreeState as apiSaveTreeState, loadTreeState as apiLoadTreeState } from '../api.js';
|
|
2
|
-
import { showToast, showLoading, resetButton, showResponse, formatNumber, showCopiedState } from '../utils.js';
|
|
2
|
+
import { showToast, showLoading, resetButton, showResponse, formatNumber, showCopiedState, getById, qsa } from '../utils.js';
|
|
3
3
|
|
|
4
|
-
// Global variable to store current structure data
|
|
5
4
|
let currentStructureData = null;
|
|
5
|
+
let excludedPaths = new Set();
|
|
6
|
+
let saveStateTimeout = null;
|
|
6
7
|
|
|
7
|
-
//
|
|
8
|
-
let excludedPaths = new Set(); // Paths that are unchecked
|
|
9
|
-
let saveStateTimeout = null; // Debounce timer for auto-save
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Handle Structure button click logic
|
|
13
|
-
*/
|
|
8
|
+
// Exported function for Handler
|
|
14
9
|
export async function handleStructureView(event) {
|
|
15
10
|
const btn = event.target.closest('.btn');
|
|
16
|
-
const pathInput =
|
|
17
|
-
const treeContainer =
|
|
18
|
-
const treeContent =
|
|
19
|
-
const errorContainer =
|
|
11
|
+
const pathInput = getById('structure-path');
|
|
12
|
+
const treeContainer = getById('structure-tree');
|
|
13
|
+
const treeContent = getById('tree-content');
|
|
14
|
+
const errorContainer = getById('structure-response');
|
|
20
15
|
|
|
16
|
+
if (!pathInput || !treeContainer || !treeContent || !errorContainer) {
|
|
17
|
+
console.error('Structure elements not found');
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
21
|
const path = pathInput.value;
|
|
22
22
|
|
|
23
23
|
showLoading(btn, btn.innerHTML);
|
|
@@ -28,13 +28,10 @@ export async function handleStructureView(event) {
|
|
|
28
28
|
const data = await getStructure(path);
|
|
29
29
|
currentStructureData = data.structure;
|
|
30
30
|
|
|
31
|
-
// Load saved state before rendering
|
|
32
31
|
await loadTreeState();
|
|
33
32
|
|
|
34
|
-
// Render Tree HTML using recursive function
|
|
35
33
|
treeContent.innerHTML = generateTreeHtml(data.structure);
|
|
36
34
|
|
|
37
|
-
// Initial token update
|
|
38
35
|
updateTotalTokens();
|
|
39
36
|
|
|
40
37
|
treeContainer.style.display = 'block';
|
|
@@ -48,37 +45,26 @@ export async function handleStructureView(event) {
|
|
|
48
45
|
resetButton(btn);
|
|
49
46
|
}
|
|
50
47
|
|
|
51
|
-
/**
|
|
52
|
-
* Toggle folder collapse/expand
|
|
53
|
-
* Only triggers if clicked on row but NOT on checkbox
|
|
54
|
-
*/
|
|
55
48
|
export function handleToggleFolder(event) {
|
|
56
49
|
if (event.target.type === 'checkbox') return;
|
|
57
|
-
|
|
58
|
-
// Find closest parent LI
|
|
59
50
|
const li = event.currentTarget.closest('.tree-li');
|
|
60
51
|
if (li && li.classList.contains('has-children')) {
|
|
61
52
|
li.classList.toggle('collapsed');
|
|
62
53
|
}
|
|
63
54
|
}
|
|
64
55
|
|
|
65
|
-
/**
|
|
66
|
-
* Handle Checkbox Logic (Parent <-> Child sync) & Update Token Total
|
|
67
|
-
*/
|
|
68
56
|
export function handleCheckboxChange(event) {
|
|
69
57
|
event.stopPropagation();
|
|
70
58
|
const checkbox = event.target;
|
|
71
59
|
const isChecked = checkbox.checked;
|
|
72
60
|
const path = checkbox.dataset.path;
|
|
73
61
|
|
|
74
|
-
// 1. Update excluded paths set
|
|
75
62
|
if (isChecked) {
|
|
76
63
|
excludedPaths.delete(path);
|
|
77
64
|
} else {
|
|
78
65
|
excludedPaths.add(path);
|
|
79
66
|
}
|
|
80
67
|
|
|
81
|
-
// 2. Sync Children: If this is a folder, update all children checkboxes
|
|
82
68
|
const li = checkbox.closest('.tree-li');
|
|
83
69
|
if (li) {
|
|
84
70
|
const childrenCheckboxes = li.querySelectorAll('.tree-checkbox');
|
|
@@ -93,54 +79,39 @@ export function handleCheckboxChange(event) {
|
|
|
93
79
|
});
|
|
94
80
|
}
|
|
95
81
|
|
|
96
|
-
// 3. Recalculate Tokens
|
|
97
82
|
updateTotalTokens();
|
|
98
|
-
|
|
99
|
-
// 4. Auto-save state (debounced)
|
|
100
83
|
debouncedSaveState();
|
|
101
84
|
}
|
|
102
85
|
|
|
103
|
-
/**
|
|
104
|
-
* Calculate total tokens of CHECKED files only
|
|
105
|
-
*/
|
|
106
86
|
function updateTotalTokens() {
|
|
107
|
-
|
|
108
|
-
const checkedFiles = document.querySelectorAll('.tree-checkbox[data-type="file"]:checked');
|
|
109
|
-
|
|
87
|
+
const checkedFiles = qsa('.tree-checkbox[data-type="file"]:checked');
|
|
110
88
|
let total = 0;
|
|
111
89
|
checkedFiles.forEach(box => {
|
|
112
90
|
const tokens = parseInt(box.dataset.tokens || '0');
|
|
113
91
|
total += tokens;
|
|
114
92
|
});
|
|
115
93
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
badge.style.color = ''; // reset to default
|
|
94
|
+
const badge = getById('total-tokens-badge');
|
|
95
|
+
if (badge) {
|
|
96
|
+
badge.textContent = `${formatNumber(total)} tokens`;
|
|
97
|
+
if (total === 0) {
|
|
98
|
+
badge.style.color = 'var(--ios-gray)';
|
|
99
|
+
} else {
|
|
100
|
+
badge.style.color = '';
|
|
101
|
+
}
|
|
125
102
|
}
|
|
126
103
|
}
|
|
127
104
|
|
|
128
|
-
/**
|
|
129
|
-
* Copy Content of Selected Files (via API)
|
|
130
|
-
*/
|
|
131
105
|
export async function handleCopySelected(event) {
|
|
132
106
|
const btn = event.target.closest('.btn-copy') || event.target.closest('.btn-icon-head');
|
|
133
|
-
const icon =
|
|
134
|
-
const text =
|
|
107
|
+
const icon = getById('copy-structure-icon') || btn;
|
|
108
|
+
const text = getById('copy-structure-text') || { textContent: '' };
|
|
135
109
|
|
|
136
|
-
|
|
137
|
-
const checkedBoxes = document.querySelectorAll('.tree-checkbox[data-type="file"]:checked');
|
|
110
|
+
const checkedBoxes = qsa('.tree-checkbox[data-type="file"]:checked');
|
|
138
111
|
const checkedPaths = [];
|
|
139
112
|
|
|
140
113
|
checkedBoxes.forEach(box => {
|
|
141
|
-
if (box.dataset.path)
|
|
142
|
-
checkedPaths.push(box.dataset.path);
|
|
143
|
-
}
|
|
114
|
+
if (box.dataset.path) checkedPaths.push(box.dataset.path);
|
|
144
115
|
});
|
|
145
116
|
|
|
146
117
|
if (checkedPaths.length === 0) {
|
|
@@ -148,30 +119,23 @@ export async function handleCopySelected(event) {
|
|
|
148
119
|
return;
|
|
149
120
|
}
|
|
150
121
|
|
|
151
|
-
// Save original button state
|
|
152
|
-
const originalText = btn.innerHTML;
|
|
153
122
|
if (btn.classList.contains('btn-copy')) {
|
|
154
123
|
showLoading(btn, btn.innerHTML);
|
|
155
124
|
} else {
|
|
156
|
-
// For header icon, just show visual feedback
|
|
157
125
|
btn.style.opacity = '0.5';
|
|
158
126
|
}
|
|
159
127
|
|
|
160
128
|
try {
|
|
161
|
-
const
|
|
129
|
+
const pathInput = getById('structure-path');
|
|
130
|
+
const path = pathInput ? pathInput.value : '.';
|
|
162
131
|
|
|
163
|
-
// 2. Call Analyze API with specific files
|
|
164
132
|
const content = await analyzeProject(path, checkedPaths);
|
|
165
|
-
|
|
166
|
-
// 3. Copy to clipboard
|
|
167
133
|
await copyToClipboard(content);
|
|
168
134
|
|
|
169
|
-
// UI Feedback
|
|
170
135
|
if (btn.classList.contains('btn-copy')) {
|
|
171
136
|
showCopiedState(btn, icon, text, '📋', 'Copy Selected');
|
|
172
137
|
resetButton(btn);
|
|
173
138
|
} else {
|
|
174
|
-
// Header icon feedback
|
|
175
139
|
btn.style.opacity = '1';
|
|
176
140
|
const originalIcon = btn.textContent;
|
|
177
141
|
btn.textContent = '✓';
|
|
@@ -187,20 +151,13 @@ export async function handleCopySelected(event) {
|
|
|
187
151
|
}
|
|
188
152
|
}
|
|
189
153
|
|
|
190
|
-
/**
|
|
191
|
-
* Recursive function to generate Tree HTML with Checkboxes
|
|
192
|
-
*/
|
|
193
154
|
function generateTreeHtml(node) {
|
|
194
155
|
if (!node) return '';
|
|
195
156
|
|
|
196
|
-
// --- COMPACT FOLDER LOGIC ---
|
|
197
157
|
let currentNode = node;
|
|
198
158
|
let displayName = node.name;
|
|
199
|
-
let isCompact = false;
|
|
200
159
|
|
|
201
|
-
// Only compact if it's a directory
|
|
202
160
|
if (currentNode.type === 'directory') {
|
|
203
|
-
// While current node has EXACTLY one child and that child is a directory
|
|
204
161
|
while (
|
|
205
162
|
currentNode.children &&
|
|
206
163
|
currentNode.children.length === 1 &&
|
|
@@ -208,30 +165,22 @@ function generateTreeHtml(node) {
|
|
|
208
165
|
) {
|
|
209
166
|
const child = currentNode.children[0];
|
|
210
167
|
displayName += '/' + child.name;
|
|
211
|
-
currentNode = child;
|
|
212
|
-
isCompact = true;
|
|
168
|
+
currentNode = child;
|
|
213
169
|
}
|
|
214
170
|
}
|
|
215
171
|
|
|
216
|
-
// Now uses 'currentNode' for properties (it's the deepest folder in the chain)
|
|
217
|
-
// But we use 'displayName' for the UI
|
|
218
|
-
// 'tokens' should be from the root node of this chain (usually same as leaf for folders)
|
|
219
|
-
|
|
220
172
|
const isDir = currentNode.type === 'directory';
|
|
221
173
|
const hasChildren = isDir && currentNode.children && currentNode.children.length > 0;
|
|
222
|
-
|
|
223
|
-
// Determine Token Color (Use original node's tokens or deep node's tokens - they should be identical)
|
|
224
174
|
const tokens = currentNode.tokens || 0;
|
|
175
|
+
|
|
225
176
|
let tokenClass = 'token-low';
|
|
226
177
|
if (tokens > 5000) tokenClass = 'token-high';
|
|
227
178
|
else if (tokens > 2000) tokenClass = 'token-med';
|
|
228
179
|
|
|
229
|
-
// Icon
|
|
230
180
|
const icon = isDir ? (hasChildren ? '📁' : '📂') : '📄';
|
|
231
181
|
const arrow = hasChildren ? '▼' : '';
|
|
232
182
|
const liClass = `tree-li ${hasChildren ? 'has-children' : ''}`;
|
|
233
183
|
|
|
234
|
-
// Actions
|
|
235
184
|
let clickAction = '';
|
|
236
185
|
let cursorStyle = '';
|
|
237
186
|
|
|
@@ -241,17 +190,13 @@ function generateTreeHtml(node) {
|
|
|
241
190
|
cursorStyle = 'cursor: pointer;';
|
|
242
191
|
}
|
|
243
192
|
} else {
|
|
244
|
-
// File click -> Open in Editor
|
|
245
|
-
// Escape backslashes for Windows paths
|
|
246
193
|
const safePath = (currentNode.relativePath || currentNode.path).replace(/\\/g, '\\\\');
|
|
247
194
|
clickAction = `onclick="window.openFileTab('${safePath}', '${currentNode.name}')"`;
|
|
248
195
|
cursorStyle = 'cursor: pointer; color: var(--text-primary);';
|
|
249
196
|
}
|
|
250
197
|
|
|
251
|
-
// Build HTML
|
|
252
198
|
let html = `<li class="${liClass}">`;
|
|
253
199
|
|
|
254
|
-
// Check if this path should be excluded (unchecked)
|
|
255
200
|
const nodePath = currentNode.relativePath || currentNode.path;
|
|
256
201
|
const isExcluded = excludedPaths.has(nodePath);
|
|
257
202
|
|
|
@@ -270,10 +215,8 @@ function generateTreeHtml(node) {
|
|
|
270
215
|
</div>
|
|
271
216
|
`;
|
|
272
217
|
|
|
273
|
-
// Children recursion (using deepest node's children)
|
|
274
218
|
if (hasChildren) {
|
|
275
219
|
html += '<ul class="tree-ul">';
|
|
276
|
-
// Sort: Folders first, then files
|
|
277
220
|
currentNode.children.forEach(child => {
|
|
278
221
|
html += generateTreeHtml(child);
|
|
279
222
|
});
|
|
@@ -281,48 +224,37 @@ function generateTreeHtml(node) {
|
|
|
281
224
|
}
|
|
282
225
|
|
|
283
226
|
html += '</li>';
|
|
284
|
-
|
|
285
227
|
return isDir ? `<ul class="tree-ul">${html}</ul>` : html;
|
|
286
228
|
}
|
|
287
229
|
|
|
288
|
-
/**
|
|
289
|
-
* Load tree state from backend
|
|
290
|
-
*/
|
|
291
230
|
async function loadTreeState() {
|
|
292
231
|
try {
|
|
293
232
|
const data = await apiLoadTreeState();
|
|
294
233
|
excludedPaths = new Set(data.excludedPaths || []);
|
|
295
|
-
console.log(`Loaded tree state: ${excludedPaths.size} excluded items`);
|
|
296
234
|
} catch (err) {
|
|
297
235
|
console.error('Failed to load tree state:', err);
|
|
298
|
-
excludedPaths = new Set();
|
|
236
|
+
excludedPaths = new Set();
|
|
299
237
|
}
|
|
300
238
|
}
|
|
301
239
|
|
|
302
|
-
/**
|
|
303
|
-
* Debounced save - waits 500ms after last change before saving
|
|
304
|
-
*/
|
|
305
240
|
function debouncedSaveState() {
|
|
306
|
-
|
|
307
|
-
if (saveStateTimeout) {
|
|
308
|
-
clearTimeout(saveStateTimeout);
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
// Set new timeout
|
|
241
|
+
if (saveStateTimeout) clearTimeout(saveStateTimeout);
|
|
312
242
|
saveStateTimeout = setTimeout(() => {
|
|
313
243
|
saveTreeState();
|
|
314
244
|
}, 500);
|
|
315
245
|
}
|
|
316
246
|
|
|
317
|
-
/**
|
|
318
|
-
* Save current tree state to backend
|
|
319
|
-
*/
|
|
320
247
|
async function saveTreeState() {
|
|
321
248
|
try {
|
|
322
249
|
const excludedArray = Array.from(excludedPaths);
|
|
323
250
|
await apiSaveTreeState(excludedArray);
|
|
324
|
-
console.log(`Saved tree state: ${excludedArray.length} excluded items`);
|
|
325
251
|
} catch (err) {
|
|
326
252
|
console.error('Failed to save tree state:', err);
|
|
327
253
|
}
|
|
328
254
|
}
|
|
255
|
+
|
|
256
|
+
// FIX: Expose functions to window so HTML onclick works
|
|
257
|
+
window.testStructure = handleStructureView;
|
|
258
|
+
window.toggleFolder = handleToggleFolder;
|
|
259
|
+
window.handleCheckboxChange = handleCheckboxChange;
|
|
260
|
+
window.copySelectedStructure = handleCopySelected;
|