vg-coder-cli 2.0.20 → 2.0.22

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vg-coder-cli",
3
- "version": "2.0.20",
3
+ "version": "2.0.22",
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": {
@@ -44,6 +44,7 @@
44
44
  "ora": "^5.4.1",
45
45
  "path": "^0.12.7",
46
46
  "socket.io": "^4.7.2",
47
+ "socket.io-client": "^4.7.2",
47
48
  "tiktoken": "^1.0.10",
48
49
  "vg-coder-cli": "^2.0.15"
49
50
  },
@@ -56,4 +57,4 @@
56
57
  "engines": {
57
58
  "node": ">=16.0.0"
58
59
  }
59
- }
60
+ }
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
 
@@ -327,11 +327,43 @@ class ApiServer {
327
327
  }
328
328
 
329
329
  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
- });
330
+ return new Promise((resolve, reject) => {
331
+ const tryPort = (port) => {
332
+ const onError = (e) => {
333
+ if (e.code === 'EADDRINUSE') {
334
+ console.log(chalk.yellow(`āš ļø Port ${port} is busy, trying ${port + 1}...`));
335
+ this.httpServer.close();
336
+ tryPort(port + 1);
337
+ } else {
338
+ this.httpServer.removeListener('error', onError);
339
+ reject(e);
340
+ }
341
+ };
342
+
343
+ this.httpServer.once('error', onError);
344
+
345
+ this.server = this.httpServer.listen(port, () => {
346
+ this.httpServer.removeListener('error', onError);
347
+
348
+ // Update actual port
349
+ this.port = this.server.address().port;
350
+
351
+ const projectName = path.basename(this.workingDir);
352
+ const startTime = new Date().toLocaleString();
353
+
354
+ console.log(chalk.green('\n──────────────────────────────────────────────────'));
355
+ console.log(`šŸš€ ${chalk.bold('VG Coder Server')} ${chalk.green('ā— Online')}`);
356
+ console.log(chalk.gray('──────────────────────────────────────────────────'));
357
+ console.log(`šŸ“ Project: ${chalk.cyan(projectName)}`);
358
+ console.log(`ā° Started: ${chalk.yellow(startTime)}`);
359
+ console.log(`šŸ“” URL: ${chalk.blue(`http://localhost:${this.port}`)}`);
360
+ console.log(chalk.green('──────────────────────────────────────────────────\n'));
361
+
362
+ resolve();
363
+ });
364
+ };
365
+
366
+ tryPort(this.port);
335
367
  });
336
368
  }
337
369
 
@@ -75,18 +75,40 @@ body {
75
75
  .header {
76
76
  display: flex;
77
77
  justify-content: space-between;
78
+ align-items: center; /* Align items vertically center */
78
79
  margin-bottom: 15px;
79
80
  }
80
81
 
81
- .header h1 {
82
- font-size: 20px;
83
- font-weight: 700;
84
- margin: 0;
82
+ .header-content {
83
+ display: flex;
84
+ align-items: center;
85
+ gap: 12px;
85
86
  }
86
87
 
87
88
  .status {
88
- font-size: 11px;
89
+ font-size: 14px;
89
90
  color: var(--ios-green);
91
+ line-height: 1;
92
+ }
93
+
94
+ /* NEW: Project Info Styles */
95
+ .project-info {
96
+ display: flex;
97
+ flex-direction: column;
98
+ justify-content: center;
99
+ line-height: 1.2;
100
+ }
101
+
102
+ .project-name {
103
+ font-weight: 700;
104
+ font-size: 16px;
105
+ color: var(--text-primary);
106
+ }
107
+
108
+ .project-meta {
109
+ font-size: 11px;
110
+ color: var(--text-secondary);
111
+ font-family: monospace;
90
112
  }
91
113
 
92
114
  .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>
@@ -275,4 +281,4 @@
275
281
  <script type="module" src="/js/main.js"></script>
276
282
  </body>
277
283
 
278
- </html>
284
+ </html>
@@ -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() {
@@ -16,6 +16,9 @@ document.addEventListener('DOMContentLoaded', async () => {
16
16
  // Check server status
17
17
  await checkServerStatus();
18
18
 
19
+ // Load Project Info
20
+ await loadProjectInfo();
21
+
19
22
  // Initialize Theme
20
23
  initTheme();
21
24
 
@@ -46,16 +49,40 @@ async function checkServerStatus() {
46
49
  const isHealthy = await checkHealth();
47
50
 
48
51
  if (isHealthy) {
49
- statusEl.textContent = 'ā— Online';
50
- statusEl.style.background = 'rgba(52, 199, 89, 0.15)';
52
+ statusEl.textContent = 'ā—';
53
+ statusEl.style.background = 'transparent';
51
54
  statusEl.style.color = 'var(--ios-green)';
52
55
  } else {
53
- statusEl.textContent = 'ā— Offline';
54
- statusEl.style.background = 'rgba(255, 59, 48, 0.15)';
56
+ statusEl.textContent = 'ā—';
57
+ statusEl.style.background = 'transparent';
55
58
  statusEl.style.color = 'var(--ios-red)';
56
59
  }
57
60
  }
58
61
 
62
+ async function loadProjectInfo() {
63
+ try {
64
+ // Fetch info for current directory (.)
65
+ const res = await fetch('/api/info?path=.');
66
+ const data = await res.json();
67
+
68
+ const projectNameEl = document.getElementById('project-name');
69
+ const projectMetaEl = document.getElementById('project-meta');
70
+
71
+ // Extract folder name from path
72
+ const fullPath = data.path;
73
+ // Handle both Windows (\) and Unix (/) paths
74
+ const folderName = fullPath.split(/[\\/]/).pop();
75
+
76
+ projectNameEl.textContent = folderName;
77
+ projectMetaEl.textContent = `${data.primaryType} • ${fullPath}`;
78
+
79
+ } catch (err) {
80
+ console.error('Failed to load project info:', err);
81
+ document.getElementById('project-name').textContent = 'Unknown Project';
82
+ document.getElementById('project-meta').textContent = 'Error loading info';
83
+ }
84
+ }
85
+
59
86
  function initTheme() {
60
87
  const themeBtn = document.getElementById('theme-toggle');
61
88
  let currentTheme = localStorage.getItem('theme') || 'light';
Binary file
Binary file
Binary file