vg-coder-cli 2.0.37 → 2.0.38

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.37",
3
+ "version": "2.0.38",
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": {
@@ -16,7 +16,7 @@
16
16
  "dev": "nodemon src/index.js",
17
17
  "build:extension": "cd vetgo-auto && npm run build",
18
18
  "build:copy": "node scripts/build.js",
19
- "build": "npm run build:inject && npm run install:local",
19
+ "build": "npm run build:extension && npm run build:copy && npm run build:inject && npm run install:local",
20
20
  "push": "npm run build && npm pack && npm publish",
21
21
  "build:inject": "gulp"
22
22
  },
@@ -41,6 +41,8 @@
41
41
  "fs-extra": "^11.3.3",
42
42
  "highlight.js": "^11.9.0",
43
43
  "ignore": "^5.3.0",
44
+ "markdown-it": "^14.0.0",
45
+ "mermaid": "^11.4.1",
44
46
  "node-pty": "^1.1.0",
45
47
  "ora": "^5.4.1",
46
48
  "path": "^0.12.7",
@@ -56,3 +56,218 @@
56
56
  color: var(--ios-red, #ff3b30);
57
57
  font-family: monospace;
58
58
  }
59
+
60
+ /* Markdown Styles */
61
+ .cv-markdown {
62
+ background: var(--ios-bg, #0d1117);
63
+ padding: 20px;
64
+ min-height: 100%;
65
+ }
66
+
67
+ .markdown-body {
68
+ color: var(--text-primary, #c9d1d9);
69
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif;
70
+ font-size: 14px;
71
+ line-height: 1.6;
72
+ max-width: 980px;
73
+ word-wrap: break-word;
74
+ }
75
+
76
+ /* Headers */
77
+ .markdown-body h1,
78
+ .markdown-body h2,
79
+ .markdown-body h3,
80
+ .markdown-body h4,
81
+ .markdown-body h5,
82
+ .markdown-body h6 {
83
+ margin-top: 24px;
84
+ margin-bottom: 16px;
85
+ font-weight: 600;
86
+ line-height: 1.25;
87
+ color: var(--text-primary, #c9d1d9);
88
+ }
89
+
90
+ .markdown-body h1 {
91
+ font-size: 2em;
92
+ border-bottom: 1px solid var(--border-color, #30363d);
93
+ padding-bottom: 0.3em;
94
+ }
95
+
96
+ .markdown-body h2 {
97
+ font-size: 1.5em;
98
+ border-bottom: 1px solid var(--border-color, #30363d);
99
+ padding-bottom: 0.3em;
100
+ }
101
+
102
+ .markdown-body h3 { font-size: 1.25em; }
103
+ .markdown-body h4 { font-size: 1em; }
104
+ .markdown-body h5 { font-size: 0.875em; }
105
+ .markdown-body h6 { font-size: 0.85em; color: var(--text-secondary, #8b949e); }
106
+
107
+ /* Paragraphs */
108
+ .markdown-body p {
109
+ margin-top: 0;
110
+ margin-bottom: 16px;
111
+ }
112
+
113
+ /* Lists */
114
+ .markdown-body ul,
115
+ .markdown-body ol {
116
+ margin-top: 0;
117
+ margin-bottom: 16px;
118
+ padding-left: 2em;
119
+ }
120
+
121
+ .markdown-body li {
122
+ margin-top: 0.25em;
123
+ }
124
+
125
+ .markdown-body li > p {
126
+ margin-top: 16px;
127
+ }
128
+
129
+ .markdown-body li + li {
130
+ margin-top: 0.25em;
131
+ }
132
+
133
+ /* Code */
134
+ .markdown-body code {
135
+ padding: 0.2em 0.4em;
136
+ margin: 0;
137
+ font-size: 85%;
138
+ background-color: rgba(110, 118, 129, 0.4);
139
+ border-radius: 6px;
140
+ font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
141
+ }
142
+
143
+ .markdown-body pre {
144
+ margin-top: 0;
145
+ margin-bottom: 16px;
146
+ padding: 16px;
147
+ overflow: auto;
148
+ font-size: 85%;
149
+ line-height: 1.45;
150
+ background-color: var(--code-block-bg, #161b22);
151
+ border-radius: 6px;
152
+ }
153
+
154
+ .markdown-body pre code {
155
+ display: block;
156
+ padding: 0;
157
+ margin: 0;
158
+ font-size: 100%;
159
+ word-break: normal;
160
+ white-space: pre;
161
+ background: transparent;
162
+ border: 0;
163
+ }
164
+
165
+ /* Links */
166
+ .markdown-body a {
167
+ color: var(--link-color, #58a6ff);
168
+ text-decoration: none;
169
+ }
170
+
171
+ .markdown-body a:hover {
172
+ text-decoration: underline;
173
+ }
174
+
175
+ /* Blockquotes */
176
+ .markdown-body blockquote {
177
+ margin: 0 0 16px 0;
178
+ padding: 0 1em;
179
+ color: var(--text-secondary, #8b949e);
180
+ border-left: 0.25em solid var(--border-color, #30363d);
181
+ }
182
+
183
+ .markdown-body blockquote > :first-child {
184
+ margin-top: 0;
185
+ }
186
+
187
+ .markdown-body blockquote > :last-child {
188
+ margin-bottom: 0;
189
+ }
190
+
191
+ /* Tables */
192
+ .markdown-body table {
193
+ border-spacing: 0;
194
+ border-collapse: collapse;
195
+ margin-top: 0;
196
+ margin-bottom: 16px;
197
+ }
198
+
199
+ .markdown-body table th,
200
+ .markdown-body table td {
201
+ padding: 6px 13px;
202
+ border: 1px solid var(--border-color, #30363d);
203
+ }
204
+
205
+ .markdown-body table th {
206
+ font-weight: 600;
207
+ background-color: var(--table-header-bg, #161b22);
208
+ }
209
+
210
+ .markdown-body table tr {
211
+ background-color: var(--table-row-bg, #0d1117);
212
+ border-top: 1px solid var(--border-color, #30363d);
213
+ }
214
+
215
+ .markdown-body table tr:nth-child(2n) {
216
+ background-color: var(--table-row-alt-bg, #161b22);
217
+ }
218
+
219
+ /* Horizontal Rule */
220
+ .markdown-body hr {
221
+ height: 0.25em;
222
+ padding: 0;
223
+ margin: 24px 0;
224
+ background-color: var(--border-color, #30363d);
225
+ border: 0;
226
+ }
227
+
228
+ /* Images */
229
+ .markdown-body img {
230
+ max-width: 100%;
231
+ box-sizing: content-box;
232
+ background-color: var(--ios-bg, #0d1117);
233
+ }
234
+
235
+ /* Strong/Bold */
236
+ .markdown-body strong {
237
+ font-weight: 600;
238
+ }
239
+
240
+ /* Emphasis/Italic */
241
+ .markdown-body em {
242
+ font-style: italic;
243
+ }
244
+
245
+ /* Mermaid Diagrams */
246
+ .markdown-body .mermaid-diagram {
247
+ margin: 16px 0;
248
+ padding: 20px;
249
+ background-color: var(--code-block-bg, #161b22);
250
+ border-radius: 6px;
251
+ display: flex;
252
+ justify-content: center;
253
+ align-items: center;
254
+ overflow-x: auto;
255
+ min-height: 100px;
256
+ }
257
+
258
+ .markdown-body .mermaid-diagram svg {
259
+ max-width: 100%;
260
+ height: auto;
261
+ }
262
+
263
+ /* Mermaid error state */
264
+ .markdown-body .mermaid-error {
265
+ margin: 16px 0;
266
+ padding: 16px;
267
+ background-color: rgba(255, 59, 48, 0.1);
268
+ border: 1px solid var(--ios-red, #ff3b30);
269
+ border-radius: 6px;
270
+ color: var(--ios-red, #ff3b30);
271
+ font-family: monospace;
272
+ font-size: 12px;
273
+ }
@@ -2,6 +2,10 @@ import { API_BASE } from '../config.js';
2
2
  import { showToast, getById } from '../utils.js';
3
3
  // Import Highlight.js core
4
4
  import hljs from 'highlight.js/lib/core';
5
+ // Import markdown-it for rendering .md files
6
+ import markdownit from 'markdown-it';
7
+ // Import mermaid for rendering diagrams
8
+ import mermaid from 'mermaid';
5
9
 
6
10
  // Import common languages to reduce bundle size
7
11
  import javascript from 'highlight.js/lib/languages/javascript';
@@ -28,6 +32,79 @@ hljs.registerLanguage('python', python);
28
32
  hljs.registerLanguage('sql', sql);
29
33
  hljs.registerLanguage('markdown', markdown);
30
34
 
35
+ // Initialize markdown-it with safe settings
36
+ const md = markdownit({
37
+ html: false, // Disable HTML tags in source for security (prevents XSS)
38
+ breaks: true, // Convert line breaks to <br>
39
+ linkify: true, // Auto-convert URLs to links
40
+ typographer: true, // Enable smart quotes and other typographic replacements
41
+ highlight: function (str, lang) {
42
+ // Use highlight.js for code blocks within markdown
43
+ if (lang && hljs.getLanguage(lang)) {
44
+ try {
45
+ return hljs.highlight(str, { language: lang }).value;
46
+ } catch (__) {}
47
+ }
48
+ return ''; // Use default escaping
49
+ }
50
+ });
51
+
52
+ // Initialize mermaid with dark theme
53
+ mermaid.initialize({
54
+ startOnLoad: false, // We'll manually trigger rendering
55
+ theme: 'dark', // Match VG Coder's dark theme
56
+ securityLevel: 'loose', // Allow interaction in shadow DOM
57
+ fontFamily: '-apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif'
58
+ });
59
+
60
+ /**
61
+ * Render mermaid diagrams in the container
62
+ * Finds all code.language-mermaid blocks and replaces them with rendered SVG
63
+ */
64
+ async function renderMermaidDiagrams(container) {
65
+ const mermaidBlocks = container.querySelectorAll('code.language-mermaid');
66
+
67
+ if (mermaidBlocks.length === 0) {
68
+ return; // No mermaid diagrams to render
69
+ }
70
+
71
+ console.log(`[Mermaid] Found ${mermaidBlocks.length} diagram(s) to render`);
72
+
73
+ for (let i = 0; i < mermaidBlocks.length; i++) {
74
+ const block = mermaidBlocks[i];
75
+ const code = block.textContent;
76
+ const pre = block.parentElement;
77
+
78
+ try {
79
+ // Use mermaid.render() which is more compatible with shadow DOM
80
+ const id = `mermaid-diagram-${Date.now()}-${i}`;
81
+ const { svg, bindFunctions } = await mermaid.render(id, code);
82
+
83
+ // Create wrapper div for mermaid
84
+ const wrapper = document.createElement('div');
85
+ wrapper.className = 'mermaid-diagram';
86
+ wrapper.innerHTML = svg;
87
+
88
+ // Replace pre/code with wrapper
89
+ pre.replaceWith(wrapper);
90
+
91
+ // Bind any interactive functions if present
92
+ if (bindFunctions) {
93
+ bindFunctions(wrapper);
94
+ }
95
+
96
+ console.log(`[Mermaid] Successfully rendered diagram ${i + 1}`);
97
+ } catch (err) {
98
+ console.error(`[Mermaid] Failed to render diagram ${i + 1}:`, err);
99
+ // On error, show error message instead of broken diagram
100
+ const errorDiv = document.createElement('div');
101
+ errorDiv.className = 'mermaid-error';
102
+ errorDiv.textContent = `Mermaid rendering error: ${err.message}`;
103
+ pre.replaceWith(errorDiv);
104
+ }
105
+ }
106
+ }
107
+
31
108
  export async function openFileInViewer(path) {
32
109
  const container = getById('code-viewer-container');
33
110
  if (!container) return;
@@ -41,22 +118,41 @@ export async function openFileInViewer(path) {
41
118
 
42
119
  if (res.ok) {
43
120
  const ext = path.split('.').pop().toLowerCase();
44
- const language = getLanguageFromExt(ext);
45
-
46
- // Escape HTML tags to prevent XSS and ensure correct rendering
47
- const escapedCode = escapeHtml(data.content);
48
121
 
49
- // Render Code Block
50
- container.innerHTML = `
51
- <div class="cv-wrapper">
52
- <pre><code class="language-${language}">${escapedCode}</code></pre>
53
- </div>
54
- `;
122
+ // Check if file is markdown
123
+ if (ext === 'md') {
124
+ // Render as markdown
125
+ const htmlContent = md.render(data.content);
126
+
127
+ container.innerHTML = `
128
+ <div class="cv-wrapper cv-markdown">
129
+ <div class="markdown-body">
130
+ ${htmlContent}
131
+ </div>
132
+ </div>
133
+ `;
134
+
135
+ // Render mermaid diagrams (if any)
136
+ await renderMermaidDiagrams(container);
137
+ } else {
138
+ // Render as code with syntax highlighting
139
+ const language = getLanguageFromExt(ext);
140
+
141
+ // Escape HTML tags to prevent XSS and ensure correct rendering
142
+ const escapedCode = escapeHtml(data.content);
143
+
144
+ // Render Code Block
145
+ container.innerHTML = `
146
+ <div class="cv-wrapper">
147
+ <pre><code class="language-${language}">${escapedCode}</code></pre>
148
+ </div>
149
+ `;
55
150
 
56
- // Apply Highlight.js
57
- const codeBlock = container.querySelector('code');
58
- if(codeBlock) {
59
- hljs.highlightElement(codeBlock);
151
+ // Apply Highlight.js
152
+ const codeBlock = container.querySelector('code');
153
+ if(codeBlock) {
154
+ hljs.highlightElement(codeBlock);
155
+ }
60
156
  }
61
157
 
62
158
  } else {
@@ -112,10 +112,8 @@ function toggleDashboard() {
112
112
 
113
113
  if (isVisible) {
114
114
  appRoot.classList.remove('visible');
115
- console.log('[Keyboard] Dashboard hidden');
116
115
  } else {
117
116
  appRoot.classList.add('visible');
118
- console.log('[Keyboard] Dashboard shown');
119
117
  }
120
118
  }
121
119
 
@@ -132,7 +130,6 @@ function openGitPanel() {
132
130
  // First, make sure dashboard is visible
133
131
  if (!appRoot.classList.contains('visible')) {
134
132
  appRoot.classList.add('visible');
135
- console.log('[Keyboard] Dashboard opened');
136
133
  }
137
134
 
138
135
  // Then activate Git panel using getRoot() to query in Shadow DOM
@@ -183,7 +180,6 @@ function handleKeyDown(event) {
183
180
  }
184
181
 
185
182
  const shortcutKey = getShortcutKey(event);
186
- console.log('[Keyboard] Shortcut key detected:', shortcutKey);
187
183
 
188
184
  if (!shortcutKey) return;
189
185
 
@@ -191,7 +187,6 @@ function handleKeyDown(event) {
191
187
  const action = SHORTCUTS[shortcutKey];
192
188
 
193
189
  if (!action) {
194
- console.log('[Keyboard] No action registered for:', shortcutKey);
195
190
  return;
196
191
  }
197
192
 
@@ -199,7 +194,6 @@ function handleKeyDown(event) {
199
194
  event.preventDefault();
200
195
  event.stopPropagation();
201
196
 
202
- console.log(`[Keyboard] Shortcut triggered: ${shortcutKey} -> ${action}`);
203
197
 
204
198
  // Execute action
205
199
  switch (action) {
@@ -213,7 +207,7 @@ function handleKeyDown(event) {
213
207
  toggleShortcutsHelp();
214
208
  break;
215
209
  default:
216
- console.warn(`[Keyboard] Unknown action: ${action}`);
210
+ return;
217
211
  }
218
212
  }
219
213
 
@@ -231,12 +225,10 @@ function toggleShortcutsHelp() {
231
225
 
232
226
  if (isVisible) {
233
227
  helpPanel.classList.remove('visible');
234
- console.log('[Keyboard] Help panel hidden');
235
228
  } else {
236
229
  // Render shortcuts before showing
237
230
  renderHelpPanel();
238
231
  helpPanel.classList.add('visible');
239
- console.log('[Keyboard] Help panel shown');
240
232
  }
241
233
  }
242
234
 
@@ -45,7 +45,7 @@ export function initProjectPanel() {
45
45
  if (getById('project-panel-selector')) {
46
46
  loadProjectsIntoSelector();
47
47
  }
48
- }, 5000);
48
+ }, 30000);
49
49
 
50
50
  console.log('[ProjectPanel] Initialized with polling (Socket.IO not available in shadow DOM)');
51
51
  }
@@ -131,35 +131,27 @@ async function loadProjectsIntoSelector() {
131
131
 
132
132
  // Save current selection to preserve it
133
133
  const currentValue = selector.value;
134
- console.log('[ProjectPanel] Current selected project:', currentValue);
135
-
134
+
136
135
  try {
137
136
  const apiBase = window.API_BASE || 'http://localhost:6868';
138
- console.log('[ProjectPanel] Fetching projects from:', `${apiBase}/api/projects`);
139
137
 
140
138
  const response = await fetch(`${apiBase}/api/projects`);
141
139
  const data = await response.json();
142
140
 
143
- console.log('[ProjectPanel] Received projects:', data);
144
-
145
141
  if (data.projects && data.projects.length > 0) {
146
142
  const options = data.projects.map(p =>
147
143
  `<option value="${p.id}" ${p.isActive ? 'selected' : ''}>${p.name}</option>`
148
144
  ).join('');
149
145
 
150
- console.log('[ProjectPanel] Updating selector with', data.projects.length, 'projects');
151
146
  selector.innerHTML = options;
152
147
 
153
148
  // IMPORTANT: Restore previous selection if it still exists
154
149
  // This prevents auto-switching when new projects join
155
150
  if (currentValue && data.projects.some(p => p.id === currentValue)) {
156
151
  selector.value = currentValue;
157
- console.log('[ProjectPanel] ✅ Restored previous selection:', currentValue);
158
152
  } else {
159
- console.log('[ProjectPanel] â„šī¸ Using active project from API:', data.activeProjectId);
160
153
  }
161
154
  } else {
162
- console.warn('[ProjectPanel] No projects returned from API');
163
155
  selector.innerHTML = '<option value="">No projects</option>';
164
156
  }
165
157
  } catch (err) {