vg-coder-cli 2.0.20 → 2.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/.vg/tree-state.json +9 -0
  2. package/package.json +5 -2
  3. package/scripts/build.js +49 -6
  4. package/src/index.js +4 -4
  5. package/src/server/api-server.js +83 -5
  6. package/src/server/views/css/structure.css +4 -1
  7. package/src/server/views/dashboard.css +51 -6
  8. package/src/server/views/dashboard.html +11 -3
  9. package/src/server/views/js/api.js +24 -0
  10. package/src/server/views/js/features/iframe-manager.js +2 -1
  11. package/src/server/views/js/features/resize.js +57 -0
  12. package/src/server/views/js/features/structure.js +109 -16
  13. package/src/server/views/js/main.js +36 -4
  14. package/src/server/views/vg-coder/background.js +48201 -2
  15. package/src/server/views/vg-coder/controller.js +496 -1
  16. package/src/server/views/vg-coder/manifest.json +13 -5
  17. package/src/server/views/vg-coder/{options.css → sidepanel.css} +34 -32
  18. package/src/server/views/vg-coder/{options.html → sidepanel.html} +2 -2
  19. package/src/server/views/vg-coder/sidepanel.js +347 -0
  20. package/vetgo-auto/README.md +3 -0
  21. package/vetgo-auto/chrome/CSP_IMPROVEMENTS.md +147 -0
  22. package/vetgo-auto/chrome/MANIFEST_V3_MIGRATION.md +123 -0
  23. package/vetgo-auto/chrome/assets/icon128.png +0 -0
  24. package/vetgo-auto/chrome/assets/icon16.png +0 -0
  25. package/vetgo-auto/chrome/assets/icon48.png +0 -0
  26. package/vetgo-auto/chrome/environments/environment.ts +13 -0
  27. package/vetgo-auto/chrome/manifest.json +66 -0
  28. package/vetgo-auto/chrome/rules.json +23 -0
  29. package/vetgo-auto/chrome/src/background.ts +200 -0
  30. package/vetgo-auto/chrome/src/controller.ts +98 -0
  31. package/vetgo-auto/chrome/src/controllers/common.firebase.ts +31 -0
  32. package/vetgo-auto/chrome/src/controllers/firebase-crud.ts +147 -0
  33. package/vetgo-auto/chrome/src/controllers/load-common-fuc.controller.ts +24 -0
  34. package/vetgo-auto/chrome/src/controllers/load-script.controller.ts +23 -0
  35. package/vetgo-auto/chrome/src/script-injector.ts +305 -0
  36. package/vetgo-auto/chrome/src/sidepanel.css +166 -0
  37. package/vetgo-auto/chrome/src/sidepanel.html +48 -0
  38. package/vetgo-auto/chrome/src/sidepanel.ts +127 -0
  39. package/vetgo-auto/chrome/src/utils/db-utils.ts +2 -0
  40. package/vetgo-auto/chrome/src/utils/environment-storage.service.ts +85 -0
  41. package/vetgo-auto/chrome/webpack.config.js +53 -0
  42. package/vetgo-auto/chrome/webpack.config.prod.js +54 -0
  43. package/vetgo-auto/package.json +30 -0
  44. package/vetgo-auto/tsconfig.json +27 -0
  45. package/vg-coder-cli-2.0.23.tgz +0 -0
  46. package/src/server/views/vg-coder/background.js.LICENSE.txt +0 -118
  47. package/src/server/views/vg-coder/options.js +0 -1
  48. package/vg-coder-cli-2.0.20.tgz +0 -0
  49. package/vg-coder-cli-2.0.21.tgz +0 -0
  50. package/vg-coder.zip +0 -0
@@ -0,0 +1,9 @@
1
+ {
2
+ "excludedPaths": [
3
+ "scripts/build.js",
4
+ "src/detectors/project-detector.js",
5
+ "src/exporter/html-exporter.js",
6
+ "src/ignore",
7
+ "src/ignore/ignore-manager.js"
8
+ ]
9
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vg-coder-cli",
3
- "version": "2.0.20",
3
+ "version": "2.0.23",
4
4
  "description": "🚀 CLI tool to analyze projects, concatenate source files, count tokens, and export HTML with syntax highlighting and copy functionality",
5
5
  "main": "src/index.js",
6
6
  "bin": {
@@ -13,6 +13,8 @@
13
13
  "test": "jest",
14
14
  "test:watch": "jest --watch",
15
15
  "dev": "nodemon src/index.js",
16
+ "build:extension": "cd vetgo-auto && npm run build",
17
+ "build:copy": "node scripts/build.js",
16
18
  "build": "node scripts/build.js",
17
19
  "push": "npm run build && npm pack && npm publish"
18
20
  },
@@ -44,6 +46,7 @@
44
46
  "ora": "^5.4.1",
45
47
  "path": "^0.12.7",
46
48
  "socket.io": "^4.7.2",
49
+ "socket.io-client": "^4.7.2",
47
50
  "tiktoken": "^1.0.10",
48
51
  "vg-coder-cli": "^2.0.15"
49
52
  },
@@ -56,4 +59,4 @@
56
59
  "engines": {
57
60
  "node": ">=16.0.0"
58
61
  }
59
- }
62
+ }
package/scripts/build.js CHANGED
@@ -1,29 +1,72 @@
1
1
  const AdmZip = require('adm-zip');
2
2
  const path = require('path');
3
3
  const fs = require('fs-extra');
4
+ const { execSync } = require('child_process');
4
5
 
5
6
  async function build() {
6
7
  try {
7
8
  const rootDir = path.resolve(__dirname, '..');
9
+ const extensionSourceDir = path.join(rootDir, 'vetgo-auto', 'chrome', 'dist');
10
+ const extensionWorkspaceDir = path.join(rootDir, 'vetgo-auto');
8
11
  const zipPath = path.join(rootDir, 'vg-coder.zip');
9
12
  const targetDir = path.join(rootDir, 'src', 'server', 'views', 'vg-coder');
10
13
 
11
14
  console.log('🏗️ Starting build process...');
12
15
 
13
- // 1. Check if zip exists
16
+ // Strategy 1: Try to build and copy from vetgo-auto/chrome/dist
17
+ if (fs.existsSync(extensionWorkspaceDir)) {
18
+ console.log('📦 Found vetgo-auto workspace. Building extension...');
19
+
20
+ try {
21
+ // Build the extension
22
+ console.log('🔨 Running: cd vetgo-auto && npm run build');
23
+ execSync('npm run build', {
24
+ cwd: extensionWorkspaceDir,
25
+ stdio: 'inherit'
26
+ });
27
+
28
+ // Check if dist directory exists
29
+ if (fs.existsSync(extensionSourceDir)) {
30
+ console.log('✅ Extension built successfully at:', extensionSourceDir);
31
+
32
+ // Clean old directory
33
+ if (fs.existsSync(targetDir)) {
34
+ console.log('🧹 Cleaning old extension directory...');
35
+ fs.removeSync(targetDir);
36
+ }
37
+
38
+ // Copy built extension
39
+ console.log('📋 Copying extension to:', targetDir);
40
+ fs.copySync(extensionSourceDir, targetDir);
41
+
42
+ console.log('✅ Extension copied successfully!');
43
+ console.log('🚀 Build completed successfully!');
44
+ return;
45
+ } else {
46
+ console.warn('⚠️ Extension dist directory not found. Falling back to zip extraction...');
47
+ }
48
+ } catch (buildError) {
49
+ console.warn('⚠️ Extension build failed:', buildError.message);
50
+ console.warn('⚠️ Falling back to zip extraction...');
51
+ }
52
+ } else {
53
+ console.log('ℹ️ vetgo-auto workspace not found. Using zip file...');
54
+ }
55
+
56
+ // Strategy 2: Fallback to zip extraction (for npm package users)
14
57
  if (!fs.existsSync(zipPath)) {
15
- console.error('⚠️ vg-coder.zip not found at root. Skipping extension extraction.');
16
- // We don't exit 1 here to allow build to continue if zip is missing in dev
17
- return;
58
+ console.error('vg-coder.zip not found and extension build failed.');
59
+ console.error(' Cannot proceed with build.');
60
+ process.exit(1);
18
61
  }
19
62
 
20
- // 2. Clean old directory
63
+ // Clean old directory
21
64
  if (fs.existsSync(targetDir)) {
22
65
  console.log('🧹 Cleaning old extension directory...');
23
66
  fs.removeSync(targetDir);
24
67
  }
25
68
 
26
- // 3. Unzip
69
+ // Unzip
27
70
  console.log('📦 Unzipping vg-coder.zip...');
28
71
  const zip = new AdmZip(zipPath);
29
72
  zip.extractAllTo(targetDir, true);
package/src/index.js CHANGED
@@ -372,13 +372,13 @@ class VGCoderCLI {
372
372
  */
373
373
  async handleStart(options) {
374
374
  try {
375
- const port = parseInt(options.port);
376
- const server = new ApiServer(port);
375
+ const initialPort = parseInt(options.port);
376
+ const server = new ApiServer(initialPort);
377
377
 
378
378
  await server.start();
379
379
 
380
- // Auto-open browser to dashboard
381
- const dashboardUrl = `http://localhost:${port}`;
380
+ // Auto-open browser to dashboard using actual port from server
381
+ const dashboardUrl = `http://localhost:${server.port}`;
382
382
  const { exec } = require('child_process');
383
383
  const platform = process.platform;
384
384
 
@@ -274,6 +274,52 @@ class ApiServer {
274
274
  }
275
275
  });
276
276
 
277
+ // --- TREE STATE API ---
278
+
279
+ // Save tree state (excluded paths)
280
+ this.app.post('/api/tree-state/save', async (req, res) => {
281
+ try {
282
+ const { excludedPaths } = req.body;
283
+ if (!Array.isArray(excludedPaths)) {
284
+ return res.status(400).json({ error: 'excludedPaths must be an array' });
285
+ }
286
+
287
+ // Create .vg directory if it doesn't exist
288
+ const vgDir = path.join(this.workingDir, '.vg');
289
+ await fs.ensureDir(vgDir);
290
+
291
+ // Save state to .vg/tree-state.json
292
+ const stateFile = path.join(vgDir, 'tree-state.json');
293
+ await fs.writeJson(stateFile, { excludedPaths }, { spaces: 2 });
294
+
295
+ console.log(chalk.green(`✓ Saved tree state: ${excludedPaths.length} excluded items`));
296
+ res.json({ success: true, count: excludedPaths.length });
297
+ } catch (error) {
298
+ console.error(chalk.red('❌ [TREE STATE SAVE] Error:'), error.message);
299
+ res.status(500).json({ error: error.message });
300
+ }
301
+ });
302
+
303
+ // Load tree state
304
+ this.app.get('/api/tree-state/load', async (req, res) => {
305
+ try {
306
+ const stateFile = path.join(this.workingDir, '.vg', 'tree-state.json');
307
+
308
+ // Check if state file exists
309
+ if (!await fs.pathExists(stateFile)) {
310
+ return res.json({ excludedPaths: [] });
311
+ }
312
+
313
+ // Read and return state
314
+ const state = await fs.readJson(stateFile);
315
+ res.json({ excludedPaths: state.excludedPaths || [] });
316
+ } catch (error) {
317
+ console.error(chalk.red('❌ [TREE STATE LOAD] Error:'), error.message);
318
+ // Return empty state on error instead of failing
319
+ res.json({ excludedPaths: [] });
320
+ }
321
+ });
322
+
277
323
  // --- GENERAL API ---
278
324
 
279
325
  this.app.post('/api/analyze', async (req, res) => {
@@ -327,11 +373,43 @@ class ApiServer {
327
373
  }
328
374
 
329
375
  async start() {
330
- return new Promise((resolve) => {
331
- this.server = this.httpServer.listen(this.port, () => {
332
- console.log(chalk.green(`\n🚀 VG Coder API Server & Socket.IO started on port ${this.port}`));
333
- resolve();
334
- });
376
+ return new Promise((resolve, reject) => {
377
+ const tryPort = (port) => {
378
+ const onError = (e) => {
379
+ if (e.code === 'EADDRINUSE') {
380
+ console.log(chalk.yellow(`⚠️ Port ${port} is busy, trying ${port + 1}...`));
381
+ this.httpServer.close();
382
+ tryPort(port + 1);
383
+ } else {
384
+ this.httpServer.removeListener('error', onError);
385
+ reject(e);
386
+ }
387
+ };
388
+
389
+ this.httpServer.once('error', onError);
390
+
391
+ this.server = this.httpServer.listen(port, () => {
392
+ this.httpServer.removeListener('error', onError);
393
+
394
+ // Update actual port
395
+ this.port = this.server.address().port;
396
+
397
+ const projectName = path.basename(this.workingDir);
398
+ const startTime = new Date().toLocaleString();
399
+
400
+ console.log(chalk.green('\n──────────────────────────────────────────────────'));
401
+ console.log(`🚀 ${chalk.bold('VG Coder Server')} ${chalk.green('● Online')}`);
402
+ console.log(chalk.gray('──────────────────────────────────────────────────'));
403
+ console.log(`📁 Project: ${chalk.cyan(projectName)}`);
404
+ console.log(`⏰ Started: ${chalk.yellow(startTime)}`);
405
+ console.log(`📡 URL: ${chalk.blue(`http://localhost:${this.port}`)}`);
406
+ console.log(chalk.green('──────────────────────────────────────────────────\n'));
407
+
408
+ resolve();
409
+ });
410
+ };
411
+
412
+ tryPort(this.port);
335
413
  });
336
414
  }
337
415
 
@@ -25,8 +25,9 @@
25
25
  font-size: 11px;
26
26
  /* Smaller tree font */
27
27
  overflow-x: auto;
28
- max-height: 400px;
28
+ max-height: 600px;
29
29
  overflow-y: auto;
30
+ width: 100%; /* Take full width */
30
31
  }
31
32
 
32
33
  .tree-ul {
@@ -58,6 +59,7 @@
58
59
  cursor: pointer;
59
60
  transition: background 0.1s;
60
61
  line-height: 1.2;
62
+ width: 100%; /* Ensure row takes full width */
61
63
  }
62
64
 
63
65
  .tree-item-row:hover {
@@ -99,6 +101,7 @@
99
101
  font-weight: 600;
100
102
  min-width: 30px;
101
103
  text-align: center;
104
+ flex-shrink: 0; /* Always keep badge visible */
102
105
  }
103
106
 
104
107
  .token-low {
@@ -61,32 +61,77 @@ body {
61
61
  height: 100%;
62
62
  overflow-y: auto;
63
63
  background: var(--ios-bg);
64
- border-right: 1px solid var(--ios-separator);
65
64
  position: relative;
66
65
  z-index: 10;
66
+ /* allow resize override */
67
+ flex: 0 0 450px;
68
+ }
69
+
70
+ /* Resize Handler */
71
+ .resize-handler {
72
+ width: 16px;
73
+ cursor: col-resize;
74
+ background: transparent;
75
+ z-index: 100;
76
+ margin-left: -3px; /* Overlap border */
77
+ position: relative;
78
+ }
79
+
80
+ .resize-handler:hover,
81
+ body.resizing .resize-handler {
82
+ background: var(--ios-blue);
83
+ opacity: 0.5;
84
+ }
85
+
86
+ body.resizing {
87
+ cursor: col-resize;
88
+ user-select: none;
67
89
  }
68
90
 
69
91
  .container {
70
92
  padding: 15px;
71
93
  padding-top: 15px;
94
+ padding-right: 0px;
72
95
  }
73
96
 
74
97
  /* --- COMPONENT STYLES --- */
75
98
  .header {
76
99
  display: flex;
77
100
  justify-content: space-between;
101
+ align-items: center; /* Align items vertically center */
78
102
  margin-bottom: 15px;
79
103
  }
80
104
 
81
- .header h1 {
82
- font-size: 20px;
83
- font-weight: 700;
84
- margin: 0;
105
+ .header-content {
106
+ display: flex;
107
+ align-items: center;
108
+ gap: 12px;
85
109
  }
86
110
 
87
111
  .status {
88
- font-size: 11px;
112
+ font-size: 14px;
89
113
  color: var(--ios-green);
114
+ line-height: 1;
115
+ }
116
+
117
+ /* NEW: Project Info Styles */
118
+ .project-info {
119
+ display: flex;
120
+ flex-direction: column;
121
+ justify-content: center;
122
+ line-height: 1.2;
123
+ }
124
+
125
+ .project-name {
126
+ font-weight: 700;
127
+ font-size: 16px;
128
+ color: var(--text-primary);
129
+ }
130
+
131
+ .project-meta {
132
+ font-size: 11px;
133
+ color: var(--text-secondary);
134
+ font-family: monospace;
90
135
  }
91
136
 
92
137
  .theme-toggle {
@@ -62,8 +62,14 @@
62
62
  <div class="container">
63
63
  <div class="header">
64
64
  <div class="header-content">
65
- <span class="status" id="status">● Server Starting...</span>
66
- <div style="height: 5px;"></div>
65
+ <!-- Status Dot -->
66
+ <span class="status" id="status" style="font-size: 14px;">●</span>
67
+
68
+ <!-- NEW: Project Info Section -->
69
+ <div class="project-info">
70
+ <div class="project-name" id="project-name">Loading...</div>
71
+ <div class="project-meta" id="project-meta">...</div>
72
+ </div>
67
73
  </div>
68
74
  <button class="theme-toggle" id="theme-toggle" title="Toggle Dark Mode">
69
75
  <span id="theme-icon">🌙</span>
@@ -180,6 +186,8 @@
180
186
  <div style="height: 50px;"></div>
181
187
  </div>
182
188
  </div>
189
+ <!-- Resize Handler -->
190
+ <div id="resize-handler" class="resize-handler"></div>
183
191
 
184
192
  <!-- CỘT PHẢI: AI Iframe & Editor -->
185
193
  <div class="right-panel">
@@ -275,4 +283,4 @@
275
283
  <script type="module" src="/js/main.js"></script>
276
284
  </body>
277
285
 
278
- </html>
286
+ </html>
@@ -100,6 +100,30 @@ export async function commitChanges(message) {
100
100
  return true;
101
101
  }
102
102
 
103
+ // --- Tree State API ---
104
+
105
+ export async function saveTreeState(excludedPaths) {
106
+ const res = await fetch(`${API_BASE}/api/tree-state/save`, {
107
+ method: 'POST',
108
+ headers: { 'Content-Type': 'application/json' },
109
+ body: JSON.stringify({ excludedPaths })
110
+ });
111
+ if (!res.ok) {
112
+ const data = await res.json();
113
+ throw new Error(data.error || 'Failed to save tree state');
114
+ }
115
+ return await res.json();
116
+ }
117
+
118
+ export async function loadTreeState() {
119
+ const res = await fetch(`${API_BASE}/api/tree-state/load`);
120
+ if (!res.ok) {
121
+ const data = await res.json();
122
+ throw new Error(data.error || 'Failed to load tree state');
123
+ }
124
+ return await res.json();
125
+ }
126
+
103
127
  // ------------------------
104
128
 
105
129
  export async function copyAsFile(filename, content) {
@@ -3,7 +3,8 @@ const AI_PROVIDERS = [
3
3
  { id: 'kimi', name: 'Kimi AI', url: 'https://www.kimi.com' },
4
4
  { id: 'deepseek', name: 'DeepSeek', url: 'https://chat.deepseek.com' },
5
5
  { id: 'gemini', name: 'Google Gemini', url: 'https://gemini.google.com/app' },
6
- { id: 'aistudio', name: 'Google AI Studio', url: 'https://aistudio.google.com/prompts/new_chat' }
6
+ { id: 'aistudio', name: 'Google AI Studio', url: 'https://aistudio.google.com/prompts/new_chat' },
7
+ { id: 'gork', name: 'Gork', url: 'https://grok.com' },
7
8
  ];
8
9
 
9
10
  export function initIframeManager() {
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Feature: Left Panel Resize
3
+ * Allows the user to drag the right edge of the left panel to resize it.
4
+ */
5
+
6
+ export function initResizeHandler() {
7
+ const leftPanel = document.querySelector('.left-panel');
8
+ const handle = document.getElementById('resize-handler'); // Match the ID we will add in HTML
9
+ const splitLayout = document.querySelector('.split-layout');
10
+
11
+ if (!leftPanel || !handle) {
12
+ console.warn('Resize elements not found');
13
+ return;
14
+ }
15
+
16
+ let isResizing = false;
17
+ let startX = 0;
18
+ let startWidth = 0;
19
+
20
+ // Mouse Down
21
+ handle.addEventListener('mousedown', (e) => {
22
+ isResizing = true;
23
+ startX = e.clientX;
24
+ startWidth = leftPanel.getBoundingClientRect().width;
25
+
26
+ // Add resizing class for styling/cursor
27
+ document.body.classList.add('resizing');
28
+
29
+ // Disable text selection during drag
30
+ e.preventDefault();
31
+ });
32
+
33
+ // Mouse Move
34
+ document.addEventListener('mousemove', (e) => {
35
+ if (!isResizing) return;
36
+
37
+ requestAnimationFrame(() => {
38
+ const currentX = e.clientX;
39
+ const diffX = currentX - startX;
40
+ const newWidth = Math.max(250, startWidth + diffX); // Min width 250px
41
+ const maxWidth = window.innerWidth - 300; // Leave space for right panel
42
+
43
+ if (newWidth < maxWidth) {
44
+ leftPanel.style.flex = `0 0 ${newWidth}px`;
45
+ leftPanel.style.width = `${newWidth}px`;
46
+ }
47
+ });
48
+ });
49
+
50
+ // Mouse Up
51
+ document.addEventListener('mouseup', () => {
52
+ if (isResizing) {
53
+ isResizing = false;
54
+ document.body.classList.remove('resizing');
55
+ }
56
+ });
57
+ }