import { loadConfig } from "../config"; import { isGitRepo, getRecentCommits } from "../git"; import { CHANGELOG_SYSTEM_PROMPT, buildChangelogPrompt } from "../prompt"; import { callAI } from "../ai"; import { BOLD, RED, DIM, RESET, CYAN } from "../terminal"; import { isStdinTTY } from "../tty"; import type { StreamCallbacks } from "../types"; import type { ParsedArgs } from "../cli"; export async function handleChangelog(args: ParsedArgs): Promise { const config = await loadConfig(); if (!config.apiKey) { console.error(`\n ${RED()}Error: API key not set. Run ${BOLD()}gai config${RESET()}${RED()} to configure.${RESET()}\n`); return 1; } if (!(await isGitRepo())) { console.error(`\n ${RED()}Error: Not a git repository.${RESET()}\n`); return 1; } const from = args.flags["from"] as string | undefined; const to = args.flags["to"] as string | undefined; const countFlag = args.flags["count"] as number | undefined; const verbose = args.flags["verbose"] as boolean; // Collect commits let commits: string[]; if (from) { // Range-based: get commits between from..to const range = to ? `${from}..${to}` : `${from}..HEAD`; try { const result = await Bun.$`git log --oneline ${range}`.quiet().text(); commits = result.trim().split("\n").filter(Boolean); } catch { console.error(`\n ${RED()}Error: Invalid range: ${range}${RESET()}\n`); return 1; } } else { // Count-based const count = typeof countFlag === "number" ? countFlag : 20; commits = await getRecentCommits(count); } if (commits.length === 0) { console.log(` ${DIM()}No commits found for the specified range.${RESET()}`); return 0; } if (verbose) { console.log(` ${DIM()}Processing ${commits.length} commits${RESET()}`); console.log(` ${DIM()}Model: ${config.model} | API: ${config.apiBase}${RESET()}`); } const userPrompt = buildChangelogPrompt(commits, from, to); const tty = isStdinTTY(); if (tty) { console.log(`\n ${BOLD()}${CYAN()}Generating changelog from ${commits.length} commits...${RESET()}\n`); } try { const callbacks: StreamCallbacks = tty ? { onToken: (token) => process.stdout.write(token), } : undefined; const result = await callAI(config, CHANGELOG_SYSTEM_PROMPT, userPrompt, callbacks); if (callbacks) { process.stdout.write("\n"); } else { process.stdout.write(result + "\n"); } } catch (err) { console.error(`\n ${RED()}AI request failed: ${err instanceof Error ? err.message : err}${RESET()}\n`); return 1; } return 0; }