From 80e90c4875d2f9be492387e2b8f80fd40fdbe61f Mon Sep 17 00:00:00 2001 From: sami-codeai Date: Sun, 17 May 2026 16:56:56 +0530 Subject: [PATCH 1/2] fix: replace process.exit() with custom Error throws (#18) --- bin/smartcommit.ts | 8 +++++++- src/index.ts | 10 +++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/bin/smartcommit.ts b/bin/smartcommit.ts index 04817cc..88f94bd 100644 --- a/bin/smartcommit.ts +++ b/bin/smartcommit.ts @@ -11,7 +11,13 @@ program .option("--auto", "Auto accept commit without confirmation") .option("--model ", "Specify Ollama model"); program.action(async (options) => { - await run(options); + try { + await run(options); + process.exit(0); + } catch (error: any) { + console.error(error.message); + process.exit(1); + } }); program.parse(); diff --git a/src/index.ts b/src/index.ts index 1d75832..27f269d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -25,16 +25,13 @@ export async function run(options: CliOptions) { // Ensure we are inside a Git repo const repo = await isGitRepo(); if (!repo) { - console.log(chalk.red("Not inside a Git repository.")); - process.exit(1); + throw new Error(chalk.red("Not inside a Git repository.")); } const stagedFiles = await getStagedFiles(); if (stagedFiles.length === 0) { - console.log(chalk.yellow("No staged changes found.")); - console.log("Stage changes using: git add "); - process.exit(0); + throw new Error(chalk.yellow("No staged changes found.") + "\nStage changes using: git add "); } // Enrich file stats @@ -98,8 +95,7 @@ export async function run(options: CliOptions) { const result = await confirmCommit(commitMessage); if (!result) { - console.log("Commit cancelled."); - process.exit(0); + throw new Error("Commit cancelled."); } finalMessage = result; From ba714aef11c2e4c16d898e158c3343fd529a1a2e Mon Sep 17 00:00:00 2001 From: sami-codeai Date: Wed, 20 May 2026 12:28:38 +0530 Subject: [PATCH 2/2] fix: resolve coderabbit reviews and lint warnings --- bin/smartcommit.ts | 15 +++++++++++++-- src/index.test.ts | 15 +++++++++++++++ src/index.ts | 7 ++++--- src/utils/errors.ts | 20 ++++++++++++++++++++ 4 files changed, 52 insertions(+), 5 deletions(-) create mode 100644 src/utils/errors.ts diff --git a/bin/smartcommit.ts b/bin/smartcommit.ts index 88f94bd..828664c 100644 --- a/bin/smartcommit.ts +++ b/bin/smartcommit.ts @@ -1,7 +1,9 @@ #!/usr/bin/env node import { program } from "commander"; +import chalk from "chalk"; import { run } from "../src/index"; +import { CancellationError } from "../src/utils/errors"; import pkg from "../package.json"; program .name("smartcommit") @@ -14,8 +16,17 @@ program.action(async (options) => { try { await run(options); process.exit(0); - } catch (error: any) { - console.error(error.message); + } catch (error: unknown) { + if (error instanceof CancellationError) { + console.log(error.message); + process.exit(0); + } + + if (error instanceof Error) { + console.error(chalk.red(error.message)); + } else { + console.error(chalk.red("An unknown error occurred.")); + } process.exit(1); } }); diff --git a/src/index.test.ts b/src/index.test.ts index ef99784..5d47053 100644 --- a/src/index.test.ts +++ b/src/index.test.ts @@ -1,5 +1,6 @@ import { describe, it, expect } from 'vitest'; import { detectScope } from './analyzer/scopeDetector'; +import { ValidationError, CancellationError } from './utils/errors'; describe('detectScope', () => { it('should detect scope from src directory', () => { @@ -17,3 +18,17 @@ describe('detectScope', () => { expect(detectScope(files)).toBe('ui'); }); }); + +describe('Errors', () => { + it('should create ValidationError with correct name and message', () => { + const error = new ValidationError('test error'); + expect(error.name).toBe('ValidationError'); + expect(error.message).toBe('test error'); + }); + + it('should create CancellationError with default message', () => { + const error = new CancellationError(); + expect(error.name).toBe('CancellationError'); + expect(error.message).toBe('Commit cancelled.'); + }); +}); diff --git a/src/index.ts b/src/index.ts index 27f269d..f0237e1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,6 +13,7 @@ import { commit } from "./git/commit"; import { enhanceCommit } from "./llm/ollamaEnhancer"; import { loadConfig } from "./config/loadConfig"; import { isOllamaRunning, getBestModel } from "./llm/checkOllama"; +import { ValidationError, CancellationError } from "./utils/errors"; interface CliOptions { ai?: boolean; @@ -25,13 +26,13 @@ export async function run(options: CliOptions) { // Ensure we are inside a Git repo const repo = await isGitRepo(); if (!repo) { - throw new Error(chalk.red("Not inside a Git repository.")); + throw new ValidationError("Not inside a Git repository."); } const stagedFiles = await getStagedFiles(); if (stagedFiles.length === 0) { - throw new Error(chalk.yellow("No staged changes found.") + "\nStage changes using: git add "); + throw new ValidationError("No staged changes found.\nStage changes using: git add "); } // Enrich file stats @@ -95,7 +96,7 @@ export async function run(options: CliOptions) { const result = await confirmCommit(commitMessage); if (!result) { - throw new Error("Commit cancelled."); + throw new CancellationError(); } finalMessage = result; diff --git a/src/utils/errors.ts b/src/utils/errors.ts new file mode 100644 index 0000000..c6c9f1f --- /dev/null +++ b/src/utils/errors.ts @@ -0,0 +1,20 @@ +export class GitBunError extends Error { + constructor(message: string) { + super(message); + this.name = "GitBunError"; + } +} + +export class ValidationError extends GitBunError { + constructor(message: string) { + super(message); + this.name = "ValidationError"; + } +} + +export class CancellationError extends GitBunError { + constructor(message: string = "Commit cancelled.") { + super(message); + this.name = "CancellationError"; + } +}