Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/commands/suggest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ async function acceptAndCommit(selected: Suggestion, config: Config, diff: strin
if (auto) {
try {
const result = commit(selected.message, selected.body);
console.log(pc.green(result.trim()));
console.log(pc.green(result.summary));
} catch (err) {
const msg = err instanceof Error ? err.message : 'Unknown error';
outro(pc.red(`Commit failed: ${msg}`));
Expand Down Expand Up @@ -208,7 +208,7 @@ async function acceptAndCommit(selected: Suggestion, config: Config, diff: strin

try {
const result = commit(finalMessage, finalBody);
console.log(pc.green(result.trim()));
console.log(pc.green(result.summary));

await appendEntry({
timestamp: new Date().toISOString(),
Expand Down
69 changes: 62 additions & 7 deletions src/git/diff.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
import { execSync, spawnSync } from 'node:child_process';
import { writeFileSync, unlinkSync } from 'node:fs';
import { tmpdir } from 'node:os';
import { join } from 'node:path';
import { join, normalize } from 'node:path';

export interface DiffResult {
diff: string;
hasChanges: boolean;
staged: boolean;
}

export interface CommitResult {
hash: string;
summary: string;
output: string;
}

const GIT_DIFF_MAX_BUFFER = 100 * 1024 * 1024;

export function checkGitRepo(): void {
try {
execSync('git rev-parse --git-dir', { encoding: 'utf-8', stdio: 'pipe' });
Expand All @@ -18,8 +26,24 @@ export function checkGitRepo(): void {
}
}

export function hasCommits(): boolean {
try {
const count = execSync('git rev-list --count HEAD', {
encoding: 'utf-8',
stdio: 'pipe',
}).trim();

return Number.parseInt(count, 10) > 0;
} catch {
return false;
}
}

export function getStagedDiff(): DiffResult {
const diff = execSync('git diff --cached', { encoding: 'utf-8' });
const diff = execSync('git diff --cached', {
encoding: 'utf-8',
maxBuffer: GIT_DIFF_MAX_BUFFER,
});
return {
diff: diff.trim(),
hasChanges: diff.trim().length > 0,
Expand All @@ -28,16 +52,29 @@ export function getStagedDiff(): DiffResult {
}

export function getUnstagedDiff(): DiffResult {
const diff = execSync('git diff', { encoding: 'utf-8' });
const diff = execSync('git diff', {
encoding: 'utf-8',
maxBuffer: GIT_DIFF_MAX_BUFFER,
});
return {
diff: diff.trim(),
hasChanges: diff.trim().length > 0,
staged: false,
};
}

function parseCommitOutput(output: string): CommitResult {
const summary = output.trim().split('\n').find(Boolean) ?? '';
const match = summary.match(/^\[(?:.+\s)?([a-f0-9]{7,})\]\s+(.+)$/i);

export function commit(message: string, body?: string): string {
return {
hash: match?.[1] ?? '',
summary: match?.[2] ?? summary,
output,
};
}

export function commit(message: string, body?: string): CommitResult {
const fullMessage = body ? `${message}\n\n${body}` : message;
const tmpFile = join(tmpdir(), `commit-echo-msg-${process.pid}-${Date.now()}.txt`);
try {
Expand All @@ -51,12 +88,30 @@ export function commit(message: string, body?: string): string {
const detail = [result.stderr, result.stdout].filter(Boolean).join('\n').trim();
throw new Error(detail || `git commit exited with code ${result.status}`);
}
return result.stdout;
return parseCommitOutput(result.stdout);
} finally {
try { unlinkSync(tmpFile); } catch {}
try {
unlinkSync(tmpFile);
} catch {}
}
}

export function getRepoRoot(): string {
return execSync('git rev-parse --show-toplevel', { encoding: 'utf-8' }).trim();
return normalize(execSync('git rev-parse --show-toplevel', { encoding: 'utf-8' }).trim());
}

export function getBranchName(): string {
try {
return execSync('git rev-parse --abbrev-ref HEAD', { encoding: 'utf-8' }).trim();
} catch {
return 'unknown';
}
}

export function getLastCommitMessage(): string {
try {
return execSync('git log -1 --format=%s', { encoding: 'utf-8', stdio: 'pipe' }).trim();
} catch {
return '';
}
}
Loading