@jxtools/visualgit 1.1.0 → 1.3.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.
@@ -1 +1 @@
1
- @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-border-style:solid}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--spacing:.25rem;--animate-spin:spin 1s linear infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.collapse{visibility:collapse}.visible{visibility:visible}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.top-0{top:calc(var(--spacing)*0)}.top-full{top:100%}.right-0{right:calc(var(--spacing)*0)}.z-10{z-index:10}.z-20{z-index:20}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.mt-1{margin-top:calc(var(--spacing)*1)}.ml-0\.5{margin-left:calc(var(--spacing)*.5)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.inline-block{display:inline-block}.h-8{height:calc(var(--spacing)*8)}.h-10{height:calc(var(--spacing)*10)}.h-12{height:calc(var(--spacing)*12)}.h-\[14px\]{height:14px}.h-\[22px\]{height:22px}.h-full{height:100%}.h-screen{height:100vh}.min-h-0{min-height:calc(var(--spacing)*0)}.w-1{width:calc(var(--spacing)*1)}.w-10{width:calc(var(--spacing)*10)}.w-12{width:calc(var(--spacing)*12)}.w-\[2px\]{width:2px}.w-full{width:100%}.w-screen{width:100vw}.min-w-0{min-width:calc(var(--spacing)*0)}.min-w-\[120px\]{min-width:120px}.min-w-full{min-width:100%}.flex-1{flex:1}.shrink-0{flex-shrink:0}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x)var(--tw-translate-y)}.-translate-y-full{--tw-translate-y:-100%;translate:var(--tw-translate-x)var(--tw-translate-y)}.animate-spin{animation:var(--animate-spin)}.cursor-col-resize{cursor:col-resize}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}.gap-6{gap:calc(var(--spacing)*6)}.gap-8{gap:calc(var(--spacing)*8)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-y-auto{overflow-y:auto}.border{border-style:var(--tw-border-style);border-width:1px}.p-4{padding:calc(var(--spacing)*4)}.px-1\.5{padding-inline:calc(var(--spacing)*1.5)}.px-2\.5{padding-inline:calc(var(--spacing)*2.5)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-6{padding-inline:calc(var(--spacing)*6)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-1\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.pt-0{padding-top:calc(var(--spacing)*0)}.pr-2{padding-right:calc(var(--spacing)*2)}.pr-3{padding-right:calc(var(--spacing)*3)}.text-left{text-align:left}.text-right{text-align:right}.align-middle{vertical-align:middle}.whitespace-pre{white-space:pre}.whitespace-pre-wrap{white-space:pre-wrap}.opacity-50{opacity:.5}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.select-none{-webkit-user-select:none;user-select:none}@media(hover:hover){.hover\:bg-\[\#58A6FF\]\/40:hover{background-color:#58a6ff66}}}body{color:#e6edf3;background-color:#0d1117;margin:0;padding:0;font-family:JetBrains Mono,monospace;overflow:hidden}@keyframes blink{0%,to{opacity:1}50%{opacity:0}}.cursor-blink{animation:1s step-end infinite blink}::-webkit-scrollbar{width:8px}::-webkit-scrollbar-track{background:#0d1117}::-webkit-scrollbar-thumb{background:#30363d;border-radius:4px}::-webkit-scrollbar-thumb:hover{background:#484f58}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@keyframes spin{to{transform:rotate(360deg)}}
1
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-border-style:solid}}}@layer theme{:root,:host{--font-sans:ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--font-mono:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--spacing:.25rem;--animate-spin:spin 1s linear infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4,0,.2,1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components;@layer utilities{.collapse{visibility:collapse}.visible{visibility:visible}.absolute{position:absolute}.relative{position:relative}.sticky{position:sticky}.top-0{top:calc(var(--spacing)*0)}.top-full{top:100%}.right-0{right:calc(var(--spacing)*0)}.z-10{z-index:10}.z-20{z-index:20}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.mt-1{margin-top:calc(var(--spacing)*1)}.ml-0\.5{margin-left:calc(var(--spacing)*.5)}.ml-auto{margin-left:auto}.block{display:block}.flex{display:flex}.inline-block{display:inline-block}.h-8{height:calc(var(--spacing)*8)}.h-10{height:calc(var(--spacing)*10)}.h-12{height:calc(var(--spacing)*12)}.h-\[14px\]{height:14px}.h-\[22px\]{height:22px}.h-full{height:100%}.h-screen{height:100vh}.min-h-0{min-height:calc(var(--spacing)*0)}.w-1{width:calc(var(--spacing)*1)}.w-10{width:calc(var(--spacing)*10)}.w-12{width:calc(var(--spacing)*12)}.w-\[2px\]{width:2px}.w-full{width:100%}.w-screen{width:100vw}.min-w-0{min-width:calc(var(--spacing)*0)}.min-w-\[120px\]{min-width:120px}.min-w-full{min-width:100%}.flex-1{flex:1}.shrink-0{flex-shrink:0}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x)var(--tw-translate-y)}.-translate-y-full{--tw-translate-y:-100%;translate:var(--tw-translate-x)var(--tw-translate-y)}.animate-spin{animation:var(--animate-spin)}.cursor-col-resize{cursor:col-resize}.cursor-not-allowed{cursor:not-allowed}.cursor-pointer{cursor:pointer}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-1{gap:calc(var(--spacing)*1)}.gap-1\.5{gap:calc(var(--spacing)*1.5)}.gap-2{gap:calc(var(--spacing)*2)}.gap-3{gap:calc(var(--spacing)*3)}.gap-4{gap:calc(var(--spacing)*4)}.gap-6{gap:calc(var(--spacing)*6)}.gap-8{gap:calc(var(--spacing)*8)}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-y-auto{overflow-y:auto}.border{border-style:var(--tw-border-style);border-width:1px}.p-4{padding:calc(var(--spacing)*4)}.px-1\.5{padding-inline:calc(var(--spacing)*1.5)}.px-2\.5{padding-inline:calc(var(--spacing)*2.5)}.px-3{padding-inline:calc(var(--spacing)*3)}.px-4{padding-inline:calc(var(--spacing)*4)}.px-6{padding-inline:calc(var(--spacing)*6)}.py-0\.5{padding-block:calc(var(--spacing)*.5)}.py-1{padding-block:calc(var(--spacing)*1)}.py-1\.5{padding-block:calc(var(--spacing)*1.5)}.py-2{padding-block:calc(var(--spacing)*2)}.pt-0{padding-top:calc(var(--spacing)*0)}.pr-2{padding-right:calc(var(--spacing)*2)}.pr-3{padding-right:calc(var(--spacing)*3)}.text-left{text-align:left}.text-right{text-align:right}.align-middle{vertical-align:middle}.whitespace-pre{white-space:pre}.opacity-50{opacity:.5}.transition-colors{transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.select-none{-webkit-user-select:none;user-select:none}@media(hover:hover){.hover\:bg-\[\#58A6FF\]\/40:hover{background-color:#58a6ff66}}}body{color:#e6edf3;background-color:#0d1117;margin:0;padding:0;font-family:JetBrains Mono,monospace;overflow:hidden}@keyframes blink{0%,to{opacity:1}50%{opacity:0}}.cursor-blink{animation:1s step-end infinite blink}::-webkit-scrollbar{width:8px}::-webkit-scrollbar-track{background:#0d1117}::-webkit-scrollbar-thumb{background:#30363d;border-radius:4px}::-webkit-scrollbar-thumb:hover{background:#484f58}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@keyframes spin{to{transform:rotate(360deg)}}
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-BZU2xrvr.js"></script>
12
- <link rel="stylesheet" crossorigin href="/assets/index-Xj2Kq8Xb.css">
11
+ <script type="module" crossorigin src="/assets/index-BT2Q0q7j.js"></script>
12
+ <link rel="stylesheet" crossorigin href="/assets/index-DA2rIHWo.css">
13
13
  </head>
14
14
  <body>
15
15
  <div id="root"></div>
@@ -10,11 +10,14 @@ 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
- app.get('/{*splat}', (_req, res) => {
17
- res.sendFile(path.join(distPath, 'index.html'));
16
+ app.get('/{*splat}', (_req, res, next) => {
17
+ res.sendFile(path.join(distPath, 'index.html'), (err) => {
18
+ if (err)
19
+ next();
20
+ });
18
21
  });
19
22
  return app;
20
23
  }
@@ -25,8 +28,5 @@ if (isDirectRun) {
25
28
  const port = parseInt(process.env.PORT || '4321', 10);
26
29
  const isGitRepo = process.env.IS_GIT_REPO !== 'false';
27
30
  const app = createServer(repoPath, isGitRepo);
28
- app.listen(port, () => {
29
- console.log(`VisualGit server running at http://localhost:${port}`);
30
- console.log(`Repo: ${repoPath}`);
31
- });
31
+ app.listen(port);
32
32
  }
@@ -1,10 +1,10 @@
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) => {
7
- const { provider = 'claude', mode = 'full', content, filePath } = req.body;
7
+ const { provider = 'claude', mode = 'full', content, filePath, model } = req.body;
8
8
  if (!content) {
9
9
  res.status(400).json({ error: 'content is required' });
10
10
  return;
@@ -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)) {
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,39 @@ import { spawn } from 'child_process';
2
2
  export class AiService {
3
3
  hasConversation = false;
4
4
  buildPrompt(mode, content, filePath) {
5
+ const markdownInstruction = 'Format your response using Markdown (headings, bold, bullet points, code blocks).';
5
6
  if (mode === 'selection') {
6
- return `Analyze this selected code snippet${filePath ? ` from ${filePath}` : ''}. Explain what it does, any issues, and potential improvements. Be concise with bullet points.\n\n\`\`\`\n${content}\n\`\`\``;
7
+ return `Analyze this selected code snippet${filePath ? ` from ${filePath}` : ''}. Explain what it does, any issues, and potential improvements. Be concise with bullet points. ${markdownInstruction}\n\n\`\`\`\n${content}\n\`\`\``;
7
8
  }
8
9
  if (mode === 'file') {
9
- return `Analyze the changes in ${filePath || 'this file'}. Explain what changed and why it matters, key improvements, and any risks. Be concise with bullet points.\n\n\`\`\`diff\n${content}\n\`\`\``;
10
+ return `Analyze the changes in ${filePath || 'this file'}. Explain what changed and why it matters, key improvements, and any risks. Be concise with bullet points. ${markdownInstruction}\n\n\`\`\`diff\n${content}\n\`\`\``;
10
11
  }
11
- return `You are a senior software engineer. Analyze this complete git diff and provide:\n\n1. Executive summary of all changes\n2. Key improvements or patterns introduced\n3. Any potential risks or concerns\n4. How the changes relate to each other\n\nBe concise with bullet points. Do not repeat the code.\n\n\`\`\`diff\n${content}\n\`\`\``;
12
+ return `You are a senior software engineer. Analyze this complete git diff and provide:\n\n1. Executive summary of all changes\n2. Key improvements or patterns introduced\n3. Any potential risks or concerns\n4. How the changes relate to each other\n\nBe concise with bullet points. Do not repeat the code. ${markdownInstruction}\n\n\`\`\`diff\n${content}\n\`\`\``;
12
13
  }
13
- getCommand(provider, prompt) {
14
+ getCommand(provider, model = 'sonnet') {
14
15
  if (provider === 'claude') {
15
- const args = ['-p', '--model', 'sonnet'];
16
+ const args = ['-p', '--model', model];
16
17
  if (this.hasConversation)
17
18
  args.push('--continue');
18
- args.push(prompt);
19
- return { command: 'claude', args };
19
+ return { command: 'claude', args, useStdin: true };
20
20
  }
21
21
  return {
22
22
  command: 'openai',
23
- args: ['api', 'chat.completions.create', '-m', 'gpt-4o', '-g', 'user', prompt],
23
+ args: ['api', 'chat.completions.create', '-m', 'gpt-4o', '-g', 'user'],
24
+ useStdin: true,
24
25
  };
25
26
  }
26
- async *analyze(provider, mode, content, filePath) {
27
+ async *analyze(provider, mode, content, filePath, model, repoPath) {
27
28
  const prompt = this.buildPrompt(mode, content, filePath);
28
- const { command, args } = this.getCommand(provider, prompt);
29
+ const { command, args, useStdin } = this.getCommand(provider, model);
29
30
  const env = { ...process.env };
30
31
  delete env.CLAUDECODE;
31
- const proc = spawn(command, args, { env });
32
+ const cwd = repoPath || process.cwd();
33
+ const proc = spawn(command, args, { env, cwd, stdio: ['pipe', 'pipe', 'pipe'] });
34
+ if (useStdin) {
35
+ proc.stdin.write(prompt);
36
+ proc.stdin.end();
37
+ }
32
38
  const result = await new Promise((resolve, reject) => {
33
39
  let data = '';
34
40
  let stderr = '';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jxtools/visualgit",
3
- "version": "1.1.0",
3
+ "version": "1.3.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": {