jvcs 1.6.3 → 1.6.4

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,7 +1,5 @@
1
1
  const blessed = require("blessed");
2
2
  const aiAnalyzer = require("./aiAnalyzer");
3
- const { marked } = require("marked");
4
- const { PlaintextRenderer } = require("marked-plaintext");
5
3
 
6
4
  function startUI(state) {
7
5
  const screen = blessed.screen({
@@ -10,80 +8,50 @@ function startUI(state) {
10
8
  });
11
9
 
12
10
  // ---------------------------------------
13
- // HEADER
11
+ // UI COMPONENTS
14
12
  // ---------------------------------------
15
13
  const header = blessed.box({
16
- top: 0,
17
- height: 1,
18
- width: "100%",
14
+ top: 0, height: 1, width: "100%",
19
15
  content: ` JVCS DIFF VIEW (${state.mode}) | ↑↓ Navigate | Enter Open | Esc Back | Tab Switch | Q Quit `,
20
- style: {
21
- fg: "white",
22
- bg: "blue",
23
- bold: true,
24
- underline: true
25
- },
16
+ style: { fg: "white", bg: "blue", bold: true, underline: true },
26
17
  tags: true
27
18
  });
28
19
  screen.append(header);
29
20
 
30
- // ---------------------------------------
31
- // FILE LIST VIEW
32
- // ---------------------------------------
33
21
  const fileList = blessed.list({
34
- top: 1,
35
- left: 0,
36
- width: "100%",
37
- height: "100%-1",
38
- keys: true,
39
- vi: true,
40
- border: "line",
22
+ top: 1, left: 0, width: "100%", height: "100%-1",
23
+ keys: true, vi: true, border: "line",
41
24
  label: " Changed Files ",
42
- style: {
43
- selected: { bg: "blue" },
44
- item: { fg: "white" }
45
- },
25
+ style: { selected: { bg: "blue" }, item: { fg: "white" } },
46
26
  tags: true
47
27
  });
48
28
  screen.append(fileList);
49
29
 
50
- function renderFileList() {
51
- const items = state.files.map(file => {
52
- let statusColored;
53
- switch(file.status) {
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();
58
- }
59
- return `${statusColored} ${file.path}`;
60
- });
61
- fileList.setItems(items);
62
- fileList.select(state.selectedIndex);
63
- fileList.focus();
64
- screen.render();
65
- }
66
-
67
- // ---------------------------------------
68
- // FILE VIEW PANELS
69
- // ---------------------------------------
70
30
  const panelOptions = {
71
- top: 1,
72
- height: "100%-1",
73
- border: "line",
74
- scrollable: true,
75
- alwaysScroll: true,
76
- keys: true,
77
- vi: true,
31
+ top: 1, height: "100%-1", border: "line",
32
+ scrollable: true, alwaysScroll: true, keys: true, vi: true,
78
33
  scrollbar: { ch: "│", track: { bg: "black" }, style: { bg: "yellow" } },
79
- padding: { left: 1, right: 1 },
80
- tags: true
34
+ padding: { left: 1, right: 1 }, tags: true
81
35
  };
82
36
 
83
37
  const leftBox = blessed.box({ ...panelOptions, left: 0, width: "33%", label: " LEFT " });
84
38
  const rightBox = blessed.box({ ...panelOptions, left: "33%", width: "34%", label: " RIGHT " });
85
39
  const aiBox = blessed.box({ ...panelOptions, left: "67%", width: "33%", label: " AI ANALYSIS " });
86
40
 
41
+ // ---------------------------------------
42
+ // HELPERS
43
+ // ---------------------------------------
44
+ function stripMarkdown(text) {
45
+ return text
46
+ .replace(/#{1,6}\s/g, "") // Remove headers
47
+ .replace(/\*\*(.*?)\*\*/g, "$1") // Bold to text
48
+ .replace(/\*(.*?)\*/g, "$1") // Italics to text
49
+ .replace(/`(.*?)`/g, "$1") // Code ticks to text
50
+ .replace(/\[(.*?)\]\(.*?\)/g, "$1") // Links to text
51
+ .replace(/^>\s/gm, "") // Blockquotes
52
+ .replace(/^- /gm, "• "); // List markers to bullets
53
+ }
54
+
87
55
  function colorDiffContent(content, type) {
88
56
  if (!content) return "";
89
57
  return content.split("\n").map(line => {
@@ -93,6 +61,9 @@ function startUI(state) {
93
61
  }).join("\n");
94
62
  }
95
63
 
64
+ // ---------------------------------------
65
+ // RENDER LOGIC
66
+ // ---------------------------------------
96
67
  async function renderFileView() {
97
68
  const file = state.getCurrentFile();
98
69
  if (!file) return;
@@ -116,11 +87,8 @@ function startUI(state) {
116
87
  mode: state.mode
117
88
  });
118
89
 
119
- // USE PLAINTEXT RENDERER HERE
120
- const renderer = new PlaintextRenderer();
121
- const cleanText = marked.parse(aiSummary, { renderer: renderer });
122
-
123
- aiBox.setContent(cleanText);
90
+ // Convert to clean text for terminal
91
+ aiBox.setContent(stripMarkdown(aiSummary));
124
92
  screen.render();
125
93
  }
126
94
  catch(error) {
@@ -129,65 +97,32 @@ function startUI(state) {
129
97
  }
130
98
  }
131
99
 
132
- function destroyFileView() {
133
- leftBox.detach();
134
- rightBox.detach();
135
- aiBox.detach();
136
- screen.render();
137
- }
138
-
139
100
  function updateActiveTabHighlight() {
140
101
  leftBox.style.border.fg = state.activeTab === 0 ? "yellow" : "grey";
141
102
  rightBox.style.border.fg = state.activeTab === 1 ? "yellow" : "grey";
142
103
  aiBox.style.border.fg = state.activeTab === 2 ? "yellow" : "grey";
143
-
144
104
  if(state.activeTab === 0) leftBox.focus();
145
105
  else if(state.activeTab === 1) rightBox.focus();
146
106
  else aiBox.focus();
147
-
148
107
  screen.render();
149
108
  }
150
109
 
151
110
  // ---------------------------------------
152
- // KEYBOARD CONTROLS
111
+ // INPUT HANDLING
153
112
  // ---------------------------------------
154
113
  screen.key(["q", "C-c"], () => process.exit(0));
114
+ fileList.key(["up"], () => { if(state.selectedIndex > 0) { state.selectFile(state.selectedIndex - 1); renderFileList(); }});
115
+ fileList.key(["down"], () => { if(state.selectedIndex < state.files.length - 1) { state.selectFile(state.selectedIndex + 1); renderFileList(); }});
116
+ fileList.key(["enter"], async () => { state.goToFileView(); fileList.detach(); await renderFileView(); });
117
+ screen.key(["escape"], () => { if(state.screen === "FILE_VIEW") { state.goToListView(); leftBox.detach(); rightBox.detach(); aiBox.detach(); screen.append(fileList); renderFileList(); }});
118
+ screen.key(["tab"], () => { if(state.screen === "FILE_VIEW") { state.switchTab((state.activeTab + 1) % 3); updateActiveTabHighlight(); }});
155
119
 
156
- fileList.key(["up"], () => {
157
- if(state.selectedIndex > 0) {
158
- state.selectFile(state.selectedIndex - 1);
159
- renderFileList();
160
- }
161
- });
162
-
163
- fileList.key(["down"], () => {
164
- if(state.selectedIndex < state.files.length - 1) {
165
- state.selectFile(state.selectedIndex + 1);
166
- renderFileList();
167
- }
168
- });
169
-
170
- fileList.key(["enter"], async () => {
171
- state.goToFileView();
172
- fileList.detach();
173
- await renderFileView();
174
- });
175
-
176
- screen.key(["escape"], () => {
177
- if(state.screen === "FILE_VIEW") {
178
- state.goToListView();
179
- destroyFileView();
180
- screen.append(fileList);
181
- renderFileList();
182
- }
183
- });
184
-
185
- screen.key(["tab"], () => {
186
- if(state.screen === "FILE_VIEW") {
187
- state.switchTab((state.activeTab + 1) % 3);
188
- updateActiveTabHighlight();
189
- }
190
- });
120
+ function renderFileList() {
121
+ fileList.setItems(state.files.map(f => `${f.status === "added" ? "{green-fg}" : f.status === "deleted" ? "{red-fg}" : "{yellow-fg}"}${f.status.toUpperCase()}{/} ${f.path}`));
122
+ fileList.select(state.selectedIndex);
123
+ fileList.focus();
124
+ screen.render();
125
+ }
191
126
 
192
127
  renderFileList();
193
128
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jvcs",
3
- "version": "1.6.3",
3
+ "version": "1.6.4",
4
4
  "bin": {
5
5
  "jvcs": "index.js"
6
6
  },