diff --git a/package.json b/package.json index 33ffc8d..9d13b91 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "displayName": "commitollama", "description": "AI Commits with ollama", "publisher": "Commitollama", - "version": "3.0.0", + "version": "3.0.1", "repository": { "type": "git", "url": "https://github.com/anjerodev/commitollama.git" diff --git a/src/diffFallback.ts b/src/diffFallback.ts new file mode 100644 index 0000000..da278d1 --- /dev/null +++ b/src/diffFallback.ts @@ -0,0 +1,26 @@ +export function buildDiffFallbackSummary(file: string, diff: string): string { + const lines = diff.split('\n') + const addedLines = lines + .filter((line) => line.startsWith('+') && !line.startsWith('+++')) + .map((line) => line.slice(1).trim()) + .filter(Boolean) + const removedCount = lines.filter( + (line) => line.startsWith('-') && !line.startsWith('---'), + ).length + + if (addedLines.length > 0) { + const preview = addedLines.slice(0, 2).join('; ') + const clipped = + preview.length > 80 ? `${preview.slice(0, 77)}...` : preview + if (removedCount > 0) { + return `Update ${file}: add ${addedLines.length} line(s), remove ${removedCount} line(s) — ${clipped}` + } + return `Update ${file}: add ${addedLines.length} line(s) — ${clipped}` + } + + if (removedCount > 0) { + return `Update ${file}: remove ${removedCount} line(s)` + } + + return `Update ${file}` +} diff --git a/src/scheduler.ts b/src/scheduler.ts index 0bf21a8..10df8de 100644 --- a/src/scheduler.ts +++ b/src/scheduler.ts @@ -1,5 +1,6 @@ import * as vscode from 'vscode' import { summaryCache } from './cache' +import { isLowQualitySummary } from './commitQuality' import { config } from './config' import { logExtensionError } from './security/log' import { summarizeFileDiff } from './summarizer' @@ -101,7 +102,9 @@ export class BackgroundScanner { } const summary = await summarizeFileDiff(workingDiff) - summaryCache.set(uri.fsPath, hash, summary) + if (!isLowQualitySummary(summary)) { + summaryCache.set(uri.fsPath, hash, summary) + } } catch (error) { logExtensionError(`backgroundScan ${uri.fsPath}`, error) } diff --git a/src/test/diffFallback.test.ts b/src/test/diffFallback.test.ts new file mode 100644 index 0000000..a378a0d --- /dev/null +++ b/src/test/diffFallback.test.ts @@ -0,0 +1,32 @@ +import * as assert from 'node:assert' +import { buildDiffFallbackSummary } from '../diffFallback' + +suite('diff fallback', () => { + test('Should summarize added lines from a unified diff', () => { + const diff = [ + '--- a/src/foo.ts', + '+++ b/src/foo.ts', + '@@ -1,2 +1,3 @@', + ' const x = 1', + '+const y = 2', + ' return x', + ].join('\n') + + const summary = buildDiffFallbackSummary('src/foo.ts', diff) + assert.match(summary, /add 1 line/) + assert.match(summary, /const y = 2/) + }) + + test('Should summarize removed lines', () => { + const diff = [ + '--- a/src/foo.ts', + '+++ b/src/foo.ts', + '@@ -1,2 +1,1 @@', + '-const y = 2', + ' const x = 1', + ].join('\n') + + const summary = buildDiffFallbackSummary('src/foo.ts', diff) + assert.match(summary, /remove 1 line/) + }) +}) diff --git a/src/utils.ts b/src/utils.ts index 572f881..cb791cb 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,6 +1,8 @@ +import { relative } from 'node:path' import * as vscode from 'vscode' import { summaryCache } from './cache' import { isLowQualitySummary } from './commitQuality' +import { buildDiffFallbackSummary } from './diffFallback' import { type ChangeSummary, getCommitMessage } from './generator' import { ensureModelSelected } from './modelSelection' import { formatExtensionError, logExtensionError } from './security/log' @@ -23,39 +25,62 @@ export function setConfig( .update(key, value, vscode.ConfigurationTarget.Workspace) } +function getRepoRelativePath(repo: Repository, uri: vscode.Uri): string { + const rootPath = repo.rootUri.fsPath + if (uri.fsPath.startsWith(rootPath)) { + return relative(rootPath, uri.fsPath).replace(/\\/g, '/') + } + return vscode.workspace.asRelativePath(uri, false) +} + export async function getSummaryUriDiff( repo: Repository, uri: vscode.Uri, ): Promise { - const path = vscode.workspace.asRelativePath(uri) + const path = getRepoRelativePath(repo, uri) return repo.diffIndexWithHEAD(path) } +async function resolveSummary( + file: string, + cacheKey: string, + diff: string, + diffHash: string, +): Promise { + const cached = summaryCache.get(cacheKey) + if (cached?.diffHash === diffHash && !isLowQualitySummary(cached.summary)) { + return cached.summary + } + + try { + const summary = await summarizeFileDiff(diff) + if (!isLowQualitySummary(summary)) { + summaryCache.set(cacheKey, diffHash, summary) + return summary + } + } catch (error) { + logExtensionError('summarizeStagedChange', error) + } + + return buildDiffFallbackSummary(file, diff) +} + async function summarizeStagedChange( repo: Repository, uri: vscode.Uri, ): Promise { - const path = vscode.workspace.asRelativePath(uri) + const path = getRepoRelativePath(repo, uri) const diff = await repo.diffIndexWithHEAD(path) if (!diff || diff.trim() === '') { return null } - const hash = summaryCache.computeHash(diff) - const cached = summaryCache.get(uri.fsPath) - - let summary: string - if (cached && cached.diffHash === hash) { - summary = cached.summary - } else { - summary = await summarizeFileDiff(diff) - summaryCache.set(uri.fsPath, hash, summary) - } - - if (isLowQualitySummary(summary)) { - return null - } - + const summary = await resolveSummary( + path, + uri.fsPath, + diff, + summaryCache.computeHash(diff), + ) return { file: path, summary } } @@ -95,13 +120,16 @@ export async function createCommitMessage(repo: Repository) { if (summaries.length === 0) { const fullDiff = await repo.diff(true) if (fullDiff?.trim()) { - const summary = await summarizeFileDiff(fullDiff) - if (!isLowQualitySummary(summary)) { - summaries.push({ - file: 'staged changes', - summary, - }) - } + const summary = await resolveSummary( + 'staged changes', + 'staged changes', + fullDiff, + summaryCache.computeHash(fullDiff), + ) + summaries.push({ + file: 'staged changes', + summary, + }) } } diff --git a/tsconfig.json b/tsconfig.json index dc2124d..cb503a2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,6 +3,7 @@ "module": "commonjs", "target": "ES2021", "lib": ["ES2021", "DOM"], + "typeRoots": ["./node_modules/@types"], "types": ["node", "mocha"], "skipLibCheck": true, "noEmit": true,