jvcs 1.6.2 → 1.6.3

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.
@@ -1,17 +1,13 @@
1
1
  const blessed = require("blessed");
2
2
  const aiAnalyzer = require("./aiAnalyzer");
3
3
  const { marked } = require("marked");
4
- const { TerminalRenderer } = require("marked-terminal");
5
-
6
- marked.setOptions({
7
- renderer: TerminalRenderer
8
- });
4
+ const { PlaintextRenderer } = require("marked-plaintext");
9
5
 
10
6
  function startUI(state) {
11
7
  const screen = blessed.screen({
12
8
  smartCSR: true,
13
9
  title: "JVCS Diff Viewer"
14
- })
10
+ });
15
11
 
16
12
  // ---------------------------------------
17
13
  // HEADER
@@ -28,8 +24,8 @@ function startUI(state) {
28
24
  underline: true
29
25
  },
30
26
  tags: true
31
- })
32
- screen.append(header)
27
+ });
28
+ screen.append(header);
33
29
 
34
30
  // ---------------------------------------
35
31
  // FILE LIST VIEW
@@ -48,52 +44,33 @@ function startUI(state) {
48
44
  item: { fg: "white" }
49
45
  },
50
46
  tags: true
51
- })
52
- screen.append(fileList)
47
+ });
48
+ screen.append(fileList);
53
49
 
54
50
  function renderFileList() {
55
51
  const items = state.files.map(file => {
56
- let statusColored
52
+ let statusColored;
57
53
  switch(file.status) {
58
- case "added": statusColored = `{green-fg}${file.status.toUpperCase()}{/green-fg}`; break
59
- case "deleted": statusColored = `{red-fg}${file.status.toUpperCase()}{/red-fg}`; break
60
- case "modified": statusColored = `{yellow-fg}${file.status.toUpperCase()}{/yellow-fg}`; break
61
- default: statusColored = file.status.toUpperCase()
54
+ case "added": statusColored = `{green-fg}${file.status.toUpperCase()}{/green-fg}`; break;
55
+ case "deleted": statusColored = `{red-fg}${file.status.toUpperCase()}{/red-fg}`; break;
56
+ case "modified": statusColored = `{yellow-fg}${file.status.toUpperCase()}{/yellow-fg}`; break;
57
+ default: statusColored = file.status.toUpperCase();
62
58
  }
63
- return `${statusColored} ${file.path}`
64
- })
65
- fileList.setItems(items)
66
- fileList.select(state.selectedIndex)
67
- fileList.focus()
68
- screen.render()
59
+ return `${statusColored} ${file.path}`;
60
+ });
61
+ fileList.setItems(items);
62
+ fileList.select(state.selectedIndex);
63
+ fileList.focus();
64
+ screen.render();
69
65
  }
70
66
 
71
67
  // ---------------------------------------
72
- // FILE VIEW (3 PANELS)
68
+ // FILE VIEW PANELS
73
69
  // ---------------------------------------
74
- const leftBox = blessed.box({
75
- top: 1,
76
- left: 0,
77
- width: "33%",
78
- height: "100%-1",
79
- border: "line",
80
- label: " LEFT ",
81
- scrollable: true,
82
- alwaysScroll: true,
83
- keys: true,
84
- vi: true,
85
- scrollbar: { ch: "│", track: { bg: "black" }, style: { bg: "yellow" } },
86
- padding: { left: 1, right: 1 },
87
- tags: true
88
- })
89
-
90
- const rightBox = blessed.box({
70
+ const panelOptions = {
91
71
  top: 1,
92
- left: "33%",
93
- width: "34%",
94
72
  height: "100%-1",
95
73
  border: "line",
96
- label: " RIGHT ",
97
74
  scrollable: true,
98
75
  alwaysScroll: true,
99
76
  keys: true,
@@ -101,43 +78,33 @@ function startUI(state) {
101
78
  scrollbar: { ch: "│", track: { bg: "black" }, style: { bg: "yellow" } },
102
79
  padding: { left: 1, right: 1 },
103
80
  tags: true
104
- })
81
+ };
105
82
 
106
- const aiBox = blessed.box({
107
- top: 1,
108
- left: "67%",
109
- width: "33%",
110
- height: "100%-1",
111
- border: "line",
112
- label: " AI ANALYSIS ",
113
- scrollable: true,
114
- alwaysScroll: true,
115
- keys: true,
116
- vi: true,
117
- scrollbar: { ch: "│", track: { bg: "black" }, style: { bg: "yellow" } },
118
- padding: { left: 1, right: 1 },
119
- tags: true
120
- })
83
+ const leftBox = blessed.box({ ...panelOptions, left: 0, width: "33%", label: " LEFT " });
84
+ const rightBox = blessed.box({ ...panelOptions, left: "33%", width: "34%", label: " RIGHT " });
85
+ const aiBox = blessed.box({ ...panelOptions, left: "67%", width: "33%", label: " AI ANALYSIS " });
121
86
 
122
87
  function colorDiffContent(content, type) {
88
+ if (!content) return "";
123
89
  return content.split("\n").map(line => {
124
- if(type === "added") return `{green-fg}+ ${line}{/green-fg}`
125
- if(type === "removed") return `{red-fg}- ${line}{/red-fg}`
126
- return ` ${line}`
127
- }).join("\n")
90
+ if(type === "added") return `{green-fg}+ ${line}{/green-fg}`;
91
+ if(type === "removed") return `{red-fg}- ${line}{/red-fg}`;
92
+ return ` ${line}`;
93
+ }).join("\n");
128
94
  }
129
95
 
130
96
  async function renderFileView() {
131
- const file = state.getCurrentFile()
132
- if (!file) return
133
-
134
- leftBox.setContent(colorDiffContent(file.leftContent, "removed"))
135
- rightBox.setContent(colorDiffContent(file.rightContent, "added"))
97
+ const file = state.getCurrentFile();
98
+ if (!file) return;
136
99
 
100
+ leftBox.setContent(colorDiffContent(file.leftContent, "removed"));
101
+ rightBox.setContent(colorDiffContent(file.rightContent, "added"));
137
102
  aiBox.setContent("AI Analysis: Loading...");
138
- screen.append(leftBox)
139
- screen.append(rightBox)
140
- screen.append(aiBox)
103
+
104
+ screen.append(leftBox);
105
+ screen.append(rightBox);
106
+ screen.append(aiBox);
107
+
141
108
  updateActiveTabHighlight();
142
109
  screen.render();
143
110
 
@@ -147,85 +114,82 @@ function startUI(state) {
147
114
  leftContent: file.leftContent,
148
115
  rightContent: file.rightContent,
149
116
  mode: state.mode
150
- })
151
-
152
- const parsed = marked(aiSummary); // Markdown terminal-friendly text
153
- aiBox.setContent(parsed);
154
- screen.render()
117
+ });
118
+
119
+ // USE PLAINTEXT RENDERER HERE
120
+ const renderer = new PlaintextRenderer();
121
+ const cleanText = marked.parse(aiSummary, { renderer: renderer });
122
+
123
+ aiBox.setContent(cleanText);
124
+ screen.render();
155
125
  }
156
126
  catch(error) {
157
- aiBox.setContent(`AI Analysis failed: ${error.message || error}`);
158
- screen.render()
127
+ aiBox.setContent(`{red-fg}AI Analysis failed: ${error.message || error}{/red-fg}`);
128
+ screen.render();
159
129
  }
160
130
  }
161
131
 
162
132
  function destroyFileView() {
163
- leftBox.detach()
164
- rightBox.detach()
165
- aiBox.detach()
166
- screen.render()
133
+ leftBox.detach();
134
+ rightBox.detach();
135
+ aiBox.detach();
136
+ screen.render();
167
137
  }
168
138
 
169
139
  function updateActiveTabHighlight() {
170
- leftBox.style.border.fg = state.activeTab === 0 ? "yellow" : "grey"
171
- rightBox.style.border.fg = state.activeTab === 1 ? "yellow" : "grey"
172
- aiBox.style.border.fg = state.activeTab === 2 ? "yellow" : "grey"
140
+ leftBox.style.border.fg = state.activeTab === 0 ? "yellow" : "grey";
141
+ rightBox.style.border.fg = state.activeTab === 1 ? "yellow" : "grey";
142
+ aiBox.style.border.fg = state.activeTab === 2 ? "yellow" : "grey";
173
143
 
174
- if(state.activeTab === 0) leftBox.focus()
175
- else if(state.activeTab === 1) rightBox.focus()
176
- else aiBox.focus()
144
+ if(state.activeTab === 0) leftBox.focus();
145
+ else if(state.activeTab === 1) rightBox.focus();
146
+ else aiBox.focus();
177
147
 
178
- screen.render()
148
+ screen.render();
179
149
  }
180
150
 
181
151
  // ---------------------------------------
182
152
  // KEYBOARD CONTROLS
183
153
  // ---------------------------------------
184
- screen.key(["q", "C-c"], () => process.exit(0))
154
+ screen.key(["q", "C-c"], () => process.exit(0));
185
155
 
186
- // Navigate list
187
156
  fileList.key(["up"], () => {
188
157
  if(state.selectedIndex > 0) {
189
- state.selectFile(state.selectedIndex - 1)
190
- renderFileList()
158
+ state.selectFile(state.selectedIndex - 1);
159
+ renderFileList();
191
160
  }
192
- })
161
+ });
162
+
193
163
  fileList.key(["down"], () => {
194
164
  if(state.selectedIndex < state.files.length - 1) {
195
- state.selectFile(state.selectedIndex + 1)
196
- renderFileList()
165
+ state.selectFile(state.selectedIndex + 1);
166
+ renderFileList();
197
167
  }
198
- })
168
+ });
199
169
 
200
- // Enter → Open file view
201
170
  fileList.key(["enter"], async () => {
202
- state.goToFileView()
203
- fileList.detach()
204
- await renderFileView()
205
- })
171
+ state.goToFileView();
172
+ fileList.detach();
173
+ await renderFileView();
174
+ });
206
175
 
207
- // ESC → Back to list
208
176
  screen.key(["escape"], () => {
209
177
  if(state.screen === "FILE_VIEW") {
210
- state.goToListView()
211
- destroyFileView()
212
- screen.append(fileList)
213
- renderFileList()
178
+ state.goToListView();
179
+ destroyFileView();
180
+ screen.append(fileList);
181
+ renderFileList();
214
182
  }
215
- })
183
+ });
216
184
 
217
- // TAB → switch active panel
218
185
  screen.key(["tab"], () => {
219
186
  if(state.screen === "FILE_VIEW") {
220
- state.switchTab((state.activeTab + 1) % 3)
221
- updateActiveTabHighlight()
187
+ state.switchTab((state.activeTab + 1) % 3);
188
+ updateActiveTabHighlight();
222
189
  }
223
- })
190
+ });
224
191
 
225
- // ---------------------------------------
226
- // INITIAL RENDER
227
- // ---------------------------------------
228
- renderFileList()
192
+ renderFileList();
229
193
  }
230
194
 
231
- module.exports = startUI
195
+ module.exports = startUI;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jvcs",
3
- "version": "1.6.2",
3
+ "version": "1.6.3",
4
4
  "bin": {
5
5
  "jvcs": "index.js"
6
6
  },
@@ -16,6 +16,7 @@
16
16
  "googleapis": "^164.1.0",
17
17
  "inquirer": "^8.2.7",
18
18
  "marked": "^15.0.12",
19
+ "marked-plaintext": "^0.0.2",
19
20
  "marked-terminal": "^7.3.0",
20
21
  "minimatch": "^10.2.4",
21
22
  "uuid": "^13.0.0",