@jxtools/visualgit 1.2.0 → 1.4.0
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/dist/assets/{index-Xj2Kq8Xb.css → index-DFSlJzsh.css} +1 -1
- package/dist/assets/index-XUf8QbsZ.js +26 -0
- package/dist/index.html +2 -2
- package/dist-server/index.js +1 -1
- package/dist-server/routes/ai.js +2 -2
- package/dist-server/services/ai.service.js +21 -10
- package/package.json +2 -1
- package/dist/assets/index-CfMbMqji.js +0 -13
package/dist/index.html
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
9
9
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
10
10
|
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
|
11
|
-
<script type="module" crossorigin src="/assets/index-
|
|
12
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
11
|
+
<script type="module" crossorigin src="/assets/index-XUf8QbsZ.js"></script>
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DFSlJzsh.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
15
15
|
<div id="root"></div>
|
package/dist-server/index.js
CHANGED
|
@@ -10,7 +10,7 @@ export function createServer(repoPath, isGitRepo = true) {
|
|
|
10
10
|
app.use(cors());
|
|
11
11
|
app.use(express.json({ limit: '5mb' }));
|
|
12
12
|
app.use('/api/git', createGitRouter(repoPath, isGitRepo));
|
|
13
|
-
app.use('/api/ai', createAiRouter());
|
|
13
|
+
app.use('/api/ai', createAiRouter(repoPath));
|
|
14
14
|
const distPath = path.join(__dirname, '..', 'dist');
|
|
15
15
|
app.use(express.static(distPath));
|
|
16
16
|
app.get('/{*splat}', (_req, res, next) => {
|
package/dist-server/routes/ai.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Router } from 'express';
|
|
2
2
|
import { AiService } from '../services/ai.service.js';
|
|
3
|
-
export function createAiRouter() {
|
|
3
|
+
export function createAiRouter(repoPath) {
|
|
4
4
|
const router = Router();
|
|
5
5
|
const aiService = new AiService();
|
|
6
6
|
router.post('/analyze', async (req, res) => {
|
|
@@ -15,7 +15,7 @@ export function createAiRouter() {
|
|
|
15
15
|
Connection: 'keep-alive',
|
|
16
16
|
});
|
|
17
17
|
try {
|
|
18
|
-
for await (const chunk of aiService.analyze(provider, mode, content, filePath, model)) {
|
|
18
|
+
for await (const chunk of aiService.analyze(provider, mode, content, filePath, model, repoPath)) {
|
|
19
19
|
res.write(`data: ${JSON.stringify({ text: chunk })}\n\n`);
|
|
20
20
|
}
|
|
21
21
|
res.write(`data: ${JSON.stringify({ done: true })}\n\n`);
|
|
@@ -2,33 +2,44 @@ import { spawn } from 'child_process';
|
|
|
2
2
|
export class AiService {
|
|
3
3
|
hasConversation = false;
|
|
4
4
|
buildPrompt(mode, content, filePath) {
|
|
5
|
+
const systemRules = [
|
|
6
|
+
'Format your response using Markdown (headings, bold, bullet points, inline code).',
|
|
7
|
+
'NEVER ask questions, suggest next steps, or offer to do anything. This is a read-only report.',
|
|
8
|
+
'NEVER repeat the source code in your response.',
|
|
9
|
+
'Be concise. Use bullet points, not paragraphs.',
|
|
10
|
+
].join(' ');
|
|
5
11
|
if (mode === 'selection') {
|
|
6
|
-
return `Analyze this
|
|
12
|
+
return `Analyze this code snippet${filePath ? ` from ${filePath}` : ''}. Follow this exact structure:\n\n## What It Does\n(Brief explanation)\n\n## Issues\n(Bugs, risks, or anti-patterns found — or "None found")\n\n## Improvements\n(Concrete suggestions — or "Looks good")\n\n${systemRules}\n\n\`\`\`\n${content}\n\`\`\``;
|
|
7
13
|
}
|
|
8
14
|
if (mode === 'file') {
|
|
9
|
-
return `Analyze the changes in ${filePath || 'this file'}.
|
|
15
|
+
return `Analyze the changes in ${filePath || 'this file'}. Follow this exact structure:\n\n## Summary\n(What changed in 1-2 sentences)\n\n## Changes\n(Bullet list of each meaningful change)\n\n## Risks\n(Potential issues — or "None identified")\n\n## Verdict\n(One-line assessment: safe to merge, needs review, or has issues)\n\n${systemRules}\n\n\`\`\`diff\n${content}\n\`\`\``;
|
|
10
16
|
}
|
|
11
|
-
return `You are a senior software engineer
|
|
17
|
+
return `You are a senior software engineer reviewing a git diff. Follow this exact structure:\n\n## Summary\n(Executive summary in 2-3 sentences)\n\n## Changes by File\n(Group changes by file, bullet points per file)\n\n## Patterns\n(Key improvements or patterns introduced — or "No notable patterns")\n\n## Risks\n(Potential issues or concerns — or "None identified")\n\n## Verdict\n(One-line overall assessment)\n\n${systemRules}\n\n\`\`\`diff\n${content}\n\`\`\``;
|
|
12
18
|
}
|
|
13
|
-
getCommand(provider,
|
|
19
|
+
getCommand(provider, model = 'sonnet') {
|
|
14
20
|
if (provider === 'claude') {
|
|
15
21
|
const args = ['-p', '--model', model];
|
|
16
22
|
if (this.hasConversation)
|
|
17
23
|
args.push('--continue');
|
|
18
|
-
args
|
|
19
|
-
return { command: 'claude', args };
|
|
24
|
+
return { command: 'claude', args, useStdin: true };
|
|
20
25
|
}
|
|
21
26
|
return {
|
|
22
27
|
command: 'openai',
|
|
23
|
-
args: ['api', 'chat.completions.create', '-m', 'gpt-4o', '-g', 'user'
|
|
28
|
+
args: ['api', 'chat.completions.create', '-m', 'gpt-4o', '-g', 'user'],
|
|
29
|
+
useStdin: true,
|
|
24
30
|
};
|
|
25
31
|
}
|
|
26
|
-
async *analyze(provider, mode, content, filePath, model) {
|
|
32
|
+
async *analyze(provider, mode, content, filePath, model, repoPath) {
|
|
27
33
|
const prompt = this.buildPrompt(mode, content, filePath);
|
|
28
|
-
const { command, args } = this.getCommand(provider,
|
|
34
|
+
const { command, args, useStdin } = this.getCommand(provider, model);
|
|
29
35
|
const env = { ...process.env };
|
|
30
36
|
delete env.CLAUDECODE;
|
|
31
|
-
const
|
|
37
|
+
const cwd = repoPath || process.cwd();
|
|
38
|
+
const proc = spawn(command, args, { env, cwd, stdio: ['pipe', 'pipe', 'pipe'] });
|
|
39
|
+
if (useStdin) {
|
|
40
|
+
proc.stdin.write(prompt);
|
|
41
|
+
proc.stdin.end();
|
|
42
|
+
}
|
|
32
43
|
const result = await new Promise((resolve, reject) => {
|
|
33
44
|
let data = '';
|
|
34
45
|
let stderr = '';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jxtools/visualgit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "Terminal-style git diff viewer with AI-powered explanations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"open": "^11.0.0",
|
|
42
42
|
"react": "^19.2.4",
|
|
43
43
|
"react-dom": "^19.2.4",
|
|
44
|
+
"react-markdown": "^10.1.0",
|
|
44
45
|
"simple-git": "^3.30.0"
|
|
45
46
|
},
|
|
46
47
|
"devDependencies": {
|