@vavasilva/git-commit-ai 0.2.0 → 0.2.1

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/index.js CHANGED
@@ -175,7 +175,16 @@ function addFiles(...paths) {
175
175
  if (paths.length === 0) {
176
176
  paths = ["."];
177
177
  }
178
- runGit("add", ...paths);
178
+ try {
179
+ runGit("add", ...paths);
180
+ return true;
181
+ } catch (error) {
182
+ const err = error;
183
+ if (err.message.includes("ignored by one of your .gitignore")) {
184
+ return false;
185
+ }
186
+ throw error;
187
+ }
179
188
  }
180
189
  function commit(message) {
181
190
  runGit("commit", "-m", `"${message.replace(/"/g, '\\"')}"`);
@@ -636,7 +645,10 @@ async function handleIndividualCommits(backend, cfg, skipConfirm) {
636
645
  }
637
646
  console.log(chalk2.dim(`Found ${filesToCommit.length} files to commit individually.`));
638
647
  for (const filePath of filesToCommit) {
639
- addFiles(filePath);
648
+ const added = addFiles(filePath);
649
+ if (!added) {
650
+ continue;
651
+ }
640
652
  const diffResult = getFileDiff(filePath);
641
653
  if (diffResult.isEmpty) {
642
654
  continue;
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/cli.ts","../src/config.ts","../src/backends/ollama.ts","../src/git.ts","../src/prompts.ts","../src/hook.ts","../src/debug.ts","../src/index.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { createInterface } from \"node:readline\";\n\nimport { loadConfig, saveConfig, showConfig, getConfigPath } from \"./config.js\";\nimport { OllamaBackend } from \"./backends/ollama.js\";\nimport {\n getStagedDiff,\n getFileDiff,\n addFiles,\n commit,\n push,\n getModifiedFiles,\n GitError,\n} from \"./git.js\";\nimport {\n buildPrompt,\n buildSummarizePrompt,\n cleanMessage,\n validateMessage,\n fixMessage,\n} from \"./prompts.js\";\nimport { installHook, removeHook, isHookInstalled } from \"./hook.js\";\nimport {\n enableDebug,\n debug,\n debugConfig,\n debugDiff,\n debugPrompt,\n debugResponse,\n debugValidation,\n} from \"./debug.js\";\nimport type { Config, DiffResult } from \"./types.js\";\n\nasync function promptUser(question: string, choices: string[]): Promise<string> {\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n const normalized = answer.trim().toLowerCase();\n if (choices.includes(normalized)) {\n resolve(normalized);\n } else {\n resolve(choices[0]); // default to first choice\n }\n });\n });\n}\n\nasync function promptEdit(currentMessage: string): Promise<string> {\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise((resolve) => {\n console.log(chalk.dim(\"\\nEnter new commit message (or press Enter to keep current):\"));\n rl.question(`Message [${currentMessage}]: `, (answer) => {\n rl.close();\n resolve(answer.trim() || currentMessage);\n });\n });\n}\n\nasync function generateMessage(\n backend: OllamaBackend,\n diffContent: string,\n context: string,\n temperatures: number[]\n): Promise<string | null> {\n const prompt = buildPrompt(diffContent, context);\n debugPrompt(prompt);\n\n for (const temp of temperatures) {\n debug(`Trying temperature: ${temp}`);\n try {\n const rawMessage = await backend.generate(prompt, temp);\n debugResponse(rawMessage);\n\n const message = cleanMessage(rawMessage);\n const isValid = validateMessage(message);\n debugValidation(message, isValid);\n\n if (isValid) {\n return message;\n }\n\n // Try to fix the message\n const fixed = fixMessage(message);\n if (validateMessage(fixed)) {\n debugValidation(fixed, true, fixed);\n return fixed;\n }\n } catch (e) {\n const error = e as Error;\n debug(`Generation error: ${error.message}`);\n console.log(chalk.yellow(`Warning: Generation failed at temp ${temp}: ${error.message}`));\n }\n }\n\n return null;\n}\n\nfunction showMessage(message: string): void {\n console.log();\n console.log(chalk.green(\"┌─\") + chalk.green(\"─\".repeat(68)) + chalk.green(\"─┐\"));\n console.log(chalk.green(\"│\") + chalk.bold(\" 📝 Generated commit message\") + \" \".repeat(40) + chalk.green(\"│\"));\n console.log(chalk.green(\"├─\") + chalk.green(\"─\".repeat(68)) + chalk.green(\"─┤\"));\n console.log(chalk.green(\"│\") + \" \" + message.padEnd(67) + chalk.green(\"│\"));\n console.log(chalk.green(\"└─\") + chalk.green(\"─\".repeat(68)) + chalk.green(\"─┘\"));\n console.log();\n}\n\nasync function promptAction(message: string): Promise<string> {\n showMessage(message);\n return promptUser(\n \"[C]onfirm [E]dit [R]egenerate [A]bort? \",\n [\"c\", \"e\", \"r\", \"a\"]\n );\n}\n\nasync function runCommitFlow(\n backend: OllamaBackend,\n cfg: Config,\n diffContent: string,\n context: string,\n skipConfirm: boolean\n): Promise<string | null> {\n const temperatures = [cfg.temperature, ...cfg.retry_temperatures];\n const spinner = ora(\"Generating commit message...\").start();\n\n while (true) {\n let message: string | null;\n try {\n message = await generateMessage(backend, diffContent, context, temperatures);\n } finally {\n spinner.stop();\n }\n\n if (message === null) {\n console.log(chalk.red(\"Error: Failed to generate a valid commit message.\"));\n message = \"chore: update files\";\n console.log(chalk.yellow(`Using fallback: ${message}`));\n }\n\n if (skipConfirm) {\n return message;\n }\n\n const action = await promptAction(message);\n\n if (action === \"c\") {\n return message;\n } else if (action === \"e\") {\n return promptEdit(message);\n } else if (action === \"r\") {\n console.log(chalk.dim(\"Regenerating...\"));\n spinner.start(\"Generating commit message...\");\n continue;\n } else if (action === \"a\") {\n return null;\n }\n }\n}\n\nasync function handleSingleCommit(\n backend: OllamaBackend,\n cfg: Config,\n skipConfirm: boolean\n): Promise<void> {\n const diffResult = getStagedDiff();\n\n if (diffResult.isEmpty) {\n console.log(chalk.yellow(\"No changes to commit.\"));\n process.exit(0);\n }\n\n debugDiff(diffResult.diff, diffResult.files);\n const context = `Files changed:\\n${diffResult.files.slice(0, 5).join(\"\\n\")}\\nStats: ${diffResult.stats}`;\n\n const message = await runCommitFlow(backend, cfg, diffResult.diff, context, skipConfirm);\n\n if (message === null) {\n console.log(chalk.yellow(\"Aborted.\"));\n process.exit(0);\n }\n\n try {\n commit(message);\n debug(`Commit successful: ${message}`);\n console.log(chalk.green(\"✓ Committed:\"), message);\n } catch (e) {\n const error = e as GitError;\n debug(`Commit failed: ${error.message}`);\n console.log(chalk.red(`Error: ${error.message}`));\n process.exit(1);\n }\n}\n\nasync function handleIndividualCommits(\n backend: OllamaBackend,\n cfg: Config,\n skipConfirm: boolean\n): Promise<void> {\n const filesToCommit = getModifiedFiles();\n\n if (filesToCommit.length === 0) {\n console.log(chalk.yellow(\"No files to commit.\"));\n process.exit(0);\n }\n\n console.log(chalk.dim(`Found ${filesToCommit.length} files to commit individually.`));\n\n for (const filePath of filesToCommit) {\n addFiles(filePath);\n const diffResult = getFileDiff(filePath);\n\n if (diffResult.isEmpty) {\n continue;\n }\n\n console.log(chalk.bold(`\\nProcessing: ${filePath}`));\n\n const context = `File: ${filePath}\\nStats: ${diffResult.stats}`;\n const message = await runCommitFlow(backend, cfg, diffResult.diff, context, skipConfirm);\n\n if (message === null) {\n console.log(chalk.yellow(`Skipped: ${filePath}`));\n continue;\n }\n\n try {\n commit(message);\n console.log(chalk.green(\"✓ Committed:\"), message);\n } catch (e) {\n const error = e as GitError;\n console.log(chalk.red(`Error committing ${filePath}: ${error.message}`));\n }\n }\n}\n\nexport function createProgram(): Command {\n const program = new Command();\n\n program\n .name(\"git-commit-ai\")\n .description(\"Generate commit messages using local LLMs\")\n .version(\"0.2.0\")\n .option(\"-p, --push\", \"Push after commit\")\n .option(\"-y, --yes\", \"Skip confirmation\")\n .option(\"-i, --individual\", \"Commit files individually\")\n .option(\"-d, --debug\", \"Enable debug output\")\n .option(\"--hook-mode\", \"Called by git hook (outputs message only)\")\n .action(async (options) => {\n if (options.debug) {\n enableDebug();\n debug(\"Debug mode enabled\");\n }\n\n const cfg = loadConfig();\n debugConfig(cfg);\n\n const backend = new OllamaBackend(cfg.model, cfg.ollama_url);\n\n // Check if Ollama is available\n const available = await backend.isAvailable();\n if (!available) {\n if (options.hookMode) {\n process.exit(1);\n }\n console.log(chalk.red(\"Error: Ollama is not running.\"));\n console.log(chalk.dim(\"Start it with: brew services start ollama\"));\n process.exit(1);\n }\n\n // Hook mode: just output the message\n if (options.hookMode) {\n const diffResult = getStagedDiff();\n if (diffResult.isEmpty) {\n process.exit(1);\n }\n\n const context = `Files changed:\\n${diffResult.files.slice(0, 5).join(\"\\n\")}\\nStats: ${diffResult.stats}`;\n const temperatures = [cfg.temperature, ...cfg.retry_temperatures];\n const message = await generateMessage(backend, diffResult.diff, context, temperatures);\n\n if (message) {\n console.log(message);\n process.exit(0);\n }\n process.exit(1);\n }\n\n // Stage all files\n addFiles(\".\");\n\n if (options.individual) {\n await handleIndividualCommits(backend, cfg, options.yes);\n } else {\n await handleSingleCommit(backend, cfg, options.yes);\n }\n\n if (options.push) {\n try {\n push();\n console.log(chalk.green(\"✓ Changes pushed to remote.\"));\n } catch (e) {\n const error = e as GitError;\n console.log(chalk.red(`Error pushing: ${error.message}`));\n process.exit(1);\n }\n }\n });\n\n program\n .command(\"config\")\n .description(\"Show or edit configuration\")\n .option(\"-e, --edit\", \"Create/edit configuration file\")\n .action((options) => {\n const cfg = loadConfig();\n\n if (options.edit) {\n console.log(chalk.dim(\"Creating default config file...\"));\n saveConfig(cfg);\n console.log(chalk.green(`Config saved to: ${getConfigPath()}`));\n console.log(chalk.dim(\"Edit this file to customize settings.\"));\n } else {\n console.log(showConfig(cfg));\n }\n });\n\n program\n .command(\"summarize\")\n .description(\"Summarize staged changes in plain English\")\n .option(\"--diff\", \"Also show the raw diff\")\n .option(\"-d, --debug\", \"Enable debug output\")\n .action(async (options) => {\n if (options.debug) {\n enableDebug();\n }\n\n const cfg = loadConfig();\n const backend = new OllamaBackend(cfg.model, cfg.ollama_url);\n\n const available = await backend.isAvailable();\n if (!available) {\n console.log(chalk.red(\"Error: Ollama is not running.\"));\n console.log(chalk.dim(\"Start it with: brew services start ollama\"));\n process.exit(1);\n }\n\n const diffResult = getStagedDiff();\n\n if (diffResult.isEmpty) {\n console.log(chalk.yellow(\"No staged changes to summarize.\"));\n console.log(chalk.dim(\"Stage changes with: git add <files>\"));\n process.exit(0);\n }\n\n debugDiff(diffResult.diff, diffResult.files);\n\n console.log(chalk.bold(`\\nFiles to summarize: ${diffResult.files.length}`));\n for (const f of diffResult.files.slice(0, 10)) {\n console.log(` • ${f}`);\n }\n if (diffResult.files.length > 10) {\n console.log(` ... and ${diffResult.files.length - 10} more`);\n }\n\n const context = `Files changed: ${diffResult.files.slice(0, 5).join(\", \")}\\nStats: ${diffResult.stats}`;\n const prompt = buildSummarizePrompt(diffResult.diff, context);\n debugPrompt(prompt);\n\n const spinner = ora(\"Generating summary...\").start();\n\n try {\n const summary = await backend.generate(prompt, cfg.temperature);\n spinner.stop();\n debugResponse(summary);\n\n console.log();\n console.log(chalk.blue(\"┌─\") + chalk.blue(\"─\".repeat(68)) + chalk.blue(\"─┐\"));\n console.log(chalk.blue(\"│\") + chalk.bold(\" 📋 Summary\") + \" \".repeat(58) + chalk.blue(\"│\"));\n console.log(chalk.blue(\"├─\") + chalk.blue(\"─\".repeat(68)) + chalk.blue(\"─┤\"));\n for (const line of summary.trim().split(\"\\n\")) {\n console.log(chalk.blue(\"│\") + \" \" + line.padEnd(67) + chalk.blue(\"│\"));\n }\n console.log(chalk.blue(\"└─\") + chalk.blue(\"─\".repeat(68)) + chalk.blue(\"─┘\"));\n\n if (options.diff) {\n console.log();\n console.log(chalk.dim(\"┌─ 📄 Diff ─────────────────────────────────────────────────────────┐\"));\n console.log(chalk.dim(diffResult.diff));\n console.log(chalk.dim(\"└───────────────────────────────────────────────────────────────────┘\"));\n }\n } catch (e) {\n spinner.stop();\n const error = e as Error;\n debug(`Summary generation error: ${error.message}`);\n console.log(chalk.red(`Error generating summary: ${error.message}`));\n process.exit(1);\n }\n });\n\n program\n .command(\"hook\")\n .description(\"Manage git hook for automatic commit message generation\")\n .option(\"--install\", \"Install git hook\")\n .option(\"--remove\", \"Remove git hook\")\n .option(\"--status\", \"Check hook status\")\n .action((options) => {\n const showStatus = !options.install && !options.remove;\n\n if (showStatus || options.status) {\n if (isHookInstalled()) {\n console.log(chalk.green(\"✓ git-commit-ai hook is installed\"));\n } else {\n console.log(chalk.yellow(\"✗ git-commit-ai hook is not installed\"));\n console.log(chalk.dim(\"Install with: git-commit-ai hook --install\"));\n }\n return;\n }\n\n if (options.install) {\n const result = installHook();\n if (result.success) {\n console.log(chalk.green(`✓ ${result.message}`));\n console.log(chalk.dim(\"Now 'git commit' will auto-generate messages!\"));\n } else {\n console.log(chalk.red(`✗ ${result.message}`));\n process.exit(1);\n }\n return;\n }\n\n if (options.remove) {\n const result = removeHook();\n if (result.success) {\n console.log(chalk.green(`✓ ${result.message}`));\n } else {\n console.log(chalk.red(`✗ ${result.message}`));\n process.exit(1);\n }\n }\n });\n\n return program;\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, dirname } from \"node:path\";\nimport { parse as parseToml } from \"smol-toml\";\nimport type { Config } from \"./types.js\";\n\nconst DEFAULT_CONFIG: Config = {\n model: \"llama3.1:8b\",\n ollama_url: \"http://localhost:11434\",\n temperature: 0.7,\n retry_temperatures: [0.5, 0.3, 0.2],\n};\n\nexport function getConfigPath(): string {\n return join(homedir(), \".config\", \"git-commit-ai\", \"config.toml\");\n}\n\nexport function loadConfig(): Config {\n const configPath = getConfigPath();\n\n if (!existsSync(configPath)) {\n return { ...DEFAULT_CONFIG };\n }\n\n try {\n const content = readFileSync(configPath, \"utf-8\");\n const data = parseToml(content) as Partial<Config>;\n\n return {\n model: data.model ?? DEFAULT_CONFIG.model,\n ollama_url: data.ollama_url ?? DEFAULT_CONFIG.ollama_url,\n temperature: data.temperature ?? DEFAULT_CONFIG.temperature,\n retry_temperatures:\n data.retry_temperatures ?? DEFAULT_CONFIG.retry_temperatures,\n };\n } catch {\n return { ...DEFAULT_CONFIG };\n }\n}\n\nexport function saveConfig(config: Config): void {\n const configPath = getConfigPath();\n const dir = dirname(configPath);\n\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n const content = `# git-commit-ai configuration\nmodel = \"${config.model}\"\nollama_url = \"${config.ollama_url}\"\ntemperature = ${config.temperature}\nretry_temperatures = [${config.retry_temperatures.join(\", \")}]\n`;\n\n writeFileSync(configPath, content, \"utf-8\");\n}\n\nexport function showConfig(config: Config): string {\n return `Configuration:\n Model: ${config.model}\n Ollama URL: ${config.ollama_url}\n Temperature: ${config.temperature}\n Retry temperatures: [${config.retry_temperatures.join(\", \")}]\n Config file: ${getConfigPath()}`;\n}\n","import type { Backend } from \"../types.js\";\n\nexport class OllamaBackend implements Backend {\n private model: string;\n private baseUrl: string;\n\n constructor(model = \"llama3.1:8b\", baseUrl = \"http://localhost:11434\") {\n this.model = model;\n this.baseUrl = baseUrl;\n }\n\n async generate(prompt: string, temperature = 0.7): Promise<string> {\n const response = await fetch(`${this.baseUrl}/api/generate`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: this.model,\n prompt,\n temperature,\n stream: false,\n }),\n });\n\n if (!response.ok) {\n throw new Error(`Ollama API error: ${response.status}`);\n }\n\n const data = (await response.json()) as { response?: string };\n return data.response ?? \"\";\n }\n\n async isAvailable(): Promise<boolean> {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 5000);\n\n const response = await fetch(`${this.baseUrl}/api/tags`, {\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n return response.status === 200;\n } catch {\n return false;\n }\n }\n\n async hasModel(model?: string): Promise<boolean> {\n const checkModel = model ?? this.model;\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 5000);\n\n const response = await fetch(`${this.baseUrl}/api/tags`, {\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (response.status !== 200) {\n return false;\n }\n\n const data = (await response.json()) as {\n models?: Array<{ name?: string }>;\n };\n const models = data.models?.map((m) => m.name ?? \"\") ?? [];\n return models.some((m) => m.includes(checkModel));\n } catch {\n return false;\n }\n }\n}\n","import { execSync } from \"node:child_process\";\nimport type { DiffResult } from \"./types.js\";\n\nexport class GitError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"GitError\";\n }\n}\n\nfunction runGit(...args: string[]): string {\n try {\n const result = execSync([\"git\", ...args].join(\" \"), {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n return result.trim();\n } catch (error) {\n const err = error as { stderr?: string; message: string };\n const message = err.stderr?.trim() || err.message;\n throw new GitError(`Git command failed: ${message}`);\n }\n}\n\nfunction runGitSafe(...args: string[]): string {\n try {\n return runGit(...args);\n } catch {\n return \"\";\n }\n}\n\nexport function getStagedDiff(): DiffResult {\n const diff = runGitSafe(\"diff\", \"--cached\");\n const stats = runGitSafe(\"diff\", \"--cached\", \"--stat\");\n const filesOutput = runGitSafe(\"diff\", \"--cached\", \"--name-only\");\n const files = filesOutput.split(\"\\n\").filter((f) => f);\n\n return {\n diff,\n stats,\n files,\n isEmpty: !diff.trim(),\n };\n}\n\nexport function getFileDiff(filePath: string): DiffResult {\n const diff = runGitSafe(\"diff\", \"--cached\", \"--\", filePath);\n const stats = runGitSafe(\"diff\", \"--cached\", \"--stat\", \"--\", filePath);\n const files = diff ? [filePath] : [];\n\n return {\n diff,\n stats,\n files,\n isEmpty: !diff.trim(),\n };\n}\n\nexport function addFiles(...paths: string[]): void {\n if (paths.length === 0) {\n paths = [\".\"];\n }\n runGit(\"add\", ...paths);\n}\n\nexport function commit(message: string): string {\n runGit(\"commit\", \"-m\", `\"${message.replace(/\"/g, '\\\\\"')}\"`);\n return runGit(\"rev-parse\", \"HEAD\");\n}\n\nexport function push(): void {\n const branch = getCurrentBranch();\n runGit(\"push\", \"origin\", branch);\n}\n\nexport function getCurrentBranch(): string {\n return runGit(\"rev-parse\", \"--abbrev-ref\", \"HEAD\");\n}\n\nexport function getModifiedFiles(): string[] {\n const files = new Set<string>();\n\n // Modified and staged files\n const staged = runGitSafe(\"diff\", \"--cached\", \"--name-only\");\n if (staged) {\n staged.split(\"\\n\").forEach((f) => files.add(f));\n }\n\n // Modified but not staged\n const modified = runGitSafe(\"diff\", \"--name-only\");\n if (modified) {\n modified.split(\"\\n\").forEach((f) => files.add(f));\n }\n\n // Untracked files\n const untracked = runGitSafe(\"ls-files\", \"--others\", \"--exclude-standard\");\n if (untracked) {\n untracked.split(\"\\n\").forEach((f) => files.add(f));\n }\n\n return Array.from(files).filter((f) => f);\n}\n\nexport function hasStagedChanges(): boolean {\n const diff = runGitSafe(\"diff\", \"--cached\", \"--name-only\");\n return Boolean(diff.trim());\n}\n","const SUMMARIZE_PROMPT = `Summarize the following code changes in plain English.\n\nProvide a brief, clear summary that explains:\n1. What files were changed\n2. What was added, removed, or modified\n3. The likely purpose of these changes\n\nKeep it concise (3-5 bullet points). Focus on the \"what\" and \"why\".\n\n{context}\n\nDIFF:\n\\`\\`\\`\n{diff}\n\\`\\`\\`\n\nProvide only the summary, no additional commentary.`;\n\nconst KARMA_PROMPT = `Analyze the git diff below and create a commit message following Karma convention.\n\nFORMAT: <type>(<scope>): <subject>\n\nTYPES (use the most appropriate):\n- feat: new feature or capability\n- fix: bug fix\n- docs: documentation changes (README, comments, docstrings)\n- style: formatting only (whitespace, semicolons)\n- refactor: code change that neither fixes bug nor adds feature\n- test: adding or modifying tests\n- build: build system, dependencies, package config\n- chore: maintenance tasks\n\nRULES:\n- Scope is optional - use the main file/module name if relevant\n- Subject must describe WHAT changed in the diff, not a generic message\n- Use imperative mood: \"add\" not \"added\", \"fix\" not \"fixed\"\n- Lowercase, no period at end, max 72 chars\n\nEXAMPLES based on diff content:\n- Adding README.md → docs: add README with usage instructions\n- Fixing null check in auth.py → fix(auth): handle null user in login\n- New API endpoint → feat(api): add user profile endpoint\n- Updating dependencies → build: update httpx to 0.25.0\n\nIMPORTANT: Base your message ONLY on the actual changes shown in the diff below.\nDo NOT use the examples above if they don't match the diff content.\n\n{context}\n\nDIFF TO ANALYZE:\n\\`\\`\\`\n{diff}\n\\`\\`\\`\n\nReply with ONLY the commit message, nothing else. No quotes, no explanation.`;\n\nconst KARMA_PATTERN =\n /^(feat|fix|docs|style|refactor|test|chore|build|ci|perf|revert)(\\([^)]+\\))?:\\s*.+/;\n\nconst ACTION_TO_TYPE: Record<string, string> = {\n add: \"feat\",\n added: \"feat\",\n adding: \"feat\",\n create: \"feat\",\n implement: \"feat\",\n fix: \"fix\",\n fixed: \"fix\",\n fixing: \"fix\",\n repair: \"fix\",\n update: \"refactor\",\n updated: \"refactor\",\n updating: \"refactor\",\n improve: \"refactor\",\n remove: \"refactor\",\n removed: \"refactor\",\n removing: \"refactor\",\n delete: \"refactor\",\n document: \"docs\",\n documented: \"docs\",\n test: \"test\",\n tested: \"test\",\n testing: \"test\",\n};\n\nconst MAX_DIFF_CHARS = 8000;\n\nexport function truncateDiff(diff: string, maxChars = MAX_DIFF_CHARS): string {\n if (diff.length <= maxChars) {\n return diff;\n }\n\n let truncated = diff.slice(0, maxChars);\n const lastNewline = truncated.lastIndexOf(\"\\n\");\n if (lastNewline > maxChars * 0.8) {\n truncated = truncated.slice(0, lastNewline);\n }\n\n return truncated + \"\\n\\n[... diff truncated for brevity ...]\";\n}\n\nexport function buildPrompt(diff: string, context: string): string {\n const truncatedDiff = truncateDiff(diff);\n return KARMA_PROMPT.replace(\"{diff}\", truncatedDiff).replace(\"{context}\", context);\n}\n\nexport function buildSummarizePrompt(diff: string, context: string): string {\n const truncatedDiff = truncateDiff(diff);\n return SUMMARIZE_PROMPT.replace(\"{diff}\", truncatedDiff).replace(\"{context}\", context);\n}\n\nexport function validateMessage(message: string): boolean {\n return KARMA_PATTERN.test(message.trim());\n}\n\nexport function cleanMessage(message: string): string {\n // Take only the first line\n let cleaned = message.trim().split(\"\\n\")[0];\n\n // Remove common prefixes that models sometimes add\n const prefixes = [\"Here is \", \"I've \", \"The commit message is:\", \"Commit message:\", \"Here's \"];\n\n for (const prefix of prefixes) {\n if (cleaned.toLowerCase().startsWith(prefix.toLowerCase())) {\n cleaned = cleaned.slice(prefix.length);\n }\n }\n\n // Strip whitespace and trailing period\n cleaned = cleaned.trim().replace(/\\.$/, \"\");\n\n return cleaned;\n}\n\nexport function fixMessage(message: string): string {\n const cleaned = cleanMessage(message);\n\n // If already valid, return as-is\n if (validateMessage(cleaned)) {\n return cleaned;\n }\n\n // Try to infer type from first word\n const words = cleaned.split(/\\s+/);\n if (words.length > 0) {\n const firstWord = words[0].toLowerCase().replace(/:$/, \"\");\n const commitType = ACTION_TO_TYPE[firstWord] ?? \"chore\";\n\n // Build the message\n const subject = words.join(\" \").toLowerCase();\n if (!subject.endsWith(\":\")) {\n return `${commitType}: ${subject}`;\n }\n }\n\n return `chore: ${cleaned.toLowerCase()}`;\n}\n","import { execSync } from \"node:child_process\";\nimport { readFileSync, writeFileSync, unlinkSync, existsSync, chmodSync, mkdirSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport type { HookResult } from \"./types.js\";\n\nconst HOOK_SCRIPT = `#!/bin/sh\n# git-commit-ai prepare-commit-msg hook\n# This hook generates commit messages using AI\n\nCOMMIT_MSG_FILE=\"$1\"\nCOMMIT_SOURCE=\"$2\"\n\n# Only run for regular commits (not merge, squash, etc.)\nif [ -n \"$COMMIT_SOURCE\" ]; then\n exit 0\nfi\n\n# Check if there's already a message (e.g., from -m flag)\nif [ -s \"$COMMIT_MSG_FILE\" ]; then\n # File is not empty, check if it's just the default template\n FIRST_LINE=$(head -n 1 \"$COMMIT_MSG_FILE\")\n if [ -n \"$FIRST_LINE\" ] && ! echo \"$FIRST_LINE\" | grep -q \"^#\"; then\n # There's actual content, don't override\n exit 0\n fi\nfi\n\n# Generate commit message using git-commit-ai\nMESSAGE=$(git-commit-ai --hook-mode 2>/dev/null)\n\nif [ $? -eq 0 ] && [ -n \"$MESSAGE\" ]; then\n # Write the generated message, preserving any existing comments\n COMMENTS=$(grep \"^#\" \"$COMMIT_MSG_FILE\" 2>/dev/null || true)\n echo \"$MESSAGE\" > \"$COMMIT_MSG_FILE\"\n if [ -n \"$COMMENTS\" ]; then\n echo \"\" >> \"$COMMIT_MSG_FILE\"\n echo \"$COMMENTS\" >> \"$COMMIT_MSG_FILE\"\n fi\nfi\n\nexit 0\n`;\n\nconst HOOK_NAME = \"prepare-commit-msg\";\n\nfunction getGitDir(): string | null {\n try {\n const result = execSync(\"git rev-parse --git-dir\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n return result.trim();\n } catch {\n return null;\n }\n}\n\nfunction getHookPath(): string | null {\n const gitDir = getGitDir();\n if (!gitDir) return null;\n return join(gitDir, \"hooks\", HOOK_NAME);\n}\n\nexport function isHookInstalled(): boolean {\n const hookPath = getHookPath();\n if (!hookPath || !existsSync(hookPath)) {\n return false;\n }\n\n const content = readFileSync(hookPath, \"utf-8\");\n return content.includes(\"git-commit-ai\");\n}\n\nexport function installHook(): HookResult {\n const hookPath = getHookPath();\n if (!hookPath) {\n return { success: false, message: \"Not in a git repository\" };\n }\n\n let returnMsg = \"Hook installed successfully\";\n\n // Check if hook already exists\n if (existsSync(hookPath)) {\n const content = readFileSync(hookPath, \"utf-8\");\n if (content.includes(\"git-commit-ai\")) {\n return { success: true, message: \"Hook already installed\" };\n }\n // Backup existing hook\n const backupPath = hookPath + \".backup\";\n writeFileSync(backupPath, content, \"utf-8\");\n returnMsg = `Existing hook backed up to ${HOOK_NAME}.backup`;\n }\n\n // Create hooks directory if needed\n const hooksDir = dirname(hookPath);\n if (!existsSync(hooksDir)) {\n mkdirSync(hooksDir, { recursive: true });\n }\n\n // Write the hook script\n writeFileSync(hookPath, HOOK_SCRIPT, \"utf-8\");\n\n // Make it executable\n chmodSync(hookPath, 0o755);\n\n return { success: true, message: returnMsg };\n}\n\nexport function removeHook(): HookResult {\n const hookPath = getHookPath();\n if (!hookPath) {\n return { success: false, message: \"Not in a git repository\" };\n }\n\n if (!existsSync(hookPath)) {\n return { success: true, message: \"No hook installed\" };\n }\n\n // Check if it's our hook\n const content = readFileSync(hookPath, \"utf-8\");\n if (!content.includes(\"git-commit-ai\")) {\n return { success: false, message: \"Hook exists but was not installed by git-commit-ai\" };\n }\n\n // Remove the hook\n unlinkSync(hookPath);\n\n // Restore backup if exists\n const backupPath = hookPath + \".backup\";\n if (existsSync(backupPath)) {\n const backupContent = readFileSync(backupPath, \"utf-8\");\n writeFileSync(hookPath, backupContent, \"utf-8\");\n unlinkSync(backupPath);\n return { success: true, message: \"Hook removed, previous hook restored\" };\n }\n\n return { success: true, message: \"Hook removed successfully\" };\n}\n","import chalk from \"chalk\";\nimport type { Config } from \"./types.js\";\n\nlet debugEnabled = false;\n\nexport function enableDebug(): void {\n debugEnabled = true;\n}\n\nexport function isDebugEnabled(): boolean {\n return debugEnabled;\n}\n\nfunction getTimestamp(): string {\n const now = new Date();\n return now.toTimeString().slice(0, 8);\n}\n\nexport function debug(message: string, data?: string): void {\n if (!debugEnabled) return;\n\n console.error(chalk.dim(`[${getTimestamp()}]`), chalk.cyan(\"[DEBUG]\"), message);\n\n if (data) {\n const truncated =\n data.length > 500 ? data.slice(0, 500) + `\\n... (${data.length} chars total, truncated)` : data;\n console.error(chalk.dim(truncated));\n }\n}\n\nexport function debugConfig(cfg: Config): void {\n debug(\n \"Config loaded:\",\n `\n Model: ${cfg.model}\n Ollama URL: ${cfg.ollama_url}\n Temperature: ${cfg.temperature}\n Retry temps: [${cfg.retry_temperatures.join(\", \")}]`\n );\n}\n\nexport function debugDiff(diff: string, files: string[]): void {\n const filesList = files.slice(0, 5).join(\", \") + (files.length > 5 ? \" ...\" : \"\");\n debug(`Diff size: ${diff.length} chars, Files: ${files.length}`, `Files: ${filesList}`);\n}\n\nexport function debugPrompt(prompt: string): void {\n const truncated = prompt.length > 500 ? prompt.slice(0, 500) + \"...\" : prompt;\n debug(\"Prompt to LLM:\", truncated);\n}\n\nexport function debugResponse(response: string): void {\n debug(\"Raw LLM response:\", response);\n}\n\nexport function debugValidation(message: string, isValid: boolean, fixed?: string): void {\n const status = isValid ? chalk.green(\"valid\") : chalk.red(\"invalid\");\n debug(`Message validation: ${status}`, message);\n if (fixed && fixed !== message) {\n debug(\"Fixed message:\", fixed);\n }\n}\n","import { createProgram } from \"./cli.js\";\n\nconst program = createProgram();\nprogram.parse();\n"],"mappings":"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","names":["chalk","execSync","readFileSync","writeFileSync","existsSync","mkdirSync","join","dirname","chalk","program"]}
1
+ {"version":3,"sources":["../src/cli.ts","../src/config.ts","../src/backends/ollama.ts","../src/git.ts","../src/prompts.ts","../src/hook.ts","../src/debug.ts","../src/index.ts"],"sourcesContent":["import { Command } from \"commander\";\nimport chalk from \"chalk\";\nimport ora from \"ora\";\nimport { createInterface } from \"node:readline\";\n\nimport { loadConfig, saveConfig, showConfig, getConfigPath } from \"./config.js\";\nimport { OllamaBackend } from \"./backends/ollama.js\";\nimport {\n getStagedDiff,\n getFileDiff,\n addFiles,\n commit,\n push,\n getModifiedFiles,\n GitError,\n} from \"./git.js\";\nimport {\n buildPrompt,\n buildSummarizePrompt,\n cleanMessage,\n validateMessage,\n fixMessage,\n} from \"./prompts.js\";\nimport { installHook, removeHook, isHookInstalled } from \"./hook.js\";\nimport {\n enableDebug,\n debug,\n debugConfig,\n debugDiff,\n debugPrompt,\n debugResponse,\n debugValidation,\n} from \"./debug.js\";\nimport type { Config, DiffResult } from \"./types.js\";\n\nasync function promptUser(question: string, choices: string[]): Promise<string> {\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n const normalized = answer.trim().toLowerCase();\n if (choices.includes(normalized)) {\n resolve(normalized);\n } else {\n resolve(choices[0]); // default to first choice\n }\n });\n });\n}\n\nasync function promptEdit(currentMessage: string): Promise<string> {\n const rl = createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n return new Promise((resolve) => {\n console.log(chalk.dim(\"\\nEnter new commit message (or press Enter to keep current):\"));\n rl.question(`Message [${currentMessage}]: `, (answer) => {\n rl.close();\n resolve(answer.trim() || currentMessage);\n });\n });\n}\n\nasync function generateMessage(\n backend: OllamaBackend,\n diffContent: string,\n context: string,\n temperatures: number[]\n): Promise<string | null> {\n const prompt = buildPrompt(diffContent, context);\n debugPrompt(prompt);\n\n for (const temp of temperatures) {\n debug(`Trying temperature: ${temp}`);\n try {\n const rawMessage = await backend.generate(prompt, temp);\n debugResponse(rawMessage);\n\n const message = cleanMessage(rawMessage);\n const isValid = validateMessage(message);\n debugValidation(message, isValid);\n\n if (isValid) {\n return message;\n }\n\n // Try to fix the message\n const fixed = fixMessage(message);\n if (validateMessage(fixed)) {\n debugValidation(fixed, true, fixed);\n return fixed;\n }\n } catch (e) {\n const error = e as Error;\n debug(`Generation error: ${error.message}`);\n console.log(chalk.yellow(`Warning: Generation failed at temp ${temp}: ${error.message}`));\n }\n }\n\n return null;\n}\n\nfunction showMessage(message: string): void {\n console.log();\n console.log(chalk.green(\"┌─\") + chalk.green(\"─\".repeat(68)) + chalk.green(\"─┐\"));\n console.log(chalk.green(\"│\") + chalk.bold(\" 📝 Generated commit message\") + \" \".repeat(40) + chalk.green(\"│\"));\n console.log(chalk.green(\"├─\") + chalk.green(\"─\".repeat(68)) + chalk.green(\"─┤\"));\n console.log(chalk.green(\"│\") + \" \" + message.padEnd(67) + chalk.green(\"│\"));\n console.log(chalk.green(\"└─\") + chalk.green(\"─\".repeat(68)) + chalk.green(\"─┘\"));\n console.log();\n}\n\nasync function promptAction(message: string): Promise<string> {\n showMessage(message);\n return promptUser(\n \"[C]onfirm [E]dit [R]egenerate [A]bort? \",\n [\"c\", \"e\", \"r\", \"a\"]\n );\n}\n\nasync function runCommitFlow(\n backend: OllamaBackend,\n cfg: Config,\n diffContent: string,\n context: string,\n skipConfirm: boolean\n): Promise<string | null> {\n const temperatures = [cfg.temperature, ...cfg.retry_temperatures];\n const spinner = ora(\"Generating commit message...\").start();\n\n while (true) {\n let message: string | null;\n try {\n message = await generateMessage(backend, diffContent, context, temperatures);\n } finally {\n spinner.stop();\n }\n\n if (message === null) {\n console.log(chalk.red(\"Error: Failed to generate a valid commit message.\"));\n message = \"chore: update files\";\n console.log(chalk.yellow(`Using fallback: ${message}`));\n }\n\n if (skipConfirm) {\n return message;\n }\n\n const action = await promptAction(message);\n\n if (action === \"c\") {\n return message;\n } else if (action === \"e\") {\n return promptEdit(message);\n } else if (action === \"r\") {\n console.log(chalk.dim(\"Regenerating...\"));\n spinner.start(\"Generating commit message...\");\n continue;\n } else if (action === \"a\") {\n return null;\n }\n }\n}\n\nasync function handleSingleCommit(\n backend: OllamaBackend,\n cfg: Config,\n skipConfirm: boolean\n): Promise<void> {\n const diffResult = getStagedDiff();\n\n if (diffResult.isEmpty) {\n console.log(chalk.yellow(\"No changes to commit.\"));\n process.exit(0);\n }\n\n debugDiff(diffResult.diff, diffResult.files);\n const context = `Files changed:\\n${diffResult.files.slice(0, 5).join(\"\\n\")}\\nStats: ${diffResult.stats}`;\n\n const message = await runCommitFlow(backend, cfg, diffResult.diff, context, skipConfirm);\n\n if (message === null) {\n console.log(chalk.yellow(\"Aborted.\"));\n process.exit(0);\n }\n\n try {\n commit(message);\n debug(`Commit successful: ${message}`);\n console.log(chalk.green(\"✓ Committed:\"), message);\n } catch (e) {\n const error = e as GitError;\n debug(`Commit failed: ${error.message}`);\n console.log(chalk.red(`Error: ${error.message}`));\n process.exit(1);\n }\n}\n\nasync function handleIndividualCommits(\n backend: OllamaBackend,\n cfg: Config,\n skipConfirm: boolean\n): Promise<void> {\n const filesToCommit = getModifiedFiles();\n\n if (filesToCommit.length === 0) {\n console.log(chalk.yellow(\"No files to commit.\"));\n process.exit(0);\n }\n\n console.log(chalk.dim(`Found ${filesToCommit.length} files to commit individually.`));\n\n for (const filePath of filesToCommit) {\n const added = addFiles(filePath);\n if (!added) {\n // File is ignored by .gitignore, skip it\n continue;\n }\n\n const diffResult = getFileDiff(filePath);\n\n if (diffResult.isEmpty) {\n continue;\n }\n\n console.log(chalk.bold(`\\nProcessing: ${filePath}`));\n\n const context = `File: ${filePath}\\nStats: ${diffResult.stats}`;\n const message = await runCommitFlow(backend, cfg, diffResult.diff, context, skipConfirm);\n\n if (message === null) {\n console.log(chalk.yellow(`Skipped: ${filePath}`));\n continue;\n }\n\n try {\n commit(message);\n console.log(chalk.green(\"✓ Committed:\"), message);\n } catch (e) {\n const error = e as GitError;\n console.log(chalk.red(`Error committing ${filePath}: ${error.message}`));\n }\n }\n}\n\nexport function createProgram(): Command {\n const program = new Command();\n\n program\n .name(\"git-commit-ai\")\n .description(\"Generate commit messages using local LLMs\")\n .version(\"0.2.0\")\n .option(\"-p, --push\", \"Push after commit\")\n .option(\"-y, --yes\", \"Skip confirmation\")\n .option(\"-i, --individual\", \"Commit files individually\")\n .option(\"-d, --debug\", \"Enable debug output\")\n .option(\"--hook-mode\", \"Called by git hook (outputs message only)\")\n .action(async (options) => {\n if (options.debug) {\n enableDebug();\n debug(\"Debug mode enabled\");\n }\n\n const cfg = loadConfig();\n debugConfig(cfg);\n\n const backend = new OllamaBackend(cfg.model, cfg.ollama_url);\n\n // Check if Ollama is available\n const available = await backend.isAvailable();\n if (!available) {\n if (options.hookMode) {\n process.exit(1);\n }\n console.log(chalk.red(\"Error: Ollama is not running.\"));\n console.log(chalk.dim(\"Start it with: brew services start ollama\"));\n process.exit(1);\n }\n\n // Hook mode: just output the message\n if (options.hookMode) {\n const diffResult = getStagedDiff();\n if (diffResult.isEmpty) {\n process.exit(1);\n }\n\n const context = `Files changed:\\n${diffResult.files.slice(0, 5).join(\"\\n\")}\\nStats: ${diffResult.stats}`;\n const temperatures = [cfg.temperature, ...cfg.retry_temperatures];\n const message = await generateMessage(backend, diffResult.diff, context, temperatures);\n\n if (message) {\n console.log(message);\n process.exit(0);\n }\n process.exit(1);\n }\n\n // Stage all files\n addFiles(\".\");\n\n if (options.individual) {\n await handleIndividualCommits(backend, cfg, options.yes);\n } else {\n await handleSingleCommit(backend, cfg, options.yes);\n }\n\n if (options.push) {\n try {\n push();\n console.log(chalk.green(\"✓ Changes pushed to remote.\"));\n } catch (e) {\n const error = e as GitError;\n console.log(chalk.red(`Error pushing: ${error.message}`));\n process.exit(1);\n }\n }\n });\n\n program\n .command(\"config\")\n .description(\"Show or edit configuration\")\n .option(\"-e, --edit\", \"Create/edit configuration file\")\n .action((options) => {\n const cfg = loadConfig();\n\n if (options.edit) {\n console.log(chalk.dim(\"Creating default config file...\"));\n saveConfig(cfg);\n console.log(chalk.green(`Config saved to: ${getConfigPath()}`));\n console.log(chalk.dim(\"Edit this file to customize settings.\"));\n } else {\n console.log(showConfig(cfg));\n }\n });\n\n program\n .command(\"summarize\")\n .description(\"Summarize staged changes in plain English\")\n .option(\"--diff\", \"Also show the raw diff\")\n .option(\"-d, --debug\", \"Enable debug output\")\n .action(async (options) => {\n if (options.debug) {\n enableDebug();\n }\n\n const cfg = loadConfig();\n const backend = new OllamaBackend(cfg.model, cfg.ollama_url);\n\n const available = await backend.isAvailable();\n if (!available) {\n console.log(chalk.red(\"Error: Ollama is not running.\"));\n console.log(chalk.dim(\"Start it with: brew services start ollama\"));\n process.exit(1);\n }\n\n const diffResult = getStagedDiff();\n\n if (diffResult.isEmpty) {\n console.log(chalk.yellow(\"No staged changes to summarize.\"));\n console.log(chalk.dim(\"Stage changes with: git add <files>\"));\n process.exit(0);\n }\n\n debugDiff(diffResult.diff, diffResult.files);\n\n console.log(chalk.bold(`\\nFiles to summarize: ${diffResult.files.length}`));\n for (const f of diffResult.files.slice(0, 10)) {\n console.log(` • ${f}`);\n }\n if (diffResult.files.length > 10) {\n console.log(` ... and ${diffResult.files.length - 10} more`);\n }\n\n const context = `Files changed: ${diffResult.files.slice(0, 5).join(\", \")}\\nStats: ${diffResult.stats}`;\n const prompt = buildSummarizePrompt(diffResult.diff, context);\n debugPrompt(prompt);\n\n const spinner = ora(\"Generating summary...\").start();\n\n try {\n const summary = await backend.generate(prompt, cfg.temperature);\n spinner.stop();\n debugResponse(summary);\n\n console.log();\n console.log(chalk.blue(\"┌─\") + chalk.blue(\"─\".repeat(68)) + chalk.blue(\"─┐\"));\n console.log(chalk.blue(\"│\") + chalk.bold(\" 📋 Summary\") + \" \".repeat(58) + chalk.blue(\"│\"));\n console.log(chalk.blue(\"├─\") + chalk.blue(\"─\".repeat(68)) + chalk.blue(\"─┤\"));\n for (const line of summary.trim().split(\"\\n\")) {\n console.log(chalk.blue(\"│\") + \" \" + line.padEnd(67) + chalk.blue(\"│\"));\n }\n console.log(chalk.blue(\"└─\") + chalk.blue(\"─\".repeat(68)) + chalk.blue(\"─┘\"));\n\n if (options.diff) {\n console.log();\n console.log(chalk.dim(\"┌─ 📄 Diff ─────────────────────────────────────────────────────────┐\"));\n console.log(chalk.dim(diffResult.diff));\n console.log(chalk.dim(\"└───────────────────────────────────────────────────────────────────┘\"));\n }\n } catch (e) {\n spinner.stop();\n const error = e as Error;\n debug(`Summary generation error: ${error.message}`);\n console.log(chalk.red(`Error generating summary: ${error.message}`));\n process.exit(1);\n }\n });\n\n program\n .command(\"hook\")\n .description(\"Manage git hook for automatic commit message generation\")\n .option(\"--install\", \"Install git hook\")\n .option(\"--remove\", \"Remove git hook\")\n .option(\"--status\", \"Check hook status\")\n .action((options) => {\n const showStatus = !options.install && !options.remove;\n\n if (showStatus || options.status) {\n if (isHookInstalled()) {\n console.log(chalk.green(\"✓ git-commit-ai hook is installed\"));\n } else {\n console.log(chalk.yellow(\"✗ git-commit-ai hook is not installed\"));\n console.log(chalk.dim(\"Install with: git-commit-ai hook --install\"));\n }\n return;\n }\n\n if (options.install) {\n const result = installHook();\n if (result.success) {\n console.log(chalk.green(`✓ ${result.message}`));\n console.log(chalk.dim(\"Now 'git commit' will auto-generate messages!\"));\n } else {\n console.log(chalk.red(`✗ ${result.message}`));\n process.exit(1);\n }\n return;\n }\n\n if (options.remove) {\n const result = removeHook();\n if (result.success) {\n console.log(chalk.green(`✓ ${result.message}`));\n } else {\n console.log(chalk.red(`✗ ${result.message}`));\n process.exit(1);\n }\n }\n });\n\n return program;\n}\n","import { readFileSync, writeFileSync, mkdirSync, existsSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join, dirname } from \"node:path\";\nimport { parse as parseToml } from \"smol-toml\";\nimport type { Config } from \"./types.js\";\n\nconst DEFAULT_CONFIG: Config = {\n model: \"llama3.1:8b\",\n ollama_url: \"http://localhost:11434\",\n temperature: 0.7,\n retry_temperatures: [0.5, 0.3, 0.2],\n};\n\nexport function getConfigPath(): string {\n return join(homedir(), \".config\", \"git-commit-ai\", \"config.toml\");\n}\n\nexport function loadConfig(): Config {\n const configPath = getConfigPath();\n\n if (!existsSync(configPath)) {\n return { ...DEFAULT_CONFIG };\n }\n\n try {\n const content = readFileSync(configPath, \"utf-8\");\n const data = parseToml(content) as Partial<Config>;\n\n return {\n model: data.model ?? DEFAULT_CONFIG.model,\n ollama_url: data.ollama_url ?? DEFAULT_CONFIG.ollama_url,\n temperature: data.temperature ?? DEFAULT_CONFIG.temperature,\n retry_temperatures:\n data.retry_temperatures ?? DEFAULT_CONFIG.retry_temperatures,\n };\n } catch {\n return { ...DEFAULT_CONFIG };\n }\n}\n\nexport function saveConfig(config: Config): void {\n const configPath = getConfigPath();\n const dir = dirname(configPath);\n\n if (!existsSync(dir)) {\n mkdirSync(dir, { recursive: true });\n }\n\n const content = `# git-commit-ai configuration\nmodel = \"${config.model}\"\nollama_url = \"${config.ollama_url}\"\ntemperature = ${config.temperature}\nretry_temperatures = [${config.retry_temperatures.join(\", \")}]\n`;\n\n writeFileSync(configPath, content, \"utf-8\");\n}\n\nexport function showConfig(config: Config): string {\n return `Configuration:\n Model: ${config.model}\n Ollama URL: ${config.ollama_url}\n Temperature: ${config.temperature}\n Retry temperatures: [${config.retry_temperatures.join(\", \")}]\n Config file: ${getConfigPath()}`;\n}\n","import type { Backend } from \"../types.js\";\n\nexport class OllamaBackend implements Backend {\n private model: string;\n private baseUrl: string;\n\n constructor(model = \"llama3.1:8b\", baseUrl = \"http://localhost:11434\") {\n this.model = model;\n this.baseUrl = baseUrl;\n }\n\n async generate(prompt: string, temperature = 0.7): Promise<string> {\n const response = await fetch(`${this.baseUrl}/api/generate`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: this.model,\n prompt,\n temperature,\n stream: false,\n }),\n });\n\n if (!response.ok) {\n throw new Error(`Ollama API error: ${response.status}`);\n }\n\n const data = (await response.json()) as { response?: string };\n return data.response ?? \"\";\n }\n\n async isAvailable(): Promise<boolean> {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 5000);\n\n const response = await fetch(`${this.baseUrl}/api/tags`, {\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n return response.status === 200;\n } catch {\n return false;\n }\n }\n\n async hasModel(model?: string): Promise<boolean> {\n const checkModel = model ?? this.model;\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 5000);\n\n const response = await fetch(`${this.baseUrl}/api/tags`, {\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (response.status !== 200) {\n return false;\n }\n\n const data = (await response.json()) as {\n models?: Array<{ name?: string }>;\n };\n const models = data.models?.map((m) => m.name ?? \"\") ?? [];\n return models.some((m) => m.includes(checkModel));\n } catch {\n return false;\n }\n }\n}\n","import { execSync } from \"node:child_process\";\nimport type { DiffResult } from \"./types.js\";\n\nexport class GitError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"GitError\";\n }\n}\n\nfunction runGit(...args: string[]): string {\n try {\n const result = execSync([\"git\", ...args].join(\" \"), {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n return result.trim();\n } catch (error) {\n const err = error as { stderr?: string; message: string };\n const message = err.stderr?.trim() || err.message;\n throw new GitError(`Git command failed: ${message}`);\n }\n}\n\nfunction runGitSafe(...args: string[]): string {\n try {\n return runGit(...args);\n } catch {\n return \"\";\n }\n}\n\nexport function getStagedDiff(): DiffResult {\n const diff = runGitSafe(\"diff\", \"--cached\");\n const stats = runGitSafe(\"diff\", \"--cached\", \"--stat\");\n const filesOutput = runGitSafe(\"diff\", \"--cached\", \"--name-only\");\n const files = filesOutput.split(\"\\n\").filter((f) => f);\n\n return {\n diff,\n stats,\n files,\n isEmpty: !diff.trim(),\n };\n}\n\nexport function getFileDiff(filePath: string): DiffResult {\n const diff = runGitSafe(\"diff\", \"--cached\", \"--\", filePath);\n const stats = runGitSafe(\"diff\", \"--cached\", \"--stat\", \"--\", filePath);\n const files = diff ? [filePath] : [];\n\n return {\n diff,\n stats,\n files,\n isEmpty: !diff.trim(),\n };\n}\n\nexport function addFiles(...paths: string[]): boolean {\n if (paths.length === 0) {\n paths = [\".\"];\n }\n try {\n runGit(\"add\", ...paths);\n return true;\n } catch (error) {\n const err = error as GitError;\n // Ignore \"ignored file\" errors\n if (err.message.includes(\"ignored by one of your .gitignore\")) {\n return false;\n }\n throw error;\n }\n}\n\nexport function commit(message: string): string {\n runGit(\"commit\", \"-m\", `\"${message.replace(/\"/g, '\\\\\"')}\"`);\n return runGit(\"rev-parse\", \"HEAD\");\n}\n\nexport function push(): void {\n const branch = getCurrentBranch();\n runGit(\"push\", \"origin\", branch);\n}\n\nexport function getCurrentBranch(): string {\n return runGit(\"rev-parse\", \"--abbrev-ref\", \"HEAD\");\n}\n\nexport function getModifiedFiles(): string[] {\n const files = new Set<string>();\n\n // Modified and staged files\n const staged = runGitSafe(\"diff\", \"--cached\", \"--name-only\");\n if (staged) {\n staged.split(\"\\n\").forEach((f) => files.add(f));\n }\n\n // Modified but not staged\n const modified = runGitSafe(\"diff\", \"--name-only\");\n if (modified) {\n modified.split(\"\\n\").forEach((f) => files.add(f));\n }\n\n // Untracked files\n const untracked = runGitSafe(\"ls-files\", \"--others\", \"--exclude-standard\");\n if (untracked) {\n untracked.split(\"\\n\").forEach((f) => files.add(f));\n }\n\n return Array.from(files).filter((f) => f);\n}\n\nexport function hasStagedChanges(): boolean {\n const diff = runGitSafe(\"diff\", \"--cached\", \"--name-only\");\n return Boolean(diff.trim());\n}\n","const SUMMARIZE_PROMPT = `Summarize the following code changes in plain English.\n\nProvide a brief, clear summary that explains:\n1. What files were changed\n2. What was added, removed, or modified\n3. The likely purpose of these changes\n\nKeep it concise (3-5 bullet points). Focus on the \"what\" and \"why\".\n\n{context}\n\nDIFF:\n\\`\\`\\`\n{diff}\n\\`\\`\\`\n\nProvide only the summary, no additional commentary.`;\n\nconst KARMA_PROMPT = `Analyze the git diff below and create a commit message following Karma convention.\n\nFORMAT: <type>(<scope>): <subject>\n\nTYPES (use the most appropriate):\n- feat: new feature or capability\n- fix: bug fix\n- docs: documentation changes (README, comments, docstrings)\n- style: formatting only (whitespace, semicolons)\n- refactor: code change that neither fixes bug nor adds feature\n- test: adding or modifying tests\n- build: build system, dependencies, package config\n- chore: maintenance tasks\n\nRULES:\n- Scope is optional - use the main file/module name if relevant\n- Subject must describe WHAT changed in the diff, not a generic message\n- Use imperative mood: \"add\" not \"added\", \"fix\" not \"fixed\"\n- Lowercase, no period at end, max 72 chars\n\nEXAMPLES based on diff content:\n- Adding README.md → docs: add README with usage instructions\n- Fixing null check in auth.py → fix(auth): handle null user in login\n- New API endpoint → feat(api): add user profile endpoint\n- Updating dependencies → build: update httpx to 0.25.0\n\nIMPORTANT: Base your message ONLY on the actual changes shown in the diff below.\nDo NOT use the examples above if they don't match the diff content.\n\n{context}\n\nDIFF TO ANALYZE:\n\\`\\`\\`\n{diff}\n\\`\\`\\`\n\nReply with ONLY the commit message, nothing else. No quotes, no explanation.`;\n\nconst KARMA_PATTERN =\n /^(feat|fix|docs|style|refactor|test|chore|build|ci|perf|revert)(\\([^)]+\\))?:\\s*.+/;\n\nconst ACTION_TO_TYPE: Record<string, string> = {\n add: \"feat\",\n added: \"feat\",\n adding: \"feat\",\n create: \"feat\",\n implement: \"feat\",\n fix: \"fix\",\n fixed: \"fix\",\n fixing: \"fix\",\n repair: \"fix\",\n update: \"refactor\",\n updated: \"refactor\",\n updating: \"refactor\",\n improve: \"refactor\",\n remove: \"refactor\",\n removed: \"refactor\",\n removing: \"refactor\",\n delete: \"refactor\",\n document: \"docs\",\n documented: \"docs\",\n test: \"test\",\n tested: \"test\",\n testing: \"test\",\n};\n\nconst MAX_DIFF_CHARS = 8000;\n\nexport function truncateDiff(diff: string, maxChars = MAX_DIFF_CHARS): string {\n if (diff.length <= maxChars) {\n return diff;\n }\n\n let truncated = diff.slice(0, maxChars);\n const lastNewline = truncated.lastIndexOf(\"\\n\");\n if (lastNewline > maxChars * 0.8) {\n truncated = truncated.slice(0, lastNewline);\n }\n\n return truncated + \"\\n\\n[... diff truncated for brevity ...]\";\n}\n\nexport function buildPrompt(diff: string, context: string): string {\n const truncatedDiff = truncateDiff(diff);\n return KARMA_PROMPT.replace(\"{diff}\", truncatedDiff).replace(\"{context}\", context);\n}\n\nexport function buildSummarizePrompt(diff: string, context: string): string {\n const truncatedDiff = truncateDiff(diff);\n return SUMMARIZE_PROMPT.replace(\"{diff}\", truncatedDiff).replace(\"{context}\", context);\n}\n\nexport function validateMessage(message: string): boolean {\n return KARMA_PATTERN.test(message.trim());\n}\n\nexport function cleanMessage(message: string): string {\n // Take only the first line\n let cleaned = message.trim().split(\"\\n\")[0];\n\n // Remove common prefixes that models sometimes add\n const prefixes = [\"Here is \", \"I've \", \"The commit message is:\", \"Commit message:\", \"Here's \"];\n\n for (const prefix of prefixes) {\n if (cleaned.toLowerCase().startsWith(prefix.toLowerCase())) {\n cleaned = cleaned.slice(prefix.length);\n }\n }\n\n // Strip whitespace and trailing period\n cleaned = cleaned.trim().replace(/\\.$/, \"\");\n\n return cleaned;\n}\n\nexport function fixMessage(message: string): string {\n const cleaned = cleanMessage(message);\n\n // If already valid, return as-is\n if (validateMessage(cleaned)) {\n return cleaned;\n }\n\n // Try to infer type from first word\n const words = cleaned.split(/\\s+/);\n if (words.length > 0) {\n const firstWord = words[0].toLowerCase().replace(/:$/, \"\");\n const commitType = ACTION_TO_TYPE[firstWord] ?? \"chore\";\n\n // Build the message\n const subject = words.join(\" \").toLowerCase();\n if (!subject.endsWith(\":\")) {\n return `${commitType}: ${subject}`;\n }\n }\n\n return `chore: ${cleaned.toLowerCase()}`;\n}\n","import { execSync } from \"node:child_process\";\nimport { readFileSync, writeFileSync, unlinkSync, existsSync, chmodSync, mkdirSync } from \"node:fs\";\nimport { join, dirname } from \"node:path\";\nimport type { HookResult } from \"./types.js\";\n\nconst HOOK_SCRIPT = `#!/bin/sh\n# git-commit-ai prepare-commit-msg hook\n# This hook generates commit messages using AI\n\nCOMMIT_MSG_FILE=\"$1\"\nCOMMIT_SOURCE=\"$2\"\n\n# Only run for regular commits (not merge, squash, etc.)\nif [ -n \"$COMMIT_SOURCE\" ]; then\n exit 0\nfi\n\n# Check if there's already a message (e.g., from -m flag)\nif [ -s \"$COMMIT_MSG_FILE\" ]; then\n # File is not empty, check if it's just the default template\n FIRST_LINE=$(head -n 1 \"$COMMIT_MSG_FILE\")\n if [ -n \"$FIRST_LINE\" ] && ! echo \"$FIRST_LINE\" | grep -q \"^#\"; then\n # There's actual content, don't override\n exit 0\n fi\nfi\n\n# Generate commit message using git-commit-ai\nMESSAGE=$(git-commit-ai --hook-mode 2>/dev/null)\n\nif [ $? -eq 0 ] && [ -n \"$MESSAGE\" ]; then\n # Write the generated message, preserving any existing comments\n COMMENTS=$(grep \"^#\" \"$COMMIT_MSG_FILE\" 2>/dev/null || true)\n echo \"$MESSAGE\" > \"$COMMIT_MSG_FILE\"\n if [ -n \"$COMMENTS\" ]; then\n echo \"\" >> \"$COMMIT_MSG_FILE\"\n echo \"$COMMENTS\" >> \"$COMMIT_MSG_FILE\"\n fi\nfi\n\nexit 0\n`;\n\nconst HOOK_NAME = \"prepare-commit-msg\";\n\nfunction getGitDir(): string | null {\n try {\n const result = execSync(\"git rev-parse --git-dir\", {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n });\n return result.trim();\n } catch {\n return null;\n }\n}\n\nfunction getHookPath(): string | null {\n const gitDir = getGitDir();\n if (!gitDir) return null;\n return join(gitDir, \"hooks\", HOOK_NAME);\n}\n\nexport function isHookInstalled(): boolean {\n const hookPath = getHookPath();\n if (!hookPath || !existsSync(hookPath)) {\n return false;\n }\n\n const content = readFileSync(hookPath, \"utf-8\");\n return content.includes(\"git-commit-ai\");\n}\n\nexport function installHook(): HookResult {\n const hookPath = getHookPath();\n if (!hookPath) {\n return { success: false, message: \"Not in a git repository\" };\n }\n\n let returnMsg = \"Hook installed successfully\";\n\n // Check if hook already exists\n if (existsSync(hookPath)) {\n const content = readFileSync(hookPath, \"utf-8\");\n if (content.includes(\"git-commit-ai\")) {\n return { success: true, message: \"Hook already installed\" };\n }\n // Backup existing hook\n const backupPath = hookPath + \".backup\";\n writeFileSync(backupPath, content, \"utf-8\");\n returnMsg = `Existing hook backed up to ${HOOK_NAME}.backup`;\n }\n\n // Create hooks directory if needed\n const hooksDir = dirname(hookPath);\n if (!existsSync(hooksDir)) {\n mkdirSync(hooksDir, { recursive: true });\n }\n\n // Write the hook script\n writeFileSync(hookPath, HOOK_SCRIPT, \"utf-8\");\n\n // Make it executable\n chmodSync(hookPath, 0o755);\n\n return { success: true, message: returnMsg };\n}\n\nexport function removeHook(): HookResult {\n const hookPath = getHookPath();\n if (!hookPath) {\n return { success: false, message: \"Not in a git repository\" };\n }\n\n if (!existsSync(hookPath)) {\n return { success: true, message: \"No hook installed\" };\n }\n\n // Check if it's our hook\n const content = readFileSync(hookPath, \"utf-8\");\n if (!content.includes(\"git-commit-ai\")) {\n return { success: false, message: \"Hook exists but was not installed by git-commit-ai\" };\n }\n\n // Remove the hook\n unlinkSync(hookPath);\n\n // Restore backup if exists\n const backupPath = hookPath + \".backup\";\n if (existsSync(backupPath)) {\n const backupContent = readFileSync(backupPath, \"utf-8\");\n writeFileSync(hookPath, backupContent, \"utf-8\");\n unlinkSync(backupPath);\n return { success: true, message: \"Hook removed, previous hook restored\" };\n }\n\n return { success: true, message: \"Hook removed successfully\" };\n}\n","import chalk from \"chalk\";\nimport type { Config } from \"./types.js\";\n\nlet debugEnabled = false;\n\nexport function enableDebug(): void {\n debugEnabled = true;\n}\n\nexport function isDebugEnabled(): boolean {\n return debugEnabled;\n}\n\nfunction getTimestamp(): string {\n const now = new Date();\n return now.toTimeString().slice(0, 8);\n}\n\nexport function debug(message: string, data?: string): void {\n if (!debugEnabled) return;\n\n console.error(chalk.dim(`[${getTimestamp()}]`), chalk.cyan(\"[DEBUG]\"), message);\n\n if (data) {\n const truncated =\n data.length > 500 ? data.slice(0, 500) + `\\n... (${data.length} chars total, truncated)` : data;\n console.error(chalk.dim(truncated));\n }\n}\n\nexport function debugConfig(cfg: Config): void {\n debug(\n \"Config loaded:\",\n `\n Model: ${cfg.model}\n Ollama URL: ${cfg.ollama_url}\n Temperature: ${cfg.temperature}\n Retry temps: [${cfg.retry_temperatures.join(\", \")}]`\n );\n}\n\nexport function debugDiff(diff: string, files: string[]): void {\n const filesList = files.slice(0, 5).join(\", \") + (files.length > 5 ? \" ...\" : \"\");\n debug(`Diff size: ${diff.length} chars, Files: ${files.length}`, `Files: ${filesList}`);\n}\n\nexport function debugPrompt(prompt: string): void {\n const truncated = prompt.length > 500 ? prompt.slice(0, 500) + \"...\" : prompt;\n debug(\"Prompt to LLM:\", truncated);\n}\n\nexport function debugResponse(response: string): void {\n debug(\"Raw LLM response:\", response);\n}\n\nexport function debugValidation(message: string, isValid: boolean, fixed?: string): void {\n const status = isValid ? chalk.green(\"valid\") : chalk.red(\"invalid\");\n debug(`Message validation: ${status}`, message);\n if (fixed && fixed !== message) {\n debug(\"Fixed message:\", fixed);\n }\n}\n","import { createProgram } from \"./cli.js\";\n\nconst program = createProgram();\nprogram.parse();\n"],"mappings":"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","names":["chalk","execSync","readFileSync","writeFileSync","existsSync","mkdirSync","join","dirname","chalk","program"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vavasilva/git-commit-ai",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "Generate commit messages using local LLMs (Ollama)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",