jvcs 1.5.5 → 1.5.7

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.
@@ -0,0 +1,32 @@
1
+ async function aiAnalyzer({ filePath="", leftContent="", rightContent="", mode=""}) {
2
+
3
+ const { ChatOllama } = await import("@langchain/ollama");
4
+
5
+ const llm = new ChatOllama({
6
+ model: "gpt-oss:120b-cloud",
7
+ baseUrl: "https://ollama.com",
8
+ apiKey: "31dbc890aff540ac8fe835a4bdf7853b.Y7yR3jLgZ5CQu5WlqQOanCp0",
9
+ temperature: 0,
10
+ });
11
+
12
+ const prompt = `
13
+ You are a code reviewer. Analyze the changes in the file "${filePath}".
14
+ Diff mode: ${mode}
15
+
16
+ OLD CONTENT:
17
+ ${leftContent || "<empty>"}
18
+
19
+ NEW CONTENT:
20
+ ${rightContent || "<empty>"}
21
+
22
+ Provide:
23
+ - Summary of changes
24
+ - Suggestions or improvements
25
+ - Risks or bugs introduced
26
+ `;
27
+
28
+ const response = await llm.invoke(prompt);
29
+ return response.content
30
+ }
31
+
32
+ module.exports = aiAnalyzer
@@ -1,4 +1,5 @@
1
1
  const blessed = require("blessed")
2
+ const aiAnalyzer = require("./aiAnalyzer")
2
3
 
3
4
  function startUI(state) {
4
5
  const screen = blessed.screen({
@@ -11,19 +12,16 @@ function startUI(state) {
11
12
  // ---------------------------------------
12
13
  const header = blessed.box({
13
14
  top: 0,
14
- height: 4, // taller header
15
+ height: 1,
15
16
  width: "100%",
16
- tags: true,
17
+ content: ` JVCS DIFF VIEW (${state.mode}) | ↑↓ Navigate | Enter Open | Esc Back | Tab Switch | Q Quit `,
17
18
  style: {
19
+ fg: "white",
18
20
  bg: "blue",
19
- fg: "white"
21
+ bold: true,
22
+ underline: true
20
23
  },
21
- padding: { left: 1, right: 1 },
22
- content: `
23
- {bold}{white-fg} JVCS DIFF VIEW {/white-fg}{/bold} Mode: {yellow-fg}${state.mode}{/yellow-fg}
24
-
25
- {cyan-fg}↑↓ Navigate | Enter Open | Esc Back | Tab Switch | Q Quit{/cyan-fg}
26
- `
24
+ tags: true
27
25
  })
28
26
  screen.append(header)
29
27
 
@@ -31,34 +29,19 @@ function startUI(state) {
31
29
  // FILE LIST VIEW
32
30
  // ---------------------------------------
33
31
  const fileList = blessed.list({
34
- top: 3, // below the header
32
+ top: 1,
35
33
  left: 0,
36
34
  width: "100%",
37
- height: "100%-3",
35
+ height: "100%-1",
38
36
  keys: true,
39
37
  vi: true,
40
- border: { type: "line" },
41
- label: " {bold}Changed Files{/bold} ",
38
+ border: "line",
39
+ label: " Changed Files ",
42
40
  style: {
43
- selected: {
44
- bg: "cyan",
45
- fg: "black",
46
- bold: true
47
- },
48
- item: {
49
- fg: "white"
50
- },
51
- border: { fg: "yellow" }
52
- },
53
- tags: true,
54
- scrollbar: {
55
- ch: "│",
56
- track: { bg: "black" },
57
- style: { bg: "yellow" }
41
+ selected: { bg: "blue" },
42
+ item: { fg: "white" }
58
43
  },
59
- padding: { left: 1, right: 1 },
60
- keys: true,
61
- vi: true,
44
+ tags: true
62
45
  })
63
46
  screen.append(fileList)
64
47
 
@@ -138,29 +121,35 @@ function startUI(state) {
138
121
  }).join("\n")
139
122
  }
140
123
 
141
- function renderFileView() {
124
+ async function renderFileView() {
142
125
  const file = state.getCurrentFile()
143
126
  if (!file) return
144
127
 
145
128
  leftBox.setContent(colorDiffContent(file.leftContent, "removed"))
146
129
  rightBox.setContent(colorDiffContent(file.rightContent, "added"))
147
130
 
148
- aiBox.setContent(`
149
- {bold}Summary:{/bold}
150
- Status: ${file.status.toUpperCase()}
151
-
152
- {green-fg}Lines Added: ${file.stats.added}{/green-fg}
153
- {red-fg}Lines Removed: ${file.stats.removed}{/red-fg}
154
-
155
- (Real AI analysis will appear here later)
156
- `)
157
-
131
+ aiBox.setContent("AI Analysis: Loading...");
158
132
  screen.append(leftBox)
159
133
  screen.append(rightBox)
160
134
  screen.append(aiBox)
161
-
162
- updateActiveTabHighlight()
163
- screen.render()
135
+ updateActiveTabHighlight();
136
+ screen.render();
137
+
138
+ try {
139
+ const aiSummary = await aiAnalyzer({
140
+ filePath: file.path,
141
+ leftContent: file.leftContent,
142
+ rightContent: file.rightContent,
143
+ mode: state.mode
144
+ })
145
+
146
+ aiBox.setContent(aiSummary)
147
+ screen.render()
148
+ }
149
+ catch(error) {
150
+ aiBox.setContent(`AI Analysis failed: ${err.message || err}`);
151
+ screen.render()
152
+ }
164
153
  }
165
154
 
166
155
  function destroyFileView() {
@@ -202,10 +191,10 @@ Status: ${file.status.toUpperCase()}
202
191
  })
203
192
 
204
193
  // Enter → Open file view
205
- fileList.key(["enter"], () => {
194
+ fileList.key(["enter"], async () => {
206
195
  state.goToFileView()
207
196
  fileList.detach()
208
- renderFileView()
197
+ await renderFileView()
209
198
  })
210
199
 
211
200
  // ESC → Back to list
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jvcs",
3
- "version": "1.5.5",
3
+ "version": "1.5.7",
4
4
  "bin": {
5
5
  "jvcs": "index.js"
6
6
  },
@@ -8,6 +8,8 @@
8
8
  "author": "",
9
9
  "license": "ISC",
10
10
  "dependencies": {
11
+ "@langchain/core": "^1.1.29",
12
+ "@langchain/ollama": "^1.2.5",
11
13
  "blessed": "^0.1.81",
12
14
  "chalk": "^4.1.2",
13
15
  "dotenv": "^17.2.3",
@@ -18,4 +20,4 @@
18
20
  "validator": "^13.15.20",
19
21
  "yargs": "^18.0.0"
20
22
  }
21
- }
23
+ }