@kyubiware/commit-mint 0.4.2 → 0.5.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/cli.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.mjs","names":["mapGroqError","mapGroqError","pkg"],"sources":["../package.json","../src/utils/debug.ts","../src/services/config.ts","../src/services/hooks.ts","../src/services/hook-progress.ts","../src/services/git.ts","../src/services/lint-staged.ts","../src/services/clipboard.ts","../src/ui/menu.ts","../src/services/ai.ts","../src/services/review-ai.ts","../src/commands/review.ts","../src/ui/review-message.ts","../src/utils/cache.ts","../src/services/grouping.ts","../src/ui/grouping.ts","../src/commands/auto-group.ts","../src/commands/commit.ts","../src/commands/config.ts","../src/cli.ts"],"sourcesContent":["","import { dim } from \"kolorist\";\n\nlet enabled = false;\n\nexport function setDebug(value: boolean): void {\n\tenabled = value;\n}\n\nexport function isDebug(): boolean {\n\treturn enabled;\n}\n\nexport function debug(...args: unknown[]): void {\n\tif (!enabled) return;\n\tconst timestamp = new Date().toISOString().slice(11, 23);\n\tconsole.error(dim(`[debug ${timestamp}]`), ...args);\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport { join } from \"node:path\";\nimport ini from \"ini\";\nimport { debug } from \"../utils/debug.js\";\n\nconst CONFIG_PATH = join(os.homedir(), \".commit-mint\");\n\ninterface Config {\n\tGROQ_API_KEY?: string;\n\tmodel?: string;\n\tlocale?: string;\n\t\"max-length\"?: string;\n\ttype?: string;\n\tproxy?: string;\n\ttimeout?: string;\n}\n\nconst defaults: Config = {\n\tmodel: \"openai/gpt-oss-20b\",\n\tlocale: \"en\",\n\t\"max-length\": \"100\",\n\ttype: \"\",\n\ttimeout: \"10000\",\n};\n\nexport async function readConfig(): Promise<Config> {\n\tdebug(\"readConfig: loading from %s\", CONFIG_PATH);\n\ttry {\n\t\tconst raw = await readFile(CONFIG_PATH, \"utf8\");\n\t\tconst parsed = ini.parse(raw);\n\t\tconst merged = { ...defaults, ...parsed };\n\t\tdebug(\"readConfig: loaded keys: %s\", Object.keys(merged).join(\", \"));\n\t\treturn merged;\n\t} catch {\n\t\tdebug(\"readConfig: no config file, using defaults\");\n\t\treturn { ...defaults };\n\t}\n}\n\nexport async function writeConfig(updates: Record<string, string>) {\n\tconst existing = await readConfig();\n\tObject.assign(existing, updates);\n\tawait writeFile(CONFIG_PATH, ini.stringify(existing), \"utf8\");\n}\n\nexport async function getConfigValue(key: string): Promise<string | undefined> {\n\tconst config = await readConfig();\n\treturn config[key as keyof Config];\n}\n\nexport async function setConfigValue(key: string, value: string) {\n\tawait writeConfig({ [key]: value });\n}\n\nexport async function getApiKey(): Promise<string> {\n\tconst envKey = process.env.GROQ_API_KEY;\n\tif (envKey) {\n\t\tdebug(\"getApiKey: found in env\");\n\t\treturn envKey;\n\t}\n\n\tconst config = await readConfig();\n\tif (config.GROQ_API_KEY) {\n\t\tdebug(\"getApiKey: found in config\");\n\t\treturn config.GROQ_API_KEY;\n\t}\n\n\tdebug(\"getApiKey: not found\");\n\tthrow new Error(\"Please set your Groq API key via `cmint config set GROQ_API_KEY=<your token>`\");\n}\n","import { debug } from \"../utils/debug.js\";\n\nexport interface HookError {\n\ttool: string;\n\tmessage: string;\n\traw: string;\n}\n\n/**\n * Parse git hook error output into structured, human-readable errors.\n * Handles output from lint-staged, biome, eslint, tsc, vitest, jest.\n */\nexport function parseHookErrors(stderr: string): HookError[] {\n\tif (!stderr) return [];\n\n\tdebug(\"parseHookErrors: stderr length=%d\", stderr.length);\n\tconst errors: HookError[] = [];\n\n\t// Detect lint-staged task failures\n\tif (stderr.includes(\"lint-staged\") || stderr.includes(\"[FAILED]\")) {\n\t\terrors.push(...parseLintStagedErrors(stderr));\n\t}\n\n\t// Detect biome errors\n\tif (stderr.includes(\"biome\") || stderr.includes(\"Biome\")) {\n\t\terrors.push(...parseBiomeErrors(stderr));\n\t}\n\n\t// Detect TypeScript errors\n\tif (stderr.includes(\"error TS\") || stderr.includes(\"tsc\")) {\n\t\terrors.push(...parseTscErrors(stderr));\n\t}\n\n\t// Detect vitest/jest test failures\n\tif (\n\t\tstderr.includes(\"vitest\") ||\n\t\tstderr.includes(\"jest\") ||\n\t\tstderr.includes(\"FAIL\") ||\n\t\tstderr.includes(\"test failed\")\n\t) {\n\t\terrors.push(...parseTestErrors(stderr));\n\t}\n\n\t// Detect ESLint errors\n\tif (stderr.includes(\"eslint\") || stderr.includes(\"ESLint\")) {\n\t\terrors.push(...parseEslintErrors(stderr));\n\t}\n\n\t// Fallback: if nothing parsed, return the raw output\n\tif (errors.length === 0) {\n\t\tdebug(\"parseHookErrors: no patterns matched, using raw fallback\");\n\t\terrors.push({\n\t\t\ttool: \"git hooks\",\n\t\t\tmessage: stderr.trim(),\n\t\t\traw: stderr,\n\t\t});\n\t}\n\n\tdebug(\"parseHookErrors: found %d errors\", errors.length);\n\treturn errors;\n}\n\nfunction parseLintStagedErrors(output: string): HookError[] {\n\tconst errors: HookError[] = [];\n\tfor (const match of output.matchAll(/\\[FAILED\\]\\s+(.+?)\\s+\\[FAILED\\]/g)) {\n\t\tconst task = match[1].trim();\n\t\terrors.push({\n\t\t\ttool: \"lint-staged\",\n\t\t\tmessage: `Task failed: ${task}`,\n\t\t\traw: match[0],\n\t\t});\n\t}\n\n\treturn errors;\n}\n\nfunction parseBiomeErrors(output: string): HookError[] {\n\tconst errors: HookError[] = [];\n\tfor (const match of output.matchAll(/^(.+?):(\\d+):(\\d+)\\s+(.+)$/gm)) {\n\t\terrors.push({\n\t\t\ttool: \"biome\",\n\t\t\tmessage: `${match[1]}:${match[2]}:${match[3]} — ${match[4]}`,\n\t\t\traw: match[0],\n\t\t});\n\t}\n\n\tif (errors.length === 0 && output.includes(\"biome\")) {\n\t\terrors.push({\n\t\t\ttool: \"biome\",\n\t\t\tmessage: \"Biome check failed. See raw output for details.\",\n\t\t\traw: output,\n\t\t});\n\t}\n\n\treturn errors;\n}\n\nfunction parseTscErrors(output: string): HookError[] {\n\tconst errors: HookError[] = [];\n\tfor (const match of output.matchAll(/^(.+?)\\((\\d+),(\\d+)\\):\\s+error\\s+(TS\\d+):\\s+(.+)$/gm)) {\n\t\terrors.push({\n\t\t\ttool: \"tsc\",\n\t\t\tmessage: `${match[1]}:${match[2]}:${match[3]} — ${match[4]}: ${match[5]}`,\n\t\t\traw: match[0],\n\t\t});\n\t}\n\n\treturn errors;\n}\n\nfunction parseTestErrors(output: string): HookError[] {\n\tconst errors: HookError[] = [];\n\tconst failPattern = /FAIL\\s+(.+\\.(test|spec)\\..+)/;\n\tconst match = failPattern.exec(output);\n\n\tif (match) {\n\t\terrors.push({\n\t\t\ttool: output.includes(\"vitest\") ? \"vitest\" : \"jest\",\n\t\t\tmessage: `Test file failed: ${match[1]}`,\n\t\t\traw: output,\n\t\t});\n\t}\n\n\tif (errors.length === 0 && (output.includes(\"vitest\") || output.includes(\"jest\"))) {\n\t\terrors.push({\n\t\t\ttool: output.includes(\"vitest\") ? \"vitest\" : \"jest\",\n\t\t\tmessage: \"Tests failed. See raw output for details.\",\n\t\t\traw: output,\n\t\t});\n\t}\n\n\treturn errors;\n}\n\nfunction parseEslintErrors(output: string): HookError[] {\n\tconst errors: HookError[] = [];\n\tconst lines = output.split(\"\\n\");\n\tlet currentFile = \"\";\n\n\tfor (const line of lines) {\n\t\t// ESLint file path line: not indented, contains a path separator\n\t\tif (!/^\\s/.test(line) && line.includes(\"/\")) {\n\t\t\tcurrentFile = line.trim();\n\t\t\tcontinue;\n\t\t}\n\n\t\t// ESLint error/warning detail: <line>:<col> <severity> <message> <rule>\n\t\t// Message and rule are separated by 2+ spaces\n\t\tconst match = line.match(/^\\s*(\\d+):(\\d+)\\s+(error|warning)\\s+(.+)\\s{2,}(\\S+)\\s*$/);\n\t\tif (match) {\n\t\t\tconst [, lineNum, col, severity, message, rule] = match;\n\t\t\tconst file = currentFile || \"unknown\";\n\t\t\terrors.push({\n\t\t\t\ttool: \"eslint\",\n\t\t\t\tmessage: `${file}:${lineNum}:${col} ${severity}: ${message} (${rule})`,\n\t\t\t\traw: line.trim(),\n\t\t\t});\n\t\t}\n\t}\n\n\treturn errors;\n}\n\nexport function formatErrorReport(errors: HookError[]): string {\n\tif (errors.length === 0) return \"\";\n\n\tconst sections = errors.map((e) => `[${e.tool}]\\n${e.message}`);\n\treturn sections.join(\"\\n\\n\");\n}\n\n// ── Tool check parsing (success case) ──────────────────────────────\n\nexport interface ToolCheck {\n\ttool: string;\n\tok: boolean;\n}\n\n/**\n * Parse lint-staged/hook stderr output to discover which tools ran\n * and whether they succeeded. Used for clean post-commit summary.\n */\nexport function parseToolChecks(stderr: string): ToolCheck[] {\n\tif (!stderr) return [];\n\n\tconst checks: ToolCheck[] = [];\n\t// Match [COMPLETED] and [FAILED] status lines from lint-staged\n\tfor (const match of stderr.matchAll(/\\[(COMPLETED|FAILED)\\]\\s+(.+)/g)) {\n\t\tconst status = match[1];\n\t\tconst command = match[2].trim();\n\n\t\tif (isLintStagedMeta(command)) continue;\n\n\t\tconst tool = extractToolName(command);\n\t\tif (!tool) continue;\n\n\t\tchecks.push({ tool, ok: status === \"COMPLETED\" });\n\t}\n\n\t// Deduplicate by tool name (keep last occurrence — final status)\n\tconst seen = new Map<string, ToolCheck>();\n\tfor (const c of checks) {\n\t\tseen.set(c.tool, c);\n\t}\n\n\treturn [...seen.values()];\n}\n\n/** Heuristic: skip lint-staged internal metadata lines */\nexport function isLintStagedMeta(command: string): boolean {\n\t// Glob patterns in task labels\n\tif (/[*{}[\\]]/.test(command)) return true;\n\t// Task count labels: \"src/ — 3 files\", \"src/ — no files\"\n\t// The dash can be em-dash (—), en-dash (–), or plain hyphen (-)\n\tif (/\\s[-–—]\\s(\\d+\\s)?files?$/.test(command)) return true;\n\tif (/\\s[-–—]\\sno\\s files$/.test(command)) return true;\n\t// Internal lint-staged lifecycle messages\n\tif (\n\t\t/^(Running tasks|Applying modifications|Cleaning up|Backing up|Backed up|Updating Git)/.test(\n\t\t\tcommand,\n\t\t)\n\t)\n\t\treturn true;\n\t// Ends with ellipsis (e.g. \"Backing up original state...\")\n\tif (/\\.{3}$/.test(command)) return true;\n\treturn false;\n}\n\n/** Extract a display-friendly tool name from a lint-staged command */\nexport function extractToolName(command: string): string | null {\n\t// Step 1: Unwrap sh -c '...' wrapper\n\tconst unwrapped = unwrapShC(command);\n\tif (unwrapped !== null) command = unwrapped;\n\n\t// Step 2: Find the meaningful command in a && chain (skip cd segments)\n\tcommand = findMeaningfulCommand(command);\n\n\treturn parseToolFromTokens(command.split(/\\s+/));\n}\n\n/** Map common script names to their underlying tool */\nconst SCRIPT_MAP: Record<string, string> = {\n\ttypecheck: \"tsc\",\n\tlint: \"eslint\",\n\tformat: \"prettier\",\n};\n\n/** Package managers that use [run|exec] <script|tool> pattern */\nconst PKG_MANAGERS = [\"npm\", \"yarn\", \"pnpm\", \"bun\"];\n\n/** Parse tool name from a tokenized command */\nfunction parseToolFromTokens(tokens: string[]): string | null {\n\tconst first = tokens[0];\n\n\t// Safety: don't return the shell itself as a tool name\n\tif (first === \"sh\" || first === \"bash\" || first === \"zsh\") return null;\n\n\t// npm/yarn/pnpm/bun [run|exec] <script/tool>\n\tif (PKG_MANAGERS.includes(first)) {\n\t\treturn parsePackageManagerTool(tokens);\n\t}\n\n\t// npx <tool>\n\tif (first === \"npx\") return tokens[1] ?? null;\n\n\t// uv run <tool> / uv tool run <tool>\n\tif (first === \"uv\") return parseUvTool(tokens);\n\n\t// Direct tool invocation (biome, eslint, tsc, vitest, jest, prettier)\n\treturn first;\n}\n\n/** Extract tool name from npm/yarn/pnpm/bun commands */\nfunction parsePackageManagerTool(tokens: string[]): string | null {\n\tconst sub = tokens[1];\n\t// pnpm exec <tool>\n\tif (sub === \"exec\") return tokens[2] ?? null;\n\t// npm/yarn/pnpm [run] <script>\n\tconst scriptIdx = sub === \"run\" ? 2 : 1;\n\tconst script = tokens[scriptIdx];\n\tif (!script) return null;\n\treturn SCRIPT_MAP[script] ?? script;\n}\n\n/** Extract tool name from uv commands */\nfunction parseUvTool(tokens: string[]): string | null {\n\tif (tokens[1] === \"run\") return tokens[2] ?? null;\n\tif (tokens[1] === \"tool\" && tokens[2] === \"run\") return tokens[3] ?? null;\n\treturn null;\n}\n\n/** Unwrap sh -c 'command' or sh -c \"command\" wrappers */\nfunction unwrapShC(command: string): string | null {\n\t// sh/bash -c 'body' or sh/bash -c \"body\"\n\tconst quoted = command.match(/^(?:sh|bash|zsh)\\s+-c\\s+(['\"])([\\s\\S]*)\\1$/);\n\tif (quoted) return quoted[2];\n\t// sh/bash -c body (no quotes, single word — rare)\n\tconst bare = command.match(/^(?:sh|bash|zsh)\\s+-c\\s+(\\S+)$/);\n\tif (bare) return bare[1];\n\treturn null;\n}\n\n/** Find the meaningful command in a && chain, skipping cd segments */\nfunction findMeaningfulCommand(command: string): string {\n\tconst segments = command\n\t\t.split(/\\s*&&\\s*/)\n\t\t.map((s) => s.trim())\n\t\t.filter(Boolean);\n\tfor (const seg of segments) {\n\t\tif (/^cd\\s/.test(seg)) continue;\n\t\treturn seg;\n\t}\n\treturn segments[segments.length - 1] || command;\n}\n","import type { SpinnerResult } from \"@clack/prompts\";\nimport { extractToolName, isLintStagedMeta } from \"./hooks.js\";\n\nexport interface HookStep {\n\tstatus: \"started\" | \"completed\" | \"failed\";\n\tcommand: string;\n\ttool: string;\n}\n\nexport type ProgressHandler = (step: HookStep) => void;\n\nconst ansiRe = new RegExp(`${String.fromCharCode(0x1b)}\\\\[[0-9;]*m`, \"g\");\n\nexport function createStderrParser(): (chunk: string) => HookStep[] {\n\tlet buffer = \"\";\n\treturn (chunk: string): HookStep[] => {\n\t\tbuffer += chunk;\n\t\tconst steps: HookStep[] = [];\n\t\tconst lines = buffer.split(\"\\n\");\n\t\tbuffer = lines.pop() ?? \"\";\n\t\tfor (const line of lines) {\n\t\t\t// Strip ANSI escape codes before matching (lint-staged wraps markers in color codes)\n\t\t\tconst clean = line.replace(ansiRe, \"\");\n\t\t\tconst match = clean.match(/\\[(STARTED|COMPLETED|FAILED)\\]\\s+(.+)/);\n\t\t\tif (!match) continue;\n\t\t\tconst status = match[1].toLowerCase() as HookStep[\"status\"];\n\t\t\tconst command = match[2].trim();\n\t\t\tif (isLintStagedMeta(command)) continue;\n\t\t\tconst tool = extractToolName(command) ?? command;\n\t\t\tsteps.push({ status, command, tool });\n\t\t}\n\t\treturn steps;\n\t};\n}\n\nexport function createProgressHandler(s: SpinnerResult): ProgressHandler {\n\treturn (step: HookStep) => {\n\t\tif (step.status === \"started\") {\n\t\t\ts.message(step.command);\n\t\t} else if (step.status === \"failed\") {\n\t\t\ts.message(step.command);\n\t\t}\n\t\t// completed: no action — post-commit parseToolChecks summary handles display\n\t};\n}\n","import type { ExecaError } from \"execa\";\nimport { execa } from \"execa\";\nimport { debug } from \"../utils/debug.js\";\nimport { createStderrParser, type ProgressHandler } from \"./hook-progress.js\";\n\nexport class KnownError extends Error {}\n\nexport async function assertGitRepo() {\n\tdebug(\"assertGitRepo\");\n\tconst { failed } = await execa(\"git\", [\"rev-parse\", \"--show-toplevel\"], {\n\t\treject: false,\n\t});\n\tif (failed) {\n\t\tthrow new KnownError(\"The current directory must be a Git repository!\");\n\t}\n}\n\nexport async function getRepoRoot() {\n\tconst { stdout } = await execa(\"git\", [\"rev-parse\", \"--show-toplevel\"]);\n\tdebug(\"getRepoRoot:\", stdout.trim());\n\treturn stdout.trim();\n}\n\nexport interface StagedDiffResult {\n\tfiles: string[];\n\tdiff: string;\n}\n\nexport interface ExcludedFilesResult {\n\texcludedFiles: string[];\n}\n\nexport type DiffResult = StagedDiffResult | ExcludedFilesResult | null;\n\nexport interface ChangedFile {\n\tpath: string;\n\tstatus: string;\n\tstaged: boolean;\n}\n\nconst DEFAULT_EXCLUDES = [\n\t\"package-lock.json\",\n\t\"node_modules/**\",\n\t\"dist/**\",\n\t\"build/**\",\n\t\".next/**\",\n\t\"coverage/**\",\n\t\"*.log\",\n\t\"*.min.js\",\n\t\"*.min.css\",\n\t\"*.lock\",\n\t\".DS_Store\",\n];\n\nexport function getDefaultExcludes(): string[] {\n\treturn [...DEFAULT_EXCLUDES];\n}\n\nexport async function getStagedDiff(exclude?: string[]): Promise<DiffResult> {\n\tconst excludeArgs = (exclude ?? []).map((e) => `:(exclude)${e}`);\n\tconst defaultExcludeArgs = DEFAULT_EXCLUDES.map((e) => `:(exclude)${e}`);\n\n\t// Check all staged files without excludes to detect \"all excluded\" case\n\tconst { stdout: allFiles } = await execa(\"git\", [\"diff\", \"--cached\", \"--name-only\"]);\n\tif (!allFiles) {\n\t\tdebug(\"getStagedDiff: no staged files\");\n\t\treturn null;\n\t}\n\n\t// Check staged files with excludes applied\n\tconst { stdout: files } = await execa(\"git\", [\n\t\t\"diff\",\n\t\t\"--cached\",\n\t\t\"--name-only\",\n\t\t...defaultExcludeArgs,\n\t\t...excludeArgs,\n\t]);\n\n\tif (!files) {\n\t\t// All staged files were excluded\n\t\tconst excludedFiles = allFiles.split(\"\\n\").filter(Boolean);\n\t\tdebug(\"getStagedDiff: all files excluded:\", excludedFiles);\n\t\treturn { excludedFiles };\n\t}\n\n\tconst { stdout: diff } = await execa(\"git\", [\n\t\t\"diff\",\n\t\t\"--cached\",\n\t\t\"--diff-algorithm=minimal\",\n\t\t...defaultExcludeArgs,\n\t\t...excludeArgs,\n\t]);\n\n\tdebug(\"getStagedDiff:\", files.split(\"\\n\").filter(Boolean).length, \"files,\", diff.length, \"chars\");\n\treturn { files: files.split(\"\\n\").filter(Boolean), diff };\n}\n\nexport async function stageAll() {\n\tdebug(\"stageAll: git add -A\");\n\tawait execa(\"git\", [\"add\", \"-A\"]);\n}\n\nexport async function resetStaging() {\n\tdebug(\"resetStaging: git reset HEAD\");\n\tawait execa(\"git\", [\"reset\", \"HEAD\"]);\n}\n\nexport async function getHead() {\n\tconst { stdout } = await execa(\"git\", [\"rev-parse\", \"HEAD\"]);\n\treturn stdout.trim();\n}\n\nexport async function getStatusShort() {\n\tconst { stdout } = await execa(\"git\", [\"status\", \"--short\"]);\n\treturn stdout.trim();\n}\n\nexport async function getChangedFiles(): Promise<ChangedFile[]> {\n\tconst { stdout } = await execa(\"git\", [\"status\", \"--short\"]);\n\tif (!stdout.trim()) return [];\n\tconst files = stdout\n\t\t.split(\"\\n\")\n\t\t.filter(Boolean)\n\t\t.map((line) => {\n\t\t\tconst indexStatus = line[0];\n\t\t\treturn {\n\t\t\t\tstatus: line.slice(0, 2).trim(),\n\t\t\t\tpath: line.slice(3),\n\t\t\t\tstaged: indexStatus !== \" \" && indexStatus !== \"?\",\n\t\t\t};\n\t\t});\n\tdebug(\"getChangedFiles:\", files.length, \"files\");\n\treturn files;\n}\n\nexport async function stageFiles(paths: string[]): Promise<void> {\n\tdebug(\"stageFiles:\", paths);\n\tawait execa(\"git\", [\"add\", ...paths]);\n}\n\nexport interface CommitResult {\n\tok: boolean;\n\terror?: string;\n\t/** Collected stderr from hooks/lint-staged — set on both success and failure */\n\tstderr?: string;\n}\n\nexport async function attemptCommit(\n\tmessage: string,\n\textraArgs: string[] = [],\n\tonProgress?: ProgressHandler,\n): Promise<CommitResult> {\n\tdebug(\"attemptCommit:\", message, extraArgs.length ? extraArgs : \"(no extra args)\");\n\ttry {\n\t\tconst subprocess = execa(\"git\", [\"commit\", \"-m\", message, ...extraArgs]);\n\n\t\t// Collect hook output (lint-staged, biome, etc.) for post-commit display\n\t\tconst stderrChunks: string[] = [];\n\t\tconst parser = onProgress ? createStderrParser() : null;\n\t\tsubprocess.stderr?.on(\"data\", (chunk: Buffer) => {\n\t\t\tconst text = chunk.toString();\n\t\t\tstderrChunks.push(text);\n\t\t\tif (parser && onProgress) {\n\t\t\t\tfor (const step of parser(text)) {\n\t\t\t\t\tonProgress(step);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tawait subprocess;\n\t\tdebug(\"attemptCommit: success\");\n\t\treturn { ok: true, stderr: stderrChunks.join(\"\") };\n\t} catch (error) {\n\t\tconst e = error as ExecaError;\n\t\tdebug(\"attemptCommit: failed —\", e.message?.slice(0, 200));\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: e.message,\n\t\t\tstderr: typeof e.stderr === \"string\" ? e.stderr : \"\",\n\t\t};\n\t}\n}\n\nexport async function attemptCommitNoVerify(\n\tmessage: string,\n\tonProgress?: ProgressHandler,\n): Promise<CommitResult> {\n\tdebug(\"attemptCommitNoVerify:\", message);\n\treturn attemptCommit(message, [\"--no-verify\"], onProgress);\n}\n","import { access, constants, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { execa } from \"execa\";\nimport { debug } from \"../utils/debug.js\";\n\nconst CONFIG_FILES = [\n\t\".lintstagedrc\",\n\t\".lintstagedrc.json\",\n\t\".lintstagedrc.yaml\",\n\t\".lintstagedrc.yml\",\n\t\".lintstagedrc.mjs\",\n\t\".lintstagedrc.cjs\",\n\t\"lint-staged.config.mjs\",\n\t\"lint-staged.config.cjs\",\n\t\"lint-staged.config.js\",\n];\n\nexport async function hasLintStagedConfig(repoRoot: string): Promise<boolean> {\n\tdebug(\"hasLintStagedConfig: checking in %s\", repoRoot);\n\n\t// Check dedicated config files\n\tfor (const file of CONFIG_FILES) {\n\t\tconst path = join(repoRoot, file);\n\t\ttry {\n\t\t\tawait access(path, constants.F_OK);\n\t\t\tdebug(\"hasLintStagedConfig: found %s\", file);\n\t\t\treturn true;\n\t\t} catch {\n\t\t\t// File doesn't exist, continue checking\n\t\t}\n\t}\n\n\t// Check package.json for \"lint-staged\" key\n\tconst packageJsonPath = join(repoRoot, \"package.json\");\n\ttry {\n\t\tconst raw = await readFile(packageJsonPath, \"utf8\");\n\t\tconst pkg = JSON.parse(raw) as Record<string, unknown>;\n\t\tif (\"lint-staged\" in pkg) {\n\t\t\tdebug(\"hasLintStagedConfig: found lint-staged in package.json\");\n\t\t\treturn true;\n\t\t}\n\t} catch {\n\t\t// package.json doesn't exist or can't be parsed\n\t}\n\n\tdebug(\"hasLintStagedConfig: no config found\");\n\treturn false;\n}\n\nexport async function runLintStaged(): Promise<{ ok: boolean; stdout: string; stderr: string }> {\n\tdebug(\"runLintStaged: starting npx lint-staged\");\n\tconst { failed, stdout, stderr } = await execa(\"npx\", [\"lint-staged\"], { reject: false });\n\tdebug(\"runLintStaged: finished, failed=%s\", failed);\n\treturn { ok: !failed, stdout, stderr };\n}\n","import { spawn } from \"node:child_process\";\n\nexport async function copyToClipboard(content: string): Promise<boolean> {\n\tconst commands: [string, string[]][] = [\n\t\t[\"wl-copy\", []],\n\t\t[\"xclip\", [\"-selection\", \"clipboard\"]],\n\t\t[\"xsel\", [\"--clipboard\", \"--input\"]],\n\t\t[\"pbcopy\", []],\n\t];\n\n\tfor (const [cmd, args] of commands) {\n\t\ttry {\n\t\t\tconst success = await new Promise<boolean>((resolve) => {\n\t\t\t\tconst child = spawn(cmd, args, {\n\t\t\t\t\tstdio: [\"pipe\", \"ignore\", \"ignore\"],\n\t\t\t\t});\n\n\t\t\t\tlet settled = false;\n\t\t\t\tconst done = (result: boolean) => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tresolve(result);\n\t\t\t\t};\n\n\t\t\t\t// Command not found (ENOENT)\n\t\t\t\tchild.on(\"error\", () => done(false));\n\t\t\t\t// Tool failed immediately (e.g. wl-copy on non-Wayland)\n\t\t\t\tchild.on(\"exit\", (code) => {\n\t\t\t\t\tif (code !== 0) done(false);\n\t\t\t\t});\n\n\t\t\t\tchild.stdin.write(content, (err) => {\n\t\t\t\t\tif (err) {\n\t\t\t\t\t\tdone(false);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tchild.stdin.end(() => {\n\t\t\t\t\t\t// Content sent to tool — don't wait for exit since\n\t\t\t\t\t\t// clipboard tools (xclip, wl-copy) hold selection open\n\t\t\t\t\t\tchild.unref();\n\t\t\t\t\t\tdone(true);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tif (success) return true;\n\t\t} catch {}\n\t}\n\treturn false;\n}\n","import * as p from \"@clack/prompts\";\nimport { bold, cyan, dim, green, red, yellow } from \"kolorist\";\nimport { copyToClipboard } from \"../services/clipboard.js\";\nimport type { ChangedFile } from \"../services/git.js\";\nimport type { HookError } from \"../services/hooks.js\";\nimport { debug } from \"../utils/debug.js\";\n\nexport type RecoveryResult = \"committed\" | \"cancelled\" | \"failed\";\n\nexport interface StagingChoice {\n\tfiles: string[]; // selected file paths to stage\n\tall: boolean; // whether user chose \"Stage all\"\n}\n\n// biome-ignore lint/complexity/noExcessiveLinesPerFunction: Staging menu with file list display + multiselect fallback\nexport async function showStagingMenu(\n\tfiles: ChangedFile[],\n\thasLintStaged: boolean,\n): Promise<StagingChoice | \"autogroup\" | \"lint-staged\" | null> {\n\tdebug(\"showStagingMenu: %d files\", files.length);\n\n\t// Build status labels with kolorist colors\n\tconst statusLabel = (status: string): string => {\n\t\tswitch (status) {\n\t\t\tcase \"M\":\n\t\t\t\treturn yellow(\"M\");\n\t\t\tcase \"A\":\n\t\t\t\treturn green(\"A\");\n\t\t\tcase \"D\":\n\t\t\t\treturn red(\"D\");\n\t\t\tcase \"?\":\n\t\t\tcase \"??\":\n\t\t\t\treturn cyan(\"?\");\n\t\t\tdefault:\n\t\t\t\treturn dim(status);\n\t\t}\n\t};\n\n\t// Sort: staged files first, then unstaged\n\tconst sorted = [...files].sort((a, b) => {\n\t\tif (a.staged !== b.staged) return a.staged ? -1 : 1;\n\t\treturn a.path.localeCompare(b.path);\n\t});\n\n\t// Show file list grouped by staged status\n\tconst stagedFiles = sorted.filter((f) => f.staged);\n\tconst unstagedFiles = sorted.filter((f) => !f.staged);\n\tconst lines: string[] = [];\n\tif (stagedFiles.length > 0) {\n\t\tlines.push(\n\t\t\tgreen(bold(\"Staged:\")),\n\t\t\t...stagedFiles.map((f) => ` ${statusLabel(f.status)} ${f.path}`),\n\t\t);\n\t}\n\tif (unstagedFiles.length > 0) {\n\t\tif (lines.length > 0) lines.push(\"\");\n\t\tlines.push(\n\t\t\tyellow(bold(\"Changed:\")),\n\t\t\t...unstagedFiles.map((f) => ` ${statusLabel(f.status)} ${f.path}`),\n\t\t);\n\t}\n\tp.note(lines.join(\"\\n\"), `${files.length} file${files.length !== 1 ? \"s\" : \"\"}`);\n\n\tconst choice = await p.select({\n\t\tmessage: \"Stage files for commit:\",\n\t\toptions: [\n\t\t\t{\n\t\t\t\tlabel: \"Auto-group into commits\",\n\t\t\t\tvalue: \"autogroup\",\n\t\t\t\thint: \"LLM groups files into logical commits\",\n\t\t\t},\n\t\t\t{\n\t\t\t\tlabel: \"Stage all files\",\n\t\t\t\tvalue: \"all\",\n\t\t\t\thint: `${files.length} file${files.length !== 1 ? \"s\" : \"\"}`,\n\t\t\t},\n\t\t\t...(hasLintStaged\n\t\t\t\t? [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlabel: \"Run lint-staged checks\",\n\t\t\t\t\t\t\tvalue: \"lint-staged\" as const,\n\t\t\t\t\t\t\thint: \"Pre-flight checks on all changed files\",\n\t\t\t\t\t\t},\n\t\t\t\t\t]\n\t\t\t\t: []),\n\t\t\t{ label: \"Select files...\", value: \"select\" },\n\t\t\t{ label: \"Cancel\", value: \"cancel\" },\n\t\t],\n\t});\n\n\tif (p.isCancel(choice) || choice === \"cancel\") {\n\t\treturn null;\n\t}\n\n\tif (choice === \"autogroup\") {\n\t\treturn \"autogroup\";\n\t}\n\n\tif (choice === \"lint-staged\") {\n\t\treturn \"lint-staged\";\n\t}\n\n\tif (choice === \"all\") {\n\t\treturn { files: files.map((f) => f.path), all: true };\n\t}\n\n\t// Multi-select\n\tconst selected = await p.multiselect({\n\t\tmessage: \"Select files to stage:\",\n\t\toptions: sorted.map((f) => ({\n\t\t\tlabel: `${statusLabel(f.status)} ${f.path}`,\n\t\t\tvalue: f.path,\n\t\t})),\n\t\trequired: true,\n\t});\n\n\tif (p.isCancel(selected)) {\n\t\treturn null;\n\t}\n\n\treturn { files: selected as string[], all: false };\n}\n\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Recovery menu with recursive retry path\n// biome-ignore lint/complexity/noExcessiveLinesPerFunction: Interactive TUI — format errors, handle 5 menu actions, recursive retry\nexport async function showRecoveryMenu(\n\terrors: HookError[],\n\tonRetry: () => Promise<boolean>,\n\tonSkipHooks: (message: string) => Promise<boolean>,\n\tonRestage: () => Promise<boolean>,\n\tmessage: string,\n\trawStderr: string,\n): Promise<RecoveryResult> {\n\tdebug(\"showRecoveryMenu: %d errors\", errors.length);\n\n\tlet clipboardCopied = false;\n\tlet showNote = true;\n\n\twhile (true) {\n\t\tif (showNote) {\n\t\t\tp.note(\n\t\t\t\terrors.map((e) => ` ${red(\"•\")} [${e.tool}] ${e.message}`).join(\"\\n\"),\n\t\t\t\tred(bold(\"Pre-commit hook failed\")),\n\t\t\t);\n\t\t\tshowNote = false;\n\t\t}\n\n\t\tconst choice = await p.select({\n\t\t\tmessage: \"What do you want to do?\",\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tlabel: clipboardCopied\n\t\t\t\t\t\t? `${green(\"✓\")} Copy error report to clipboard`\n\t\t\t\t\t\t: \"Copy error report to clipboard\",\n\t\t\t\t\tvalue: \"clipboard\",\n\t\t\t\t\thint: clipboardCopied ? \"Copied!\" : \"Paste into another terminal for an AI agent\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: \"Skip hooks and commit (--no-verify)\",\n\t\t\t\t\tvalue: \"skip\",\n\t\t\t\t\thint: \"Commit anyway, fix later\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: \"Re-stage files and retry\",\n\t\t\t\t\tvalue: \"restage\",\n\t\t\t\t\thint: \"Pick up fixes from another terminal\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: \"Edit commit message\",\n\t\t\t\t\tvalue: \"edit\",\n\t\t\t\t\thint: \"Modify the message before retrying\",\n\t\t\t\t},\n\t\t\t\t{ label: \"Cancel\", value: \"cancel\" },\n\t\t\t],\n\t\t});\n\n\t\tif (p.isCancel(choice)) {\n\t\t\tdebug(\"showRecoveryMenu: user cancelled\");\n\t\t\tp.outro(yellow(\"Cancelled. Message cached for --retry.\"));\n\t\t\treturn \"cancelled\";\n\t\t}\n\n\t\tdebug(\"showRecoveryMenu: user chose %s\", choice);\n\n\t\tswitch (choice) {\n\t\t\tcase \"clipboard\": {\n\t\t\t\tconst ok = await copyToClipboard(rawStderr);\n\t\t\t\tif (ok) {\n\t\t\t\t\tclipboardCopied = true;\n\t\t\t\t\tp.log.step(green(\"Copied to clipboard.\"));\n\t\t\t\t} else {\n\t\t\t\t\tp.log.warn(red(\"No clipboard tool found. Install xclip, wl-copy, or xsel.\"));\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcase \"skip\": {\n\t\t\t\tp.log.info(yellow(\"Committing with --no-verify...\"));\n\t\t\t\tconst ok = await onSkipHooks(message);\n\t\t\t\tif (ok) {\n\t\t\t\t\tp.outro(green(\"Committed (hooks skipped).\"));\n\t\t\t\t\treturn \"committed\";\n\t\t\t\t} else {\n\t\t\t\t\tp.outro(red(\"Commit failed even with --no-verify.\"));\n\t\t\t\t\treturn \"failed\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tcase \"restage\": {\n\t\t\t\tp.log.info(cyan(\"Re-staging and retrying...\"));\n\t\t\t\tconst ok = await onRestage();\n\t\t\t\tif (ok) {\n\t\t\t\t\tp.outro(green(\"Committed successfully.\"));\n\t\t\t\t\treturn \"committed\";\n\t\t\t\t}\n\t\t\t\t// Re-show errors after failed restage for context\n\t\t\t\tshowNote = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcase \"edit\": {\n\t\t\t\tconst edited = await p.text({\n\t\t\t\t\tmessage: \"Edit commit message:\",\n\t\t\t\t\tinitialValue: message,\n\t\t\t\t\tvalidate: (v) => (v?.trim() ? undefined : \"Message cannot be empty\"),\n\t\t\t\t});\n\t\t\t\tif (p.isCancel(edited)) {\n\t\t\t\t\tp.outro(yellow(\"Cancelled. Message cached for --retry.\"));\n\t\t\t\t\treturn \"cancelled\";\n\t\t\t\t}\n\t\t\t\tconst ok = await onRetry();\n\t\t\t\tif (ok) {\n\t\t\t\t\tp.outro(green(\"Committed successfully.\"));\n\t\t\t\t\treturn \"committed\";\n\t\t\t\t} else {\n\t\t\t\t\tp.outro(red(\"Commit failed again.\"));\n\t\t\t\t\treturn \"failed\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tcase \"cancel\": {\n\t\t\t\tp.outro(dim(\"Message cached for --retry.\"));\n\t\t\t\treturn \"cancelled\";\n\t\t\t}\n\t\t}\n\t}\n}\n","import Groq from \"groq-sdk\";\nimport { debug } from \"../utils/debug.js\";\n\nconst MAX_DIFF_CHARS = 20000;\n\nexport function mapGroqError(error: unknown): Error {\n\tif (error instanceof Groq.AuthenticationError) {\n\t\treturn new Error(\"Invalid GROQ_API_KEY. Run: cmint config set GROQ_API_KEY=<key>\");\n\t}\n\tif (error instanceof Groq.RateLimitError) {\n\t\treturn new Error(\"Rate limited by Groq. Please wait and try again.\");\n\t}\n\tif (error instanceof Groq.APIConnectionTimeoutError) {\n\t\treturn new Error(\"Request timed out. Check your network or try a smaller diff.\");\n\t}\n\tif (error instanceof Groq.APIError) {\n\t\treturn new Error(`Groq API error: ${error.message}`);\n\t}\n\treturn new Error(`Unexpected error: ${error instanceof Error ? error.message : String(error)}`);\n}\n\nconst CONVENTIONAL_COMMIT_REGEX =\n\t/^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\\(.+\\))?!?: .+$/;\n\nexport function stripThinkTags(text: string): string {\n\treturn text.replace(/<think[\\s\\S]*?<\\/think>/gi, \"\").trim();\n}\n\nexport function deriveMessageFromReasoning(reasoning: string): string | null {\n\tconst match = reasoning.match(\n\t\t/(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\\(.+\\))?!?: .+/i,\n\t);\n\tif (match) return match[0].trim();\n\n\tconst sentences = reasoning.split(/[.!?]/);\n\tconst first = sentences.find((s) => s.trim().length >= 10);\n\treturn first ? first.trim() : null;\n}\n\nfunction stripContextLines(diff: string): string {\n\treturn diff\n\t\t.split(\"\\n\")\n\t\t.filter((line) => !line.startsWith(\" \"))\n\t\t.join(\"\\n\");\n}\n\nexport function compressDiff(diff: string): string {\n\t// Tier 0 — Full diff\n\tif (diff.length <= MAX_DIFF_CHARS) {\n\t\treturn diff;\n\t}\n\n\t// Tier 1 — Strip context lines\n\tlet result = stripContextLines(diff);\n\tif (result.length <= MAX_DIFF_CHARS) {\n\t\treturn result;\n\t}\n\n\t// Tier 2 — Per-hunk line cap\n\tconst fileDiffs = result.split(/(?=diff --git)/).filter(Boolean);\n\tconst cappedFiles = fileDiffs.map((fd) => {\n\t\tconst parts = fd.split(/(?=\\n@@)/);\n\t\tconst cappedParts = parts.map((part, idx) => {\n\t\t\tif (idx === 0) return part; // Keep file header\n\t\t\tconst lines = part.split(\"\\n\");\n\t\t\tconst header = lines[0]; // @@ line\n\t\t\tconst changedLines = lines.slice(1).filter((l) => l.startsWith(\"+\") || l.startsWith(\"-\"));\n\t\t\tconst keptLines = changedLines.slice(0, 10);\n\t\t\treturn [header, ...keptLines].join(\"\\n\");\n\t\t});\n\t\treturn cappedParts.join(\"\");\n\t});\n\tresult = cappedFiles.join(\"\");\n\tif (result.length <= MAX_DIFF_CHARS) {\n\t\treturn result;\n\t}\n\n\t// Tier 3 — File summary\n\tconst fileMatches = diff.match(/^diff --git a\\/(.+) b\\/(.+)$/gm) || [];\n\tconst summary = fileMatches\n\t\t.map((f) => {\n\t\t\tconst match = f.match(/^diff --git a\\/(.+) b\\/(.+)$/);\n\t\t\treturn match && match[1] === match[2] ? `${match[1]} | changed` : \"\";\n\t\t})\n\t\t.filter(Boolean);\n\treturn `Summary of changes:\\n${summary.join(\"\\n\")}`;\n}\n\nexport function buildStatSummary(diff: string): string {\n\tconst files: { name: string; adds: number; dels: number }[] = [];\n\tlet currentFile = \"\";\n\tlet adds = 0;\n\tlet dels = 0;\n\n\tfor (const line of diff.split(\"\\n\")) {\n\t\tconst match = line.match(/^diff --git a\\/.+ b\\/(.+)$/);\n\t\tif (match) {\n\t\t\tif (currentFile) files.push({ name: currentFile, adds, dels });\n\t\t\tcurrentFile = match[1];\n\t\t\tadds = 0;\n\t\t\tdels = 0;\n\t\t} else if (line.startsWith(\"+\") && !line.startsWith(\"+++\")) {\n\t\t\tadds++;\n\t\t} else if (line.startsWith(\"-\") && !line.startsWith(\"---\")) {\n\t\t\tdels++;\n\t\t}\n\t}\n\tif (currentFile) files.push({ name: currentFile, adds, dels });\n\n\tconst totalAdds = files.reduce((s, f) => s + f.adds, 0);\n\tconst totalDels = files.reduce((s, f) => s + f.dels, 0);\n\n\tconst lines = files.map((f) => ` ${f.name} | +${f.adds} -${f.dels}`);\n\tlines.push(\n\t\t` ${files.length} files changed, ${totalAdds} insertions(+), ${totalDels} deletions(-)`,\n\t);\n\n\treturn lines.join(\"\\n\");\n}\n\nfunction buildSystemPrompt(type?: string): string {\n\tlet prompt =\n\t\t\"You are a commit message generator. Follow the Conventional Commits specification.\\n\" +\n\t\t\"Valid types: build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test.\\n\" +\n\t\t\"Format: type(scope): description\\n\" +\n\t\t\"Use imperative mood, lowercase, no trailing period.\\n\" +\n\t\t\"Output ONLY the commit message, no markdown fences, no explanation.\";\n\n\tif (type && type.trim().length > 0) {\n\t\tprompt += `\\nYou MUST use type: ${type}`;\n\t}\n\n\treturn prompt;\n}\n\nfunction buildUserPrompt(diff: string, hint?: string, statSummary?: string): string {\n\tconst parts: string[] = [];\n\tif (hint) parts.push(`Context: ${hint}`);\n\tif (statSummary) parts.push(`Change summary:\\n${statSummary}`);\n\tparts.push(`Generate a conventional commit for:\\n\\n${diff}`);\n\treturn parts.join(\"\\n\\n\");\n}\n\nfunction isValidConventionalCommit(message: string): boolean {\n\treturn CONVENTIONAL_COMMIT_REGEX.test(message);\n}\n\nexport function extractContentText(\n\tcontent: string | Array<{ type: string; text?: string }> | null | undefined,\n): string {\n\tif (content == null) return \"\";\n\tif (typeof content === \"string\") return content.trim();\n\tif (Array.isArray(content)) {\n\t\treturn content\n\t\t\t.filter((part) => part.type === \"text\" && typeof part.text === \"string\")\n\t\t\t.map((part) => stripThinkTags(part.text as string))\n\t\t\t.join(\"\")\n\t\t\t.trim();\n\t}\n\treturn \"\";\n}\n\n// biome-ignore lint/complexity/noExcessiveLinesPerFunction: AI pipeline — prompt build, call, validate, retry, error mapping\nexport async function generateCommitMessage(\n\tdiff: string,\n\toptions: {\n\t\tapiKey: string;\n\t\tmodel?: string;\n\t\ttype?: string;\n\t\ttimeout?: number;\n\t\thint?: string;\n\t},\n): Promise<string> {\n\tdebug(\n\t\t\"generateCommitMessage: model=%s, type=%s, hint=%s\",\n\t\toptions.model ?? \"default\",\n\t\toptions.type ?? \"none\",\n\t\toptions.hint ?? \"none\",\n\t);\n\n\tconst timeoutMs = options.timeout ?? 60000;\n\tdebug(\"Timeout: %d ms\", timeoutMs);\n\n\tconst client = new Groq({\n\t\tapiKey: options.apiKey,\n\t\ttimeout: timeoutMs,\n\t});\n\n\tconst compressedDiff = compressDiff(diff);\n\tconst statSummary = buildStatSummary(diff);\n\tconst systemPrompt = buildSystemPrompt(options.type);\n\tconst userPrompt = buildUserPrompt(compressedDiff, options.hint, statSummary);\n\n\tdebug(\"Diff: %d chars → compressed to %d chars\", diff.length, compressedDiff.length);\n\tdebug(\"Stat summary:\\n%s\", statSummary);\n\tdebug(\"User prompt length: %d chars\", userPrompt.length);\n\n\t// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Error class instanceof chain for API error mapping\n\t// biome-ignore lint/complexity/noExcessiveLinesPerFunction: API call with streaming, error handling, and retry\n\tasync function callAI(strictSystemPrompt?: string): Promise<string> {\n\t\tconst callStart = Date.now();\n\t\tconst isRetry = !!strictSystemPrompt;\n\t\tdebug(\n\t\t\t\"callAI: %s — model=%s, promptLen=%d, systemLen=%d\",\n\t\t\tisRetry ? \"RETRY (strict)\" : \"INITIAL\",\n\t\t\toptions.model ?? \"openai/gpt-oss-20b\",\n\t\t\tuserPrompt.length,\n\t\t\t(strictSystemPrompt ?? systemPrompt).length,\n\t\t);\n\t\ttry {\n\t\t\tconst isReasoningModel = /^(o[1-9]|.*gpt-oss.*|.*gpt-5.*)/i.test(options.model ?? \"\");\n\t\t\tconst completion = await client.chat.completions.create({\n\t\t\t\tmessages: [\n\t\t\t\t\t{ role: \"system\", content: strictSystemPrompt ?? systemPrompt },\n\t\t\t\t\t{ role: \"user\", content: userPrompt },\n\t\t\t\t],\n\t\t\t\tmodel: options.model ?? \"openai/gpt-oss-20b\",\n\t\t\t\ttemperature: 0.3,\n\t\t\t\t...(isReasoningModel ? { max_completion_tokens: 1024 } : { max_tokens: 1024 }),\n\t\t\t\treasoning_format: \"parsed\",\n\t\t\t});\n\n\t\t\tconst elapsed = Date.now() - callStart;\n\t\t\tconst rawContent = completion.choices[0]?.message?.content;\n\t\t\tconst processedContent =\n\t\t\t\ttypeof rawContent === \"string\" ? stripThinkTags(rawContent) : rawContent;\n\t\t\tconst content = extractContentText(processedContent);\n\t\t\tdebug(\n\t\t\t\t\"callAI response (%d ms): choices=%d, finishReason=%s, contentLen=%d, rawType=%s\",\n\t\t\t\telapsed,\n\t\t\t\tcompletion.choices.length,\n\t\t\t\tcompletion.choices[0]?.finish_reason ?? \"(none)\",\n\t\t\t\tcontent.length,\n\t\t\t\ttypeof rawContent,\n\t\t\t);\n\t\t\tdebug(\"callAI raw content: %s\", content.slice(0, 300) || \"(empty)\");\n\t\t\tif (!content) {\n\t\t\t\tconst reasoning = completion.choices[0]?.message?.reasoning;\n\t\t\t\tdebug(\n\t\t\t\t\t\"callAI: content empty, attempting reasoning fallback (reasoningLen=%d)\",\n\t\t\t\t\treasoning?.length ?? 0,\n\t\t\t\t);\n\t\t\t\tif (reasoning) {\n\t\t\t\t\tconst derived = deriveMessageFromReasoning(reasoning);\n\t\t\t\t\tif (derived) {\n\t\t\t\t\t\tdebug(\"callAI: derived message from reasoning: %s\", derived.slice(0, 100));\n\t\t\t\t\t\treturn stripThinkTags(derived);\n\t\t\t\t\t}\n\t\t\t\t\tdebug(\"callAI: could not derive message from reasoning\");\n\t\t\t\t}\n\t\t\t\tthrow new Error(\"AI returned an empty commit message\");\n\t\t\t}\n\t\t\treturn content;\n\t\t} catch (error) {\n\t\t\tconst elapsed = Date.now() - callStart;\n\t\t\tdebug(\n\t\t\t\t\"callAI FAILED after %d ms: %s\",\n\t\t\t\telapsed,\n\t\t\t\terror instanceof Error ? `${error.name}: ${error.message}` : String(error),\n\t\t\t);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\ttry {\n\t\tconst totalStart = Date.now();\n\t\tlet message = await callAI();\n\t\tdebug(\n\t\t\t\"Validation: message=%s, isValid=%s\",\n\t\t\tmessage.slice(0, 100),\n\t\t\tisValidConventionalCommit(message),\n\t\t);\n\n\t\tif (!isValidConventionalCommit(message)) {\n\t\t\tdebug(\n\t\t\t\t\"Initial message failed conventional commit validation, retrying with strict prompt (elapsed: %d ms)\",\n\t\t\t\tDate.now() - totalStart,\n\t\t\t);\n\t\t\tconst retryMessage = await callAI(\n\t\t\t\t\"You MUST output ONLY a valid conventional commit message. \" +\n\t\t\t\t\t\"Format: type(scope): description. \" +\n\t\t\t\t\t\"If you output anything else your response will be rejected.\\n\" +\n\t\t\t\t\t\"Valid types: build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test.\",\n\t\t\t);\n\t\t\tdebug(\n\t\t\t\t\"Retry validation: message=%s, isValid=%s\",\n\t\t\t\tretryMessage.slice(0, 100),\n\t\t\t\tisValidConventionalCommit(retryMessage),\n\t\t\t);\n\t\t\tif (isValidConventionalCommit(retryMessage)) {\n\t\t\t\tdebug(\"Retry produced valid conventional commit\");\n\t\t\t\tmessage = retryMessage;\n\t\t\t} else {\n\t\t\t\tdebug(\"Retry also failed validation, using original message\");\n\t\t\t}\n\t\t}\n\n\t\tdebug(\"Final message (%d ms total): %s\", Date.now() - totalStart, message);\n\t\treturn message;\n\t} catch (error) {\n\t\tdebug(\"AI error: %s\", error instanceof Error ? error.message : String(error));\n\t\tthrow mapGroqError(error);\n\t}\n}\n","import Groq from \"groq-sdk\";\nimport { debug } from \"../utils/debug.js\";\nimport {\n\tbuildStatSummary,\n\tcompressDiff,\n\tderiveMessageFromReasoning,\n\textractContentText,\n\tmapGroqError,\n} from \"./ai.js\";\n\nfunction buildReviewSystemPrompt(): string {\n\treturn [\n\t\t\"You are an expert code reviewer. Review the following staged git diff.\",\n\t\t\"\",\n\t\t\"Focus on finding:\",\n\t\t\"1. **Bugs** — logic errors, off-by-one, race conditions, null pointer risks\",\n\t\t\"2. **Security issues** — injection, exposure of secrets, missing validation, CSRF, XSS\",\n\t\t\"3. **Performance problems** — unnecessary work, large allocations in hot paths\",\n\t\t\"4. **Code quality** — readability, maintainability, error handling gaps\",\n\t\t\"5. **Edge cases** — missing boundary checks, empty states, error states\",\n\t\t\"\",\n\t\t\"For each issue found, use this format:\",\n\t\t\"- SEVERITY: [critical|major|minor|suggestion]\",\n\t\t\"- LOCATION: <file-path>:<line-number>\",\n\t\t\"- ISSUE: <description>\",\n\t\t\"- FIX: <suggested resolution>\",\n\t\t\"\",\n\t\t\"Separate issues with a blank line.\",\n\t\t\"\",\n\t\t\"If you find NO issues at all, respond with exactly: NO_ISSUES_FOUND\",\n\t\t\"\",\n\t\t\"Be thorough but practical. Only flag real problems — not style preferences or nitpicks.\",\n\t].join(\"\\n\");\n}\n\nfunction buildReviewPrompt(diff: string, files: string[], statSummary: string): string {\n\tconst parts: string[] = [];\n\tparts.push(`Review the following staged changes (${files.length} files):`);\n\tparts.push(\"\");\n\tparts.push(statSummary);\n\tparts.push(\"\");\n\tparts.push(\"```diff\");\n\tparts.push(diff);\n\tparts.push(\"```\");\n\treturn parts.join(\"\\n\");\n}\n\nexport async function generateCodeReview(\n\tdiff: string,\n\tfiles: string[],\n\toptions: {\n\t\tapiKey: string;\n\t\tmodel?: string;\n\t\ttimeout?: number;\n\t},\n): Promise<string> {\n\tdebug(\"generateCodeReview: model=%s, files=%d\", options.model ?? \"default\", files.length);\n\tconst timeoutMs = options.timeout ?? 60000;\n\tconst client = new Groq({ apiKey: options.apiKey, timeout: timeoutMs });\n\tconst compressedDiff = compressDiff(diff);\n\tconst statSummary = buildStatSummary(diff);\n\tconst systemPrompt = buildReviewSystemPrompt();\n\tconst userPrompt = buildReviewPrompt(compressedDiff, files, statSummary);\n\n\tdebug(\n\t\t\"Code review: %d chars → %d chars, system=%d chars, user=%d chars\",\n\t\tdiff.length,\n\t\tcompressedDiff.length,\n\t\tsystemPrompt.length,\n\t\tuserPrompt.length,\n\t);\n\n\ttry {\n\t\tconst completion = await client.chat.completions.create({\n\t\t\tmessages: [\n\t\t\t\t{ role: \"system\", content: systemPrompt },\n\t\t\t\t{ role: \"user\", content: userPrompt },\n\t\t\t],\n\t\t\tmodel: options.model ?? \"openai/gpt-oss-20b\",\n\t\t\ttemperature: 0.3,\n\t\t\tmax_tokens: 4096,\n\t\t});\n\n\t\tconst rawContent = completion.choices[0]?.message?.content;\n\t\tconst content = extractContentText(rawContent);\n\t\tdebug(\n\t\t\t\"generateCodeReview response: choices=%d, finishReason=%s, contentLen=%d\",\n\t\t\tcompletion.choices.length,\n\t\t\tcompletion.choices[0]?.finish_reason ?? \"(none)\",\n\t\t\tcontent.length,\n\t\t);\n\n\t\tif (!content) {\n\t\t\tconst reasoning = completion.choices[0]?.message?.reasoning;\n\t\t\tif (reasoning) {\n\t\t\t\tconst derived = deriveMessageFromReasoning(reasoning);\n\t\t\t\tif (derived) {\n\t\t\t\t\tdebug(\"generateCodeReview: derived from reasoning\");\n\t\t\t\t\treturn derived;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn \"NO_ISSUES_FOUND\";\n\t\t}\n\n\t\treturn content;\n\t} catch (error) {\n\t\tdebug(\"generateCodeReview error: %s\", error instanceof Error ? error.message : String(error));\n\t\tthrow mapGroqError(error);\n\t}\n}\n","import { intro, isCancel, log, note, outro, select, spinner } from \"@clack/prompts\";\nimport { bold, dim, green, red } from \"kolorist\";\nimport { copyToClipboard } from \"../services/clipboard.js\";\nimport { getApiKey, readConfig } from \"../services/config.js\";\nimport { assertGitRepo, getRepoRoot, getStagedDiff, stageAll } from \"../services/git.js\";\nimport { generateCodeReview } from \"../services/review-ai.js\";\nimport { debug } from \"../utils/debug.js\";\n\nexport async function reviewCommand(): Promise<void> {\n\tdebug(\"reviewCommand called\");\n\tawait assertGitRepo();\n\n\t// Stage all tracked files before reviewing\n\tconst s = spinner();\n\ts.start(\"Staging all changes...\");\n\tawait stageAll();\n\ts.stop(\"Changes staged\");\n\n\tconst diffResult = await getStagedDiff();\n\tif (!diffResult) {\n\t\toutro(dim(\"No changes to review.\"));\n\t\treturn;\n\t}\n\tif (\"excludedFiles\" in diffResult) {\n\t\toutro(dim(\"Staged files are all excluded from review.\"));\n\t\treturn;\n\t}\n\n\tintro(\"commit-mint — code review\");\n\tlog.info(diffResult.files.map((f) => ` ${f}`).join(\"\\n\"));\n\n\tconst opencodeAvailable = await isOpenCodeAvailable();\n\tconst report = opencodeAvailable\n\t\t? await reviewWithOpenCode(diffResult.diff, diffResult.files)\n\t\t: await reviewWithGroq(diffResult.diff, diffResult.files);\n\n\tconst hasIssues = report !== \"NO_ISSUES_FOUND\" && report.trim().length > 0;\n\tif (hasIssues) {\n\t\tnote(report, red(bold(\"Review findings\")));\n\t\tawait offerClipboardCopy(report);\n\t} else {\n\t\toutro(green(\"No issues found. Looks good!\"));\n\t}\n}\n\nasync function offerClipboardCopy(report: string): Promise<void> {\n\tconst shouldCopy = await select({\n\t\tmessage: \"Copy review report to clipboard?\",\n\t\toptions: [\n\t\t\t{ label: \"Yes, copy to clipboard\", value: \"yes\" },\n\t\t\t{ label: \"No\", value: \"no\" },\n\t\t],\n\t});\n\tif (isCancel(shouldCopy) || shouldCopy === \"no\") {\n\t\toutro(dim(\"Done.\"));\n\t\treturn;\n\t}\n\n\tconst ok = await copyToClipboard(report);\n\tif (ok) {\n\t\toutro(green(\"Report copied to clipboard. You can paste it anywhere for fixes.\"));\n\t} else {\n\t\toutro(red(\"Failed to copy to clipboard. Install xclip, wl-copy, or xsel.\"));\n\t}\n}\n\nexport async function isOpenCodeAvailable(): Promise<boolean> {\n\ttry {\n\t\tconst { exitCode } = await import(\"execa\").then((m) =>\n\t\t\tm.execa(\"which\", [\"opencode\"], { reject: false }),\n\t\t);\n\t\treturn exitCode === 0;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nexport async function reviewWithGroq(diff: string, files: string[]): Promise<string> {\n\tconst s = spinner();\n\ts.start(\"Reviewing with Groq...\");\n\n\ttry {\n\t\tconst config = await readConfig();\n\t\tconst apiKey = await getApiKey();\n\n\t\tconst report = await generateCodeReview(diff, files, {\n\t\t\tapiKey,\n\t\t\tmodel: config.model,\n\t\t\ttimeout: config.timeout ? Number.parseInt(config.timeout, 10) : undefined,\n\t\t});\n\n\t\ts.stop(\"Review complete\");\n\t\treturn report;\n\t} catch (err) {\n\t\ts.stop(red(\"Review failed.\"));\n\t\tdebug(\"reviewWithGroq error:\", err instanceof Error ? err.message : String(err));\n\t\tthrow err;\n\t}\n}\n\nexport async function reviewWithOpenCode(diff: string, files: string[]): Promise<string> {\n\tconst s = spinner();\n\ts.start(\"Running OpenCode review...\");\n\n\ttry {\n\t\tconst repoRoot = await getRepoRoot();\n\n\t\tconst prompt = [\n\t\t\t\"Review the staged changes in this git repository.\",\n\t\t\t\"Analyze the code diff for bugs, security issues, performance problems,\",\n\t\t\t\"code quality issues, and missing edge cases.\",\n\t\t\t\"\",\n\t\t\t`Files changed (${files.length}):`,\n\t\t\t...files.map((f) => ` - ${f}`),\n\t\t\t\"\",\n\t\t\t\"```diff\",\n\t\t\tdiff.slice(0, 15000), // Cap diff to avoid hitting token limits\n\t\t\t\"```\",\n\t\t\t\"\",\n\t\t\t\"Provide a structured report with severity, location, issue, and fix suggestion for each finding.\",\n\t\t\t\"If no issues found, respond with: NO_ISSUES_FOUND\",\n\t\t].join(\"\\n\");\n\n\t\t// Try direct execution first\n\t\tconst { stdout } = await import(\"execa\").then((m) =>\n\t\t\tm.execa(\"opencode\", [\"run\", prompt, \"--dir\", repoRoot], {\n\t\t\t\ttimeout: 120_000,\n\t\t\t\treject: false,\n\t\t\t}),\n\t\t);\n\n\t\ts.stop(\"Review complete\");\n\t\treturn stdout || \"OpenCode review completed but no output captured.\";\n\t} catch (err) {\n\t\ts.stop(red(\"OpenCode review failed.\"));\n\t\tdebug(\"reviewWithOpenCode error:\", err instanceof Error ? err.message : String(err));\n\t\tthrow new Error(`OpenCode review failed: ${err instanceof Error ? err.message : String(err)}`);\n\t}\n}\n","import { isCancel, log, outro, spinner } from \"@clack/prompts\";\nimport { bold, dim, green, red } from \"kolorist\";\nimport { isOpenCodeAvailable, reviewWithGroq, reviewWithOpenCode } from \"../commands/review.js\";\nimport { copyToClipboard } from \"../services/clipboard.js\";\nimport { getStagedDiff } from \"../services/git.js\";\nimport { debug } from \"../utils/debug.js\";\n\nexport async function runCodeReview(): Promise<void> {\n\tconst diffResult = await getStagedDiff();\n\tif (!diffResult || \"excludedFiles\" in diffResult) {\n\t\toutro(dim(\"No staged changes to review.\"));\n\t\treturn;\n\t}\n\n\tconst opencodeAvailable = await isOpenCodeAvailable();\n\tconst s = spinner();\n\ts.start(opencodeAvailable ? \"Running OpenCode review...\" : \"Running Groq review...\");\n\n\ttry {\n\t\tconst report = opencodeAvailable\n\t\t\t? await reviewWithOpenCode(diffResult.diff, diffResult.files)\n\t\t\t: await reviewWithGroq(diffResult.diff, diffResult.files);\n\t\ts.stop(\"Review complete\");\n\n\t\tawait showReviewResults(report);\n\t} catch (err) {\n\t\ts.stop(red(\"Review failed.\"));\n\t\tdebug(\"Code review error:\", err instanceof Error ? err.message : String(err));\n\t\toutro(red(err instanceof Error ? err.message : String(err)));\n\t}\n}\n\nexport async function showReviewResults(report: string): Promise<void> {\n\tconst { note: clackNote, select: clackSelect } = await import(\"@clack/prompts\");\n\tconst hasIssues = report !== \"NO_ISSUES_FOUND\" && report.trim().length > 0;\n\tif (!hasIssues) {\n\t\tlog.info(green(\"No issues found.\"));\n\t\treturn;\n\t}\n\n\tclackNote(report, red(bold(\"Review findings\")));\n\tconst shouldCopy = await clackSelect({\n\t\tmessage: \"Copy review report to clipboard?\",\n\t\toptions: [\n\t\t\t{ label: \"Yes, copy to clipboard\", value: \"yes\" },\n\t\t\t{ label: \"No\", value: \"no\" },\n\t\t],\n\t});\n\tif (isCancel(shouldCopy) || shouldCopy !== \"yes\") return;\n\n\tconst ok = await copyToClipboard(report);\n\tif (ok) {\n\t\tlog.info(green(\"Report copied to clipboard.\"));\n\t} else {\n\t\tlog.warn(red(\"Failed to copy to clipboard.\"));\n\t}\n}\n\nexport async function reviewCommitMessage(message: string): Promise<string | null> {\n\tconst { select, text } = await import(\"@clack/prompts\");\n\twhile (true) {\n\t\tconst review = await select({\n\t\t\tmessage: `Review commit message:\\n\\n ${bold(message)}\\n`,\n\t\t\toptions: [\n\t\t\t\t{ label: \"Use as-is\", value: \"use\" },\n\t\t\t\t{ label: \"Edit\", value: \"edit\" },\n\t\t\t\t{ label: \"Review with OpenCode\", value: \"review\" },\n\t\t\t\t{ label: \"Cancel\", value: \"cancel\" },\n\t\t\t],\n\t\t});\n\n\t\tif (isCancel(review) || review === \"cancel\") {\n\t\t\tdebug(\"User cancelled at review step\");\n\t\t\treturn null;\n\t\t}\n\n\t\tif (review === \"use\") {\n\t\t\tdebug(\"User accepted message\");\n\t\t\treturn message;\n\t\t}\n\n\t\tif (review === \"edit\") {\n\t\t\tdebug(\"User chose to edit message\");\n\t\t\tconst edited = await text({\n\t\t\t\tmessage: \"Edit commit message:\",\n\t\t\t\tinitialValue: message,\n\t\t\t\tvalidate: (v) => (v?.trim() ? undefined : \"Message cannot be empty\"),\n\t\t\t});\n\t\t\tif (isCancel(edited)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmessage = String(edited).trim();\n\t\t\tdebug(\"Edited message:\", message);\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (review === \"review\") {\n\t\t\tdebug(\"User chose to review code\");\n\t\t\tawait runCodeReview();\n\t\t}\n\t}\n}\n","import { createHash } from \"node:crypto\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport { join } from \"node:path\";\nimport { debug } from \"./debug.js\";\n\nconst CACHE_DIR = join(os.homedir(), \".cache\", \"commit-mint\");\n\nfunction repoHash(repoPath: string): string {\n\treturn createHash(\"sha256\").update(repoPath).digest(\"hex\").slice(0, 12);\n}\n\nfunction cachePath(repoPath: string): string {\n\treturn join(CACHE_DIR, `${repoHash(repoPath)}.json`);\n}\n\nexport interface CachedCommit {\n\tmessage: string;\n\ttimestamp: number;\n\trepoPath: string;\n}\n\nexport async function saveCachedCommit(repoPath: string, message: string) {\n\tawait mkdir(CACHE_DIR, { recursive: true });\n\tconst data: CachedCommit = {\n\t\tmessage,\n\t\ttimestamp: Date.now(),\n\t\trepoPath,\n\t};\n\tconst path = cachePath(repoPath);\n\tdebug(\"saveCachedCommit: saving to %s\", path);\n\tawait writeFile(path, JSON.stringify(data, null, 2), \"utf8\");\n}\n\nexport async function loadCachedCommit(repoPath: string): Promise<CachedCommit | null> {\n\tconst path = cachePath(repoPath);\n\tdebug(\"loadCachedCommit: loading from %s\", path);\n\ttry {\n\t\tconst raw = await readFile(path, \"utf8\");\n\t\tconst data = JSON.parse(raw) as CachedCommit;\n\t\tdebug(\"loadCachedCommit: found message from %s\", new Date(data.timestamp).toISOString());\n\t\treturn data;\n\t} catch {\n\t\tdebug(\"loadCachedCommit: no cached commit found\");\n\t\treturn null;\n\t}\n}\n","import Groq from \"groq-sdk\";\nimport { debug } from \"../utils/debug.js\";\nimport type { ChangedFile } from \"./git.js\";\nimport { getDefaultExcludes } from \"./git.js\";\n\nexport interface CommitGroup {\n\tname: string;\n\tdescription: string;\n\tfiles: string[];\n}\n\nexport interface GroupingResult {\n\tgroups: CommitGroup[];\n\texcluded: string[];\n}\n\nfunction mapGroqError(error: unknown): Error {\n\tif (error instanceof Groq.AuthenticationError) {\n\t\treturn new Error(\"Invalid GROQ_API_KEY. Run: cmint config set GROQ_API_KEY=<key>\");\n\t}\n\tif (error instanceof Groq.RateLimitError) {\n\t\treturn new Error(\"Rate limited by Groq. Please wait and try again.\");\n\t}\n\tif (error instanceof Groq.APIConnectionTimeoutError) {\n\t\treturn new Error(\"Request timed out. Check your network and try again.\");\n\t}\n\tif (error instanceof Groq.APIError) {\n\t\treturn new Error(`Groq API error: ${error.message}`);\n\t}\n\treturn new Error(`Unexpected error: ${error instanceof Error ? error.message : String(error)}`);\n}\n\nfunction matchesExcludePattern(filePath: string, pattern: string): boolean {\n\tif (pattern === filePath) return true;\n\tif (pattern.endsWith(\"/**\")) {\n\t\tconst prefix = pattern.slice(0, -3);\n\t\treturn filePath === prefix || filePath.startsWith(`${prefix}/`);\n\t}\n\tif (pattern.startsWith(\"*.\")) {\n\t\tconst suffix = pattern.slice(1);\n\t\treturn filePath.endsWith(suffix);\n\t}\n\treturn false;\n}\n\n/** Lockfiles that should be kept when their companion manifest is present */\nconst LOCKFILE_COMPANIONS: Record<string, string> = {\n\t\"package-lock.json\": \"package.json\",\n\t\"pnpm-lock.yaml\": \"package.json\",\n\t\"yarn.lock\": \"package.json\",\n};\n\nexport function filterExcludedFiles(files: ChangedFile[]): {\n\tincluded: ChangedFile[];\n\texcluded: string[];\n} {\n\tconst patterns = getDefaultExcludes();\n\tconst included: ChangedFile[] = [];\n\tconst excluded: ChangedFile[] = [];\n\tconst filePaths = new Set(files.map((f) => f.path));\n\n\tfor (const file of files) {\n\t\tconst isExcluded = patterns.some((pattern) => matchesExcludePattern(file.path, pattern));\n\t\tif (isExcluded) {\n\t\t\texcluded.push(file);\n\t\t} else {\n\t\t\tincluded.push(file);\n\t\t}\n\t}\n\n\t// Promote lockfiles whose companion manifest is present\n\tconst stillExcluded: string[] = [];\n\tfor (const file of excluded) {\n\t\tconst companion = LOCKFILE_COMPANIONS[file.path];\n\t\tif (companion && filePaths.has(companion)) {\n\t\t\tincluded.push(file);\n\t\t} else {\n\t\t\tstillExcluded.push(file.path);\n\t\t}\n\t}\n\n\tdebug(\"filterExcludedFiles: %d included, %d excluded\", included.length, stillExcluded.length);\n\treturn { included, excluded: stillExcluded };\n}\n\nfunction statusIndicator(status: string): string {\n\tswitch (status) {\n\t\tcase \"M\":\n\t\t\treturn \"modified\";\n\t\tcase \"A\":\n\t\t\treturn \"added\";\n\t\tcase \"D\":\n\t\t\treturn \"deleted\";\n\t\tcase \"R\":\n\t\t\treturn \"renamed\";\n\t\tcase \"C\":\n\t\t\treturn \"copied\";\n\t\tcase \"?\":\n\t\tcase \"??\":\n\t\t\treturn \"untracked\";\n\t\tdefault:\n\t\t\treturn \"changed\";\n\t}\n}\n\nexport function buildFileSummary(files: ChangedFile[]): string {\n\treturn files.map((f) => `${f.path} (${statusIndicator(f.status)})`).join(\"\\n\");\n}\n\nexport function buildGroupingSystemPrompt(): string {\n\treturn [\n\t\t\"You are analyzing changed files in a git repository. Group them into logical commits based on what changed and why. Each group should be a coherent unit of work.\",\n\t\t\"\",\n\t\t\"Rules:\",\n\t\t\"- Group by feature, fix, or concern (e.g., 'Frontend refactor', 'API changes', 'Test updates')\",\n\t\t\"- Keep related files together (e.g., a component + its test, a model + its migration)\",\n\t\t\"- Separate documentation changes (*.md files, docs/) from code changes — put docs in their own group\",\n\t\t\"- Do not split a single logical change across multiple groups\",\n\t\t\"- If a file does not clearly belong to any group, include it anyway — do not omit files\",\n\t\t\"\",\n\t\t\"Output format: JSON array of objects with keys 'name', 'description', 'files'.\",\n\t\t\"name: short label (3-5 words)\",\n\t\t\"description: 1-2 sentences explaining what this group changes\",\n\t\t\"files: array of exact file paths from the input\",\n\t\t\"\",\n\t\t\"Output ONLY valid JSON. No markdown fences, no explanation.\",\n\t].join(\"\\n\");\n}\n\nfunction buildGroupingUserPrompt(summary: string): string {\n\treturn [\"Group the following changed files into logical commits:\", \"\", summary].join(\"\\n\");\n}\n\nfunction parseGroupingResponse(content: string): CommitGroup[] {\n\tconst jsonText = content\n\t\t.replace(/^```json\\s*/, \"\")\n\t\t.replace(/\\s*```$/, \"\")\n\t\t.trim();\n\tconst parsed = JSON.parse(jsonText) as unknown;\n\n\tif (!Array.isArray(parsed)) {\n\t\tthrow new Error(\"AI response was not a JSON array\");\n\t}\n\n\tconst rawGroups: CommitGroup[] = [];\n\tfor (const item of parsed) {\n\t\tif (\n\t\t\ttypeof item === \"object\" &&\n\t\t\titem !== null &&\n\t\t\t\"name\" in item &&\n\t\t\t\"description\" in item &&\n\t\t\t\"files\" in item &&\n\t\t\tArray.isArray(item.files)\n\t\t) {\n\t\t\trawGroups.push({\n\t\t\t\tname: String(item.name),\n\t\t\t\tdescription: String(item.description),\n\t\t\t\tfiles: item.files.filter((f: unknown) => typeof f === \"string\") as string[],\n\t\t\t});\n\t\t}\n\t}\n\n\treturn rawGroups;\n}\n\nexport async function generateGroups(\n\tfiles: ChangedFile[],\n\tapiKey: string,\n\tmodel?: string,\n\ttimeout?: number,\n): Promise<GroupingResult> {\n\tdebug(\"generateGroups: %d files, model=%s\", files.length, model ?? \"default\");\n\n\tconst { included, excluded } = filterExcludedFiles(files);\n\n\tif (included.length === 0) {\n\t\tdebug(\"generateGroups: no files to group after exclusion\");\n\t\treturn { groups: [], excluded };\n\t}\n\n\tconst summary = buildFileSummary(included);\n\tconst systemPrompt = buildGroupingSystemPrompt();\n\tconst userPrompt = buildGroupingUserPrompt(summary);\n\n\tdebug(\"File summary:\\n%s\", summary);\n\tdebug(\"User prompt length: %d chars\", userPrompt.length);\n\n\tconst timeoutMs = timeout ?? 60000;\n\tconst client = new Groq({ apiKey, timeout: timeoutMs });\n\n\ttry {\n\t\tconst completion = await client.chat.completions.create({\n\t\t\tmessages: [\n\t\t\t\t{ role: \"system\", content: systemPrompt },\n\t\t\t\t{ role: \"user\", content: userPrompt },\n\t\t\t],\n\t\t\tmodel: model ?? \"openai/gpt-oss-20b\",\n\t\t\ttemperature: 0.3,\n\t\t\tmax_tokens: 2048,\n\t\t});\n\n\t\tconst rawContent = completion.choices[0]?.message?.content;\n\t\tconst content = typeof rawContent === \"string\" ? rawContent.trim() : \"\";\n\n\t\tdebug(\n\t\t\t\"generateGroups response: choices=%d, finishReason=%s, contentLen=%d\",\n\t\t\tcompletion.choices.length,\n\t\t\tcompletion.choices[0]?.finish_reason ?? \"(none)\",\n\t\t\tcontent.length,\n\t\t);\n\t\tdebug(\"generateGroups raw content: %s\", content.slice(0, 500) || \"(empty)\");\n\n\t\tif (!content) {\n\t\t\tthrow new Error(\"AI returned an empty grouping response\");\n\t\t}\n\n\t\tconst rawGroups = parseGroupingResponse(content);\n\n\t\tdebug(\"generateGroups: parsed %d raw groups\", rawGroups.length);\n\t\tconst validated = validateGroups(rawGroups, included);\n\t\tdebug(\"generateGroups: %d validated groups\", validated.length);\n\n\t\treturn { groups: validated, excluded };\n\t} catch (error) {\n\t\tdebug(\"generateGroups error: %s\", error instanceof Error ? error.message : String(error));\n\t\tthrow mapGroqError(error);\n\t}\n}\n\nexport function validateGroups(groups: CommitGroup[], allFiles: ChangedFile[]): CommitGroup[] {\n\tconst seen = new Set<string>();\n\tconst validated: CommitGroup[] = [];\n\n\tfor (const group of groups) {\n\t\tconst uniqueFiles = group.files.filter((f) => {\n\t\t\tif (seen.has(f)) return false;\n\t\t\tseen.add(f);\n\t\t\treturn true;\n\t\t});\n\n\t\tif (uniqueFiles.length > 0) {\n\t\t\tvalidated.push({\n\t\t\t\tname: group.name,\n\t\t\t\tdescription: group.description,\n\t\t\t\tfiles: uniqueFiles,\n\t\t\t});\n\t\t}\n\t}\n\n\t// Find files not in any group\n\tconst ungrouped = allFiles.filter((f) => !seen.has(f.path));\n\n\tif (ungrouped.length > 0) {\n\t\tdebug(\"validateGroups: %d ungrouped files added to 'Other changes'\", ungrouped.length);\n\t\tvalidated.push({\n\t\t\tname: \"Other changes\",\n\t\t\tdescription: \"Miscellaneous changes that did not fit into other groups\",\n\t\t\tfiles: ungrouped.map((f) => f.path),\n\t\t});\n\t}\n\n\treturn validated;\n}\n","import * as p from \"@clack/prompts\";\nimport { bold, cyan, dim, green } from \"kolorist\";\nimport type { CommitGroup } from \"../services/grouping.js\";\nimport { debug } from \"../utils/debug.js\";\n\nexport async function showGroupingConfirmation(\n\tgroups: CommitGroup[],\n\texcluded: string[],\n): Promise<boolean> {\n\tdebug(\"showGroupingConfirmation: %d groups, %d excluded\", groups.length, excluded.length);\n\n\tconst lines: string[] = [];\n\n\tfor (const group of groups) {\n\t\tlines.push(bold(group.name));\n\t\tlines.push(` ${dim(group.description)}`);\n\t\tlines.push(` ${green(String(group.files.length))} file${group.files.length !== 1 ? \"s\" : \"\"}`);\n\t\tfor (const file of group.files) {\n\t\t\tlines.push(` ${dim(\"•\")} ${file}`);\n\t\t}\n\t\tlines.push(\"\");\n\t}\n\n\tif (excluded.length > 0) {\n\t\tlines.push(dim(`Excluded: ${excluded.length} file${excluded.length !== 1 ? \"s\" : \"\"}`));\n\t\tfor (const file of excluded) {\n\t\t\tlines.push(` ${dim(\"•\")} ${dim(file)}`);\n\t\t}\n\t}\n\n\tp.note(lines.join(\"\\n\"), \"Proposed commit groups\");\n\n\tconst choice = await p.select({\n\t\tmessage: \"Proceed with these groupings?\",\n\t\toptions: [\n\t\t\t{ label: \"Yes, commit all groups\", value: \"yes\" },\n\t\t\t{ label: \"No, cancel\", value: \"no\" },\n\t\t],\n\t});\n\n\tif (p.isCancel(choice) || choice === \"no\") {\n\t\tdebug(\"showGroupingConfirmation: user cancelled\");\n\t\treturn false;\n\t}\n\n\tdebug(\"showGroupingConfirmation: user confirmed\");\n\treturn true;\n}\n\nexport function showGroupProgress(current: number, total: number, groupName: string): void {\n\tp.log.info(`Commit group ${current} of ${total}: ${cyan(`\"${groupName}\"`)}`);\n}\n","import { isCancel, log, outro, spinner } from \"@clack/prompts\";\nimport { dim, green, red } from \"kolorist\";\nimport { generateCommitMessage } from \"../services/ai.js\";\nimport { getApiKey, readConfig, setConfigValue } from \"../services/config.js\";\nimport {\n\tattemptCommit,\n\tattemptCommitNoVerify,\n\ttype ChangedFile,\n\tgetDefaultExcludes,\n\tgetHead,\n\tgetStagedDiff,\n\tresetStaging,\n\tstageFiles,\n} from \"../services/git.js\";\nimport { filterExcludedFiles, generateGroups, validateGroups } from \"../services/grouping.js\";\nimport { createProgressHandler } from \"../services/hook-progress.js\";\nimport { parseHookErrors, parseToolChecks } from \"../services/hooks.js\";\nimport { showGroupingConfirmation, showGroupProgress } from \"../ui/grouping.js\";\nimport { type RecoveryResult, showRecoveryMenu } from \"../ui/menu.js\";\nimport { reviewCommitMessage } from \"../ui/review-message.js\";\nimport { saveCachedCommit } from \"../utils/cache.js\";\nimport { debug } from \"../utils/debug.js\";\n\nexport interface CommitFlags {\n\tretry: boolean;\n\tauto: boolean;\n\tmessage?: string;\n\thint?: string;\n}\n\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Multi-step auto-group flow with sequential commits, review, and recovery\n// biome-ignore lint/complexity/noExcessiveLinesPerFunction: Sequential multi-commit loop with review, cache, and recovery\nexport async function runAutoGroupFlow(\n\tchangedFiles: ChangedFile[],\n\tflags: CommitFlags,\n): Promise<RecoveryResult> {\n\t// Step 1: Filter excluded files\n\tconst { included, excluded } = filterExcludedFiles(changedFiles);\n\n\t// Step 2: Ensure API key\n\ttry {\n\t\tawait getApiKey();\n\t\tdebug(\"API key found\");\n\t} catch {\n\t\tdebug(\"No API key found, prompting user\");\n\t\tconst { text: promptText } = await import(\"@clack/prompts\");\n\t\tconst key = await promptText({\n\t\t\tmessage: \"Enter your Groq API key:\",\n\t\t\tplaceholder: \"gsk_...\",\n\t\t\tvalidate: (v) => (v?.trim() ? undefined : \"API key is required\"),\n\t\t});\n\t\tif (isCancel(key)) {\n\t\t\toutro(dim(\"Cancelled.\"));\n\t\t\treturn \"cancelled\";\n\t\t}\n\t\tawait setConfigValue(\"GROQ_API_KEY\", String(key).trim());\n\t\tdebug(\"API key saved to config\");\n\t}\n\n\t// Step 3: Call grouping service\n\tconst s = spinner();\n\ts.start(\"Analyzing files...\");\n\tconst config = await readConfig();\n\tconst apiKey = await getApiKey();\n\tconst result = await generateGroups(\n\t\tincluded,\n\t\tapiKey,\n\t\tconfig.model,\n\t\tconfig.timeout ? parseInt(config.timeout, 10) : undefined,\n\t);\n\tconst validatedGroups = validateGroups(result.groups, included);\n\ts.stop(\"Files analyzed\");\n\n\t// Step 4: Show grouping confirmation (skip in auto mode)\n\tif (flags.auto) {\n\t\tdebug(\"Auto mode: skipping grouping confirmation\");\n\t} else {\n\t\tconst confirmed = await showGroupingConfirmation(validatedGroups, excluded);\n\t\tif (!confirmed) {\n\t\t\toutro(dim(\"Cancelled.\"));\n\t\t\treturn \"cancelled\";\n\t\t}\n\t}\n\n\t// Step 5: Sequential multi-commit loop\n\tfor (let i = 0; i < validatedGroups.length; i++) {\n\t\tconst group = validatedGroups[i];\n\t\tshowGroupProgress(i + 1, validatedGroups.length, group.name);\n\n\t\t// Unstage everything first, then stage only this group's files\n\t\tawait resetStaging();\n\t\tawait stageFiles(group.files);\n\n\t\t// Get diff for this group\n\t\tconst diffResult = await getStagedDiff();\n\t\tif (!diffResult || \"excludedFiles\" in diffResult) {\n\t\t\tlog.warn(red(`No changes found for group \"${group.name}\" — skipping.`));\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Generate message\n\t\ts.start(\"Generating commit message...\");\n\t\tlet message: string;\n\t\ttry {\n\t\t\tmessage = await generateMessage(diffResult.diff, flags.hint);\n\t\t} catch (err) {\n\t\t\ts.stop(red(\"Failed to generate message.\"));\n\t\t\toutro(red(err instanceof Error ? err.message : String(err)));\n\t\t\treturn \"cancelled\";\n\t\t}\n\t\ts.stop(\"Message generated\");\n\t\tlog.info(dim(message));\n\n\t\t// Review message (skip in auto mode)\n\t\tif (flags.auto) {\n\t\t\tdebug(\"Auto mode: accepting generated message\");\n\t\t} else {\n\t\t\tconst reviewed = await reviewCommitMessage(message);\n\t\t\tif (reviewed === null) {\n\t\t\t\toutro(dim(\"Cancelled.\"));\n\t\t\t\treturn \"cancelled\";\n\t\t\t}\n\t\t\tmessage = reviewed;\n\t\t}\n\n\t\t// Cache message\n\t\tconst { getRepoRoot } = await import(\"../services/git.js\");\n\t\tconst repoRoot = await getRepoRoot();\n\t\tawait saveCachedCommit(repoRoot, message);\n\n\t\t// Attempt commit\n\t\ts.start(\"Running pre-commit hooks...\");\n\t\tconst headBefore = await getHead();\n\t\tconst commitResult = await attemptCommit(message, [], createProgressHandler(s));\n\t\tconst headAfter = await getHead();\n\n\t\tif (commitResult.ok || headBefore !== headAfter) {\n\t\t\ts.stop(\"Committed successfully.\");\n\t\t\tconst checks = parseToolChecks(commitResult.stderr ?? \"\");\n\t\t\tif (checks.length > 0) {\n\t\t\t\tconst lines = checks.map((c) => ` ${c.ok ? green(\"✓\") : red(\"✗\")} ${c.tool}`);\n\t\t\t\tlog.info(lines.join(\"\\n\"));\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Hook failure — stop sequence, show recovery menu\n\t\ts.stop(\"Commit failed.\");\n\t\tconst errors = parseHookErrors(commitResult.stderr ?? \"\");\n\t\tconst recoveryResult = await showRecoveryMenu(\n\t\t\terrors,\n\t\t\tasync () => (await attemptCommit(message)).ok,\n\t\t\tasync (msg) => (await attemptCommitNoVerify(msg)).ok,\n\t\t\tasync () => {\n\t\t\t\tawait stageFiles(group.files);\n\t\t\t\treturn (await attemptCommit(message)).ok;\n\t\t\t},\n\t\t\tmessage,\n\t\t\tcommitResult.stderr ?? \"\",\n\t\t);\n\t\tif (recoveryResult === \"committed\") {\n\t\t\tif (i < validatedGroups.length - 1) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\treturn \"committed\";\n\t\t}\n\t\treturn recoveryResult;\n\t}\n\n\toutro(green(\"All groups committed.\"));\n\treturn \"committed\";\n}\n\nexport async function generateMessage(diff: string, hint?: string): Promise<string> {\n\tconst config = await readConfig();\n\tconst apiKey = await getApiKey();\n\tdebug(\"Generating message with model:\", config.model, \"type:\", config.type);\n\n\treturn generateCommitMessage(diff, {\n\t\tapiKey,\n\t\tmodel: config.model,\n\t\ttype: config.type,\n\t\ttimeout: config.timeout ? parseInt(config.timeout, 10) : undefined,\n\t\thint,\n\t});\n}\n\nexport function buildExcludedFilesMessage(files: string[]): string {\n\tconst excludes = getDefaultExcludes();\n\tconst isLockfile = (f: string) =>\n\t\texcludes.some((pattern) => {\n\t\t\tif (pattern.endsWith(\".lock\") || pattern.endsWith(\".json\")) {\n\t\t\t\treturn f === pattern || f.endsWith(pattern.replace(\"*.\", \".\"));\n\t\t\t}\n\t\t\treturn false;\n\t\t});\n\n\tif (files.every(isLockfile)) {\n\t\treturn \"chore: update lockfile\";\n\t}\n\n\treturn \"chore: update generated files\";\n}\n","import { intro, isCancel, log, outro, spinner } from \"@clack/prompts\";\nimport { dim, green, red } from \"kolorist\";\nimport { getApiKey, setConfigValue } from \"../services/config.js\";\nimport {\n\tassertGitRepo,\n\tattemptCommit,\n\tattemptCommitNoVerify,\n\tgetChangedFiles,\n\tgetHead,\n\tgetStagedDiff,\n\tgetStatusShort,\n\tstageAll,\n\tstageFiles,\n} from \"../services/git.js\";\nimport { createProgressHandler } from \"../services/hook-progress.js\";\nimport { parseHookErrors, parseToolChecks } from \"../services/hooks.js\";\nimport { hasLintStagedConfig, runLintStaged } from \"../services/lint-staged.js\";\nimport { showRecoveryMenu, showStagingMenu } from \"../ui/menu.js\";\nimport { reviewCommitMessage } from \"../ui/review-message.js\";\nimport { loadCachedCommit, saveCachedCommit } from \"../utils/cache.js\";\nimport { debug } from \"../utils/debug.js\";\nimport {\n\tbuildExcludedFilesMessage,\n\ttype CommitFlags,\n\tgenerateMessage,\n\trunAutoGroupFlow,\n} from \"./auto-group.js\";\n\n// biome-ignore lint/complexity/noExcessiveLinesPerFunction: Sequential CLI lifecycle orchestrator\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Multi-branch state machine (retry/normal, staging, review, recovery)\nexport async function commitCommand(flags: CommitFlags) {\n\tdebug(\"commitCommand called\", { flags });\n\tawait assertGitRepo();\n\n\t// ── Retry mode ──────────────────────────────────────────────────\n\tif (flags.retry) {\n\t\tdebug(\"Entering retry mode\");\n\t\tconst { getRepoRoot } = await import(\"../services/git.js\");\n\t\tconst repoRoot = await getRepoRoot();\n\t\tdebug(\"Repo root:\", repoRoot);\n\t\tconst cached = await loadCachedCommit(repoRoot);\n\t\tif (!cached) {\n\t\t\tdebug(\"No cached commit found\");\n\t\t\toutro(red(\"No cached commit message found. Run cmint without --retry first.\"));\n\t\t\tprocess.exit(1);\n\t\t}\n\t\tdebug(\"Loaded cached message:\", cached.message);\n\t\tintro(\"commit-mint — retry\");\n\t\tconst s = spinner();\n\t\ts.start(\"Running pre-commit hooks...\");\n\t\tconst result = await attemptCommit(cached.message, [], createProgressHandler(s));\n\t\ts.stop(\"Attempted commit\");\n\t\tdebug(\"Retry commit result:\", result);\n\t\tif (result.ok) {\n\t\t\t// Show clean tool check summary\n\t\t\tconst checks = parseToolChecks(result.stderr ?? \"\");\n\t\t\tif (checks.length > 0) {\n\t\t\t\tconst lines = checks.map((c) => ` ${c.ok ? green(\"✓\") : red(\"✗\")} ${c.tool}`);\n\t\t\t\tlog.info(lines.join(\"\\n\"));\n\t\t\t}\n\t\t\toutro(green(\"Committed successfully.\"));\n\t\t} else {\n\t\t\tconst errors = parseHookErrors(result.stderr ?? \"\");\n\t\t\tdebug(\"Hook errors on retry:\", errors.length);\n\t\t\tconst recoveryResult = await showRecoveryMenu(\n\t\t\t\terrors,\n\t\t\t\tasync () => (await attemptCommit(cached.message)).ok,\n\t\t\t\tasync (msg) => (await attemptCommitNoVerify(msg)).ok,\n\t\t\t\tasync () => {\n\t\t\t\t\tawait stageAll();\n\t\t\t\t\treturn (await attemptCommit(cached.message)).ok;\n\t\t\t\t},\n\t\t\t\tcached.message,\n\t\t\t\tresult.stderr ?? \"\",\n\t\t\t);\n\t\t\tif (recoveryResult === \"cancelled\") {\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\t}\n\n\t// ── Normal mode ─────────────────────────────────────────────────\n\tintro(\"commit-mint\");\n\n\tconst status = await getStatusShort();\n\tdebug(\"Git status:\", status || \"(empty)\");\n\tif (!status) {\n\t\toutro(dim(\"Nothing to commit.\"));\n\t\treturn;\n\t}\n\n\t// Stage changes\n\tlet changedFiles = await getChangedFiles();\n\tdebug(\"Changed files:\", changedFiles.length);\n\tconst s = spinner();\n\n\ttry {\n\t\tif (flags.auto) {\n\t\t\t// --auto flag: auto-group with auto-accept, skip all menus\n\t\t\tif (flags.message) {\n\t\t\t\toutro(red(\"--message flag is not compatible with auto-group mode.\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst agResult = await runAutoGroupFlow(changedFiles, flags);\n\t\t\tif (agResult !== \"committed\") {\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t\treturn;\n\t\t} else if (changedFiles.length === 1) {\n\t\t\t// Single file: auto-stage it\n\t\t\ts.start(`Staging ${changedFiles[0].path}...`);\n\t\t\tawait stageFiles([changedFiles[0].path]);\n\t\t\ts.stop(\"File staged\");\n\t\t} else {\n\t\t\t// Multiple files: show interactive staging menu (loops for lint-staged)\n\t\t\tconst { getRepoRoot } = await import(\"../services/git.js\");\n\t\t\tconst repoRoot = await getRepoRoot();\n\t\t\tconst lintStagedAvailable = await hasLintStagedConfig(repoRoot);\n\t\t\tdebug(\"lint-staged available:\", lintStagedAvailable);\n\n\t\t\tlet stagingResult: Awaited<ReturnType<typeof showStagingMenu>> = null;\n\t\t\tlet filesToStage: string[] = [];\n\t\t\tlet stageAllFlag = false;\n\n\t\t\twhile (true) {\n\t\t\t\tstagingResult = await showStagingMenu(changedFiles, lintStagedAvailable);\n\n\t\t\t\tif (stagingResult === \"autogroup\") {\n\t\t\t\t\tif (flags.message) {\n\t\t\t\t\t\toutro(red(\"--message flag is not compatible with auto-group mode.\"));\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tconst agResult = await runAutoGroupFlow(changedFiles, flags);\n\t\t\t\t\tif (agResult !== \"committed\") {\n\t\t\t\t\t\tprocess.exit(1);\n\t\t\t\t\t}\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tif (stagingResult === \"lint-staged\") {\n\t\t\t\t\tawait stageAll();\n\t\t\t\t\tconst lsSpinner = spinner();\n\t\t\t\t\tlsSpinner.start(\"Running lint-staged checks...\");\n\t\t\t\t\tconst lsResult = await runLintStaged();\n\t\t\t\t\tif (lsResult.ok) {\n\t\t\t\t\t\tlsSpinner.stop(\"All lint-staged checks passed\");\n\t\t\t\t\t\tif (lsResult.stdout.trim()) {\n\t\t\t\t\t\t\tlog.info(dim(lsResult.stdout.trim()));\n\t\t\t\t\t\t}\n\t\t\t\t\t} else {\n\t\t\t\t\t\tlsSpinner.stop(\"Lint-staged checks failed\");\n\t\t\t\t\t\tlog.info(lsResult.stderr?.trim() || lsResult.stdout?.trim() || \"Unknown error\");\n\t\t\t\t\t}\n\t\t\t\t\t// Refresh changed files list after lint-staged may have modified files\n\t\t\t\t\tchangedFiles = await getChangedFiles();\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (!stagingResult) {\n\t\t\t\t\toutro(dim(\"Cancelled.\"));\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tfilesToStage = stagingResult.files;\n\t\t\t\tstageAllFlag = stagingResult.all;\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\ts.start(`Staging ${filesToStage.length} file${filesToStage.length !== 1 ? \"s\" : \"\"}...`);\n\t\t\tif (stageAllFlag) {\n\t\t\t\tawait stageAll();\n\t\t\t} else {\n\t\t\t\tawait stageFiles(filesToStage);\n\t\t\t}\n\t\t\ts.stop(\"Files staged\");\n\t\t}\n\t} catch (err) {\n\t\ts.stop(red(\"Staging failed.\"));\n\t\tconst msg = err instanceof Error ? err.message : String(err);\n\t\tdebug(\"Staging error:\", msg);\n\t\toutro(red(`Failed to stage files: ${msg}`));\n\t\tprocess.exit(1);\n\t}\n\n\t// Get diff for AI\n\tconst diffResult = await getStagedDiff();\n\tif (!diffResult) {\n\t\tdebug(\"No staged changes found after staging\");\n\t\toutro(red(\"No staged changes found.\"));\n\t\tprocess.exit(1);\n\t}\n\n\t// Handle all-staged-files-are-excluded case with hardcoded message\n\tif (\"excludedFiles\" in diffResult) {\n\t\tdebug(\"All staged files are excluded:\", diffResult.excludedFiles);\n\t\tconst message = buildExcludedFilesMessage(diffResult.excludedFiles);\n\n\t\tlog.info(diffResult.excludedFiles.map((f) => ` ${f}`).join(\"\\n\"));\n\n\t\t// Cache and commit with hardcoded message\n\t\tconst { getRepoRoot } = await import(\"../services/git.js\");\n\t\tconst repoRoot = await getRepoRoot();\n\t\tawait saveCachedCommit(repoRoot, message);\n\n\t\ts.start(\"Running pre-commit hooks...\");\n\t\tconst headBefore = await getHead();\n\t\tconst result = await attemptCommit(message, [], createProgressHandler(s));\n\t\tconst headAfter = await getHead();\n\n\t\tif (result.ok || headBefore !== headAfter) {\n\t\t\ts.stop(\"Committed successfully.\");\n\t\t\toutro(green(\"Done.\"));\n\t\t\treturn;\n\t\t}\n\n\t\ts.stop(\"Commit failed.\");\n\t\tconst errors = parseHookErrors(result.stderr ?? \"\");\n\t\tconst recoveryResult = await showRecoveryMenu(\n\t\t\terrors,\n\t\t\tasync () => (await attemptCommit(message)).ok,\n\t\t\tasync (msg) => (await attemptCommitNoVerify(msg)).ok,\n\t\t\tasync () => {\n\t\t\t\tawait stageAll();\n\t\t\t\treturn (await attemptCommit(message)).ok;\n\t\t\t},\n\t\t\tmessage,\n\t\t\tresult.stderr ?? \"\",\n\t\t);\n\t\tif (recoveryResult === \"cancelled\") {\n\t\t\tprocess.exit(1);\n\t\t}\n\t\treturn;\n\t}\n\n\tdebug(\"Staged files:\", diffResult.files);\n\tdebug(\"Diff length:\", diffResult.diff.length, \"chars\");\n\n\tlog.info(diffResult.files.map((f) => ` ${f}`).join(\"\\n\"));\n\n\t// Generate or use provided message\n\tlet message: string;\n\n\tif (flags.message) {\n\t\tdebug(\"Using provided message:\", flags.message);\n\t\tmessage = flags.message;\n\t} else {\n\t\t// Ensure API key is available before generating\n\t\ttry {\n\t\t\tawait getApiKey();\n\t\t\tdebug(\"API key found\");\n\t\t} catch {\n\t\t\tdebug(\"No API key found, prompting user\");\n\t\t\tconst { text: promptText } = await import(\"@clack/prompts\");\n\t\t\tconst key = await promptText({\n\t\t\t\tmessage: \"Enter your Groq API key:\",\n\t\t\t\tplaceholder: \"gsk_...\",\n\t\t\t\tvalidate: (v) => (v?.trim() ? undefined : \"API key is required\"),\n\t\t\t});\n\t\t\tif (isCancel(key)) {\n\t\t\t\toutro(dim(\"Cancelled.\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait setConfigValue(\"GROQ_API_KEY\", String(key).trim());\n\t\t\tdebug(\"API key saved to config\");\n\t\t}\n\n\t\ts.start(\"Generating commit message...\");\n\t\ttry {\n\t\t\tconst genStart = Date.now();\n\t\t\tmessage = await generateMessage(diffResult.diff, flags.hint);\n\t\t\tdebug(\"generateMessage took %d ms\", Date.now() - genStart);\n\t\t\tdebug(\"Generated message:\", message);\n\t\t} catch (err) {\n\t\t\ts.stop(red(\"Failed to generate message.\"));\n\t\t\tdebug(\"Message generation failed:\", err instanceof Error ? err.message : String(err));\n\t\t\toutro(red(err instanceof Error ? err.message : String(err)));\n\t\t\treturn;\n\t\t}\n\t\ts.stop(\"Message generated\");\n\t}\n\n\t// Review message (with optional code review)\n\tconst reviewed = await reviewCommitMessage(message);\n\tif (reviewed === null) {\n\t\toutro(dim(\"Cancelled.\"));\n\t\treturn;\n\t}\n\tmessage = reviewed;\n\n\t// Cache message before attempting commit\n\tconst { getRepoRoot } = await import(\"../services/git.js\");\n\tconst repoRoot = await getRepoRoot();\n\tawait saveCachedCommit(repoRoot, message);\n\tdebug(\"Message cached for repo:\", repoRoot);\n\n\t// Attempt commit\n\ts.start(\"Running pre-commit hooks...\");\n\tconst headBefore = await getHead();\n\tdebug(\"HEAD before commit:\", headBefore);\n\tconst result = await attemptCommit(message, [], createProgressHandler(s));\n\tconst headAfter = await getHead();\n\tdebug(\"HEAD after commit:\", headAfter);\n\tdebug(\"Commit result:\", result);\n\n\tif (result.ok || headBefore !== headAfter) {\n\t\ts.stop(\"Committed successfully.\");\n\n\t\t// Show clean tool check summary\n\t\tconst checks = parseToolChecks(result.stderr ?? \"\");\n\t\tif (checks.length > 0) {\n\t\t\tconst lines = checks.map((c) => ` ${c.ok ? green(\"✓\") : red(\"✗\")} ${c.tool}`);\n\t\t\tlog.info(lines.join(\"\\n\"));\n\t\t}\n\n\t\toutro(green(\"Done.\"));\n\t\treturn;\n\t}\n\n\ts.stop(\"Commit failed.\");\n\tdebug(\"Commit failed, showing recovery menu\");\n\n\t// Hook failure — show recovery menu\n\tconst errors = parseHookErrors(result.stderr ?? \"\");\n\tdebug(\"Parsed hook errors:\", errors.length, \"errors\");\n\tconst recoveryResult = await showRecoveryMenu(\n\t\terrors,\n\t\tasync () => {\n\t\t\tconst r = await attemptCommit(message);\n\t\t\treturn r.ok;\n\t\t},\n\t\tasync (msg) => {\n\t\t\tconst r = await attemptCommitNoVerify(msg);\n\t\t\treturn r.ok;\n\t\t},\n\t\tasync () => {\n\t\t\tawait stageAll();\n\t\t\tconst r = await attemptCommit(message);\n\t\t\treturn r.ok;\n\t\t},\n\t\tmessage,\n\t\tresult.stderr ?? \"\",\n\t);\n\tif (recoveryResult === \"cancelled\") {\n\t\tprocess.exit(1);\n\t}\n}\n","import { command } from \"cleye\";\nimport { getConfigValue, setConfigValue } from \"../services/config.js\";\n\nexport const configCommand = command(\n\t{\n\t\tname: \"config\",\n\t\tparameters: [\"<mode>\", \"<key=value...>\"],\n\t},\n\tasync (argv) => {\n\t\tconst { mode, keyValue } = argv._;\n\n\t\tif (mode === \"get\") {\n\t\t\tfor (const kv of keyValue) {\n\t\t\t\tconst key = kv.split(\"=\")[0];\n\t\t\t\tconst value = await getConfigValue(key);\n\t\t\t\tconsole.log(`${key}=${value ?? \"\"}`);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tif (mode === \"set\") {\n\t\t\tfor (const kv of keyValue) {\n\t\t\t\tconst [key, ...rest] = kv.split(\"=\");\n\t\t\t\tconst value = rest.join(\"=\");\n\t\t\t\tawait setConfigValue(key, value);\n\t\t\t}\n\t\t\tconsole.log(\"Config updated.\");\n\t\t\treturn;\n\t\t}\n\n\t\tconsole.error(`Unknown config mode: ${mode}. Use \"get\" or \"set\".`);\n\t\tprocess.exit(1);\n\t},\n);\n","#!/usr/bin/env node\nimport { cli } from \"cleye\";\nimport pkg from \"../package.json\" with { type: \"json\" };\n\nconst { version } = pkg;\n\nimport { commitCommand } from \"./commands/commit.js\";\nimport { configCommand } from \"./commands/config.js\";\nimport { reviewCommand } from \"./commands/review.js\";\nimport { setDebug } from \"./utils/debug.js\";\n\ncli(\n\t{\n\t\tname: \"cmint\",\n\t\tversion,\n\t\tdescription: \"A commit tool that actually handles hook failures\",\n\t\tflags: {\n\t\t\tretry: {\n\t\t\t\ttype: Boolean,\n\t\t\t\tdescription: \"Retry the last failed commit\",\n\t\t\t\talias: \"r\",\n\t\t\t\tdefault: false,\n\t\t\t},\n\t\t\tauto: {\n\t\t\t\ttype: Boolean,\n\t\t\t\tdescription: \"Auto-group files into commits and accept messages (no prompts)\",\n\t\t\t\talias: \"a\",\n\t\t\t\tdefault: false,\n\t\t\t},\n\t\t\tmessage: {\n\t\t\t\ttype: String,\n\t\t\t\tdescription: \"Provide a commit message directly (skip AI generation)\",\n\t\t\t\talias: \"m\",\n\t\t\t},\n\t\t\thint: {\n\t\t\t\ttype: String,\n\t\t\t\tdescription: \"Add context hint for AI commit message generation\",\n\t\t\t\talias: \"H\",\n\t\t\t},\n\t\t\treview: {\n\t\t\t\ttype: Boolean,\n\t\t\t\tdescription: \"Review staged changes with a coding model\",\n\t\t\t\talias: \"R\",\n\t\t\t\tdefault: false,\n\t\t\t},\n\t\t\tdebug: {\n\t\t\t\ttype: Boolean,\n\t\t\t\tdescription: \"Enable debug output\",\n\t\t\t\talias: \"d\",\n\t\t\t\tdefault: false,\n\t\t\t},\n\t\t},\n\t\tcommands: [configCommand],\n\t},\n\t(argv) => {\n\t\tsetDebug(argv.flags.debug);\n\t\tif (argv.flags.review) {\n\t\t\treviewCommand();\n\t\t} else {\n\t\t\tcommitCommand(argv.flags);\n\t\t}\n\t},\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.mjs","names":["pkg"],"sources":["../package.json","../src/utils/debug.ts","../src/services/provider.ts","../src/services/config.ts","../src/services/hooks.ts","../src/services/hook-progress.ts","../src/services/git.ts","../src/ui/review-message.ts","../src/utils/cache.ts","../src/services/ai.ts","../src/services/checks.ts","../src/services/grouping.ts","../src/ui/grouping.ts","../src/services/clipboard.ts","../src/ui/menu.ts","../src/commands/auto-group.ts","../src/commands/commit-utils.ts","../src/commands/retry.ts","../src/commands/staging.ts","../src/commands/commit.ts","../src/commands/config.ts","../src/cli.ts"],"sourcesContent":["","import { dim } from \"kolorist\";\n\nlet enabled = false;\n\nexport function setDebug(value: boolean): void {\n\tenabled = value;\n}\n\nexport function isDebug(): boolean {\n\treturn enabled;\n}\n\nexport function debug(...args: unknown[]): void {\n\tif (!enabled) return;\n\tconst timestamp = new Date().toISOString().slice(11, 23);\n\tconsole.error(dim(`[debug ${timestamp}]`), ...args);\n}\n","import Groq from \"groq-sdk\";\n\nexport type ProviderName = \"groq\" | \"cerebras\" | \"mistral\";\n\nexport interface ProviderConfig {\n\tbaseURL: string;\n\tdefaultModel: string;\n}\n\nexport const PROVIDER_CONFIGS: Record<ProviderName, ProviderConfig> = {\n\tgroq: {\n\t\tbaseURL: \"https://api.groq.com\",\n\t\tdefaultModel: \"openai/gpt-oss-20b\",\n\t},\n\tcerebras: {\n\t\tbaseURL: \"https://api.cerebras.ai\",\n\t\tdefaultModel: \"gpt-oss-120b\",\n\t},\n\tmistral: {\n\t\tbaseURL: \"https://api.mistral.ai\",\n\t\tdefaultModel: \"mistral-small\",\n\t},\n};\n\nexport const ALLOWED_PROVIDERS = Object.keys(PROVIDER_CONFIGS) as ProviderName[];\nexport const DEFAULT_PROVIDER: ProviderName = \"groq\";\n\nexport const PROVIDER_ENV_KEYS: Record<ProviderName, string> = {\n\tgroq: \"GROQ_API_KEY\",\n\tcerebras: \"CEREBRAS_API_KEY\",\n\tmistral: \"MISTRAL_API_KEY\",\n};\n\nexport function formatProviderName(provider: string): string {\n\treturn provider.charAt(0).toUpperCase() + provider.slice(1);\n}\n\nexport function isValidProvider(name: string): name is ProviderName {\n\treturn ALLOWED_PROVIDERS.includes(name as ProviderName);\n}\n\nexport function createProvider(options: {\n\tprovider: ProviderName;\n\tapiKey: string;\n\tmodelOverride?: string;\n\ttimeout?: number;\n\tbaseURLOverride?: string;\n}): { client: Groq; model: string } {\n\tif (!isValidProvider(options.provider)) {\n\t\tthrow new Error(\n\t\t\t`Invalid provider \"${options.provider}\". Allowed values: ${ALLOWED_PROVIDERS.join(\", \")}`,\n\t\t);\n\t}\n\n\tconst providerConfig = PROVIDER_CONFIGS[options.provider];\n\tconst model = options.modelOverride ?? providerConfig.defaultModel;\n\tconst baseURL = options.baseURLOverride ?? providerConfig.baseURL;\n\n\tconst client = new Groq({\n\t\tapiKey: options.apiKey,\n\t\tbaseURL,\n\t\ttimeout: options.timeout,\n\t});\n\n\treturn { client, model };\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport { join } from \"node:path\";\nimport ini from \"ini\";\nimport { debug } from \"../utils/debug.js\";\nimport { formatProviderName, PROVIDER_ENV_KEYS, type ProviderName } from \"./provider.js\";\n\nconst CONFIG_PATH = join(os.homedir(), \".commit-mint\");\n\ninterface Config {\n\tGROQ_API_KEY?: string;\n\tCEREBRAS_API_KEY?: string;\n\tMISTRAL_API_KEY?: string;\n\tprovider?: string;\n\tmodel?: string;\n\tmodel_groq?: string;\n\tmodel_cerebras?: string;\n\tmodel_mistral?: string;\n\tlocale?: string;\n\t\"max-length\"?: string;\n\ttype?: string;\n\tproxy?: string;\n\ttimeout?: string;\n}\n\nconst defaults: Config = {\n\tprovider: \"groq\",\n\tmodel: \"openai/gpt-oss-20b\",\n\tlocale: \"en\",\n\t\"max-length\": \"100\",\n\ttype: \"\",\n\ttimeout: \"10000\",\n};\n\nexport async function readConfig(): Promise<Config> {\n\tdebug(\"readConfig: loading from %s\", CONFIG_PATH);\n\ttry {\n\t\tconst raw = await readFile(CONFIG_PATH, \"utf8\");\n\t\tconst parsed = ini.parse(raw);\n\t\tconst merged = { ...defaults, ...parsed };\n\t\tdebug(\"readConfig: loaded keys: %s\", Object.keys(merged).join(\", \"));\n\t\treturn merged;\n\t} catch {\n\t\tdebug(\"readConfig: no config file, using defaults\");\n\t\treturn { ...defaults };\n\t}\n}\n\nexport async function writeConfig(updates: Record<string, string>) {\n\tconst existing = await readConfig();\n\tObject.assign(existing, updates);\n\tawait writeFile(CONFIG_PATH, ini.stringify(existing), \"utf8\");\n}\n\nexport async function getConfigValue(key: string): Promise<string | undefined> {\n\tconst config = await readConfig();\n\treturn config[key as keyof Config];\n}\n\nexport async function setConfigValue(key: string, value: string) {\n\tawait writeConfig({ [key]: value });\n}\n\nexport async function getApiKey(): Promise<string> {\n\tconst envKey = process.env.GROQ_API_KEY;\n\tif (envKey) {\n\t\tdebug(\"getApiKey: found in env\");\n\t\treturn envKey;\n\t}\n\n\tconst config = await readConfig();\n\tif (config.GROQ_API_KEY) {\n\t\tdebug(\"getApiKey: found in config\");\n\t\treturn config.GROQ_API_KEY;\n\t}\n\n\tdebug(\"getApiKey: not found\");\n\tthrow new Error(\n\t\t\"Please set your Groq API key via `cmint config set GROQ_API_KEY=<your token>`. \" +\n\t\t\t\"Multi-provider: set `cmint config set provider=cerebras` for Cerebras, or `cmint config set provider=mistral` for Mistral.\",\n\t);\n}\n\nexport async function getProviderApiKey(provider: string): Promise<string> {\n\tconst envVar = PROVIDER_ENV_KEYS[provider as ProviderName];\n\tif (envVar) {\n\t\tconst envValue = process.env[envVar];\n\t\tif (envValue) {\n\t\t\tdebug(\"getProviderApiKey(%s): found in env\", provider);\n\t\t\treturn envValue;\n\t\t}\n\t}\n\n\tconst config = await readConfig();\n\tconst configKey = PROVIDER_ENV_KEYS[provider as ProviderName];\n\tif (configKey && (config as Record<string, string | undefined>)[configKey]) {\n\t\tdebug(\"getProviderApiKey(%s): found in config\", provider);\n\t\tconst val = (config as Record<string, string | undefined>)[configKey];\n\t\treturn val as string;\n\t}\n\n\tdebug(\"getProviderApiKey(%s): not found\", provider);\n\tthrow new Error(\n\t\t`Please set your ${formatProviderName(provider)} API key via \\`cmint config set ${envVar}=<your token>\\``,\n\t);\n}\n\nexport function getModelForProvider(\n\tconfig: Config,\n\tprovider: string,\n\tdefaultModel: string,\n): string {\n\tconst modelKey = `model_${provider}` as keyof Config;\n\treturn config[modelKey] ?? config.model ?? defaultModel;\n}\n","import { debug } from \"../utils/debug.js\";\n\nexport interface HookError {\n\ttool: string;\n\tmessage: string;\n\traw: string;\n}\n\n/**\n * Parse git hook error output into structured, human-readable errors.\n * Handles output from lint-staged, biome, eslint, tsc, vitest, jest.\n */\nexport function parseHookErrors(stderr: string): HookError[] {\n\tif (!stderr) return [];\n\n\tdebug(\"parseHookErrors: stderr length=%d\", stderr.length);\n\tconst errors: HookError[] = [];\n\n\t// Detect lint-staged task failures\n\tif (stderr.includes(\"lint-staged\") || stderr.includes(\"[FAILED]\")) {\n\t\terrors.push(...parseLintStagedErrors(stderr));\n\t}\n\n\t// Detect biome errors\n\tif (stderr.includes(\"biome\") || stderr.includes(\"Biome\")) {\n\t\terrors.push(...parseBiomeErrors(stderr));\n\t}\n\n\t// Detect TypeScript errors\n\tif (stderr.includes(\"error TS\") || stderr.includes(\"tsc\")) {\n\t\terrors.push(...parseTscErrors(stderr));\n\t}\n\n\t// Detect vitest/jest test failures\n\tif (\n\t\tstderr.includes(\"vitest\") ||\n\t\tstderr.includes(\"jest\") ||\n\t\tstderr.includes(\"FAIL\") ||\n\t\tstderr.includes(\"test failed\")\n\t) {\n\t\terrors.push(...parseTestErrors(stderr));\n\t}\n\n\t// Detect ESLint errors\n\tif (stderr.includes(\"eslint\") || stderr.includes(\"ESLint\")) {\n\t\terrors.push(...parseEslintErrors(stderr));\n\t}\n\n\t// Fallback: if nothing parsed, return the raw output\n\tif (errors.length === 0) {\n\t\tdebug(\"parseHookErrors: no patterns matched, using raw fallback\");\n\t\terrors.push({\n\t\t\ttool: \"git hooks\",\n\t\t\tmessage: stderr.trim(),\n\t\t\traw: stderr,\n\t\t});\n\t}\n\n\tdebug(\"parseHookErrors: found %d errors\", errors.length);\n\treturn errors;\n}\n\nfunction parseLintStagedErrors(output: string): HookError[] {\n\tconst errors: HookError[] = [];\n\tfor (const match of output.matchAll(/\\[FAILED\\]\\s+(.+?)\\s+\\[FAILED\\]/g)) {\n\t\tconst task = match[1].trim();\n\t\terrors.push({\n\t\t\ttool: \"lint-staged\",\n\t\t\tmessage: `Task failed: ${task}`,\n\t\t\traw: match[0],\n\t\t});\n\t}\n\n\treturn errors;\n}\n\nfunction parseBiomeErrors(output: string): HookError[] {\n\tconst errors: HookError[] = [];\n\tfor (const match of output.matchAll(/^(.+?):(\\d+):(\\d+)\\s+(.+)$/gm)) {\n\t\terrors.push({\n\t\t\ttool: \"biome\",\n\t\t\tmessage: `${match[1]}:${match[2]}:${match[3]} — ${match[4]}`,\n\t\t\traw: match[0],\n\t\t});\n\t}\n\n\tif (errors.length === 0 && output.includes(\"biome\")) {\n\t\terrors.push({\n\t\t\ttool: \"biome\",\n\t\t\tmessage: \"Biome check failed. See raw output for details.\",\n\t\t\traw: output,\n\t\t});\n\t}\n\n\treturn errors;\n}\n\nfunction parseTscErrors(output: string): HookError[] {\n\tconst errors: HookError[] = [];\n\tfor (const match of output.matchAll(/^(.+?)\\((\\d+),(\\d+)\\):\\s+error\\s+(TS\\d+):\\s+(.+)$/gm)) {\n\t\terrors.push({\n\t\t\ttool: \"tsc\",\n\t\t\tmessage: `${match[1]}:${match[2]}:${match[3]} — ${match[4]}: ${match[5]}`,\n\t\t\traw: match[0],\n\t\t});\n\t}\n\n\treturn errors;\n}\n\nfunction parseTestErrors(output: string): HookError[] {\n\tconst errors: HookError[] = [];\n\tconst failPattern = /FAIL\\s+(.+\\.(test|spec)\\..+)/;\n\tconst match = failPattern.exec(output);\n\n\tif (match) {\n\t\terrors.push({\n\t\t\ttool: output.includes(\"vitest\") ? \"vitest\" : \"jest\",\n\t\t\tmessage: `Test file failed: ${match[1]}`,\n\t\t\traw: output,\n\t\t});\n\t}\n\n\tif (errors.length === 0 && (output.includes(\"vitest\") || output.includes(\"jest\"))) {\n\t\terrors.push({\n\t\t\ttool: output.includes(\"vitest\") ? \"vitest\" : \"jest\",\n\t\t\tmessage: \"Tests failed. See raw output for details.\",\n\t\t\traw: output,\n\t\t});\n\t}\n\n\treturn errors;\n}\n\nfunction parseEslintErrors(output: string): HookError[] {\n\tconst errors: HookError[] = [];\n\tconst lines = output.split(\"\\n\");\n\tlet currentFile = \"\";\n\n\tfor (const line of lines) {\n\t\t// ESLint file path line: not indented, contains a path separator\n\t\tif (!/^\\s/.test(line) && line.includes(\"/\")) {\n\t\t\tcurrentFile = line.trim();\n\t\t\tcontinue;\n\t\t}\n\n\t\t// ESLint error/warning detail: <line>:<col> <severity> <message> <rule>\n\t\t// Message and rule are separated by 2+ spaces\n\t\tconst match = line.match(/^\\s*(\\d+):(\\d+)\\s+(error|warning)\\s+(.+)\\s{2,}(\\S+)\\s*$/);\n\t\tif (match) {\n\t\t\tconst [, lineNum, col, severity, message, rule] = match;\n\t\t\tconst file = currentFile || \"unknown\";\n\t\t\terrors.push({\n\t\t\t\ttool: \"eslint\",\n\t\t\t\tmessage: `${file}:${lineNum}:${col} ${severity}: ${message} (${rule})`,\n\t\t\t\traw: line.trim(),\n\t\t\t});\n\t\t}\n\t}\n\n\treturn errors;\n}\n\nexport function formatErrorReport(errors: HookError[]): string {\n\tif (errors.length === 0) return \"\";\n\n\tconst sections = errors.map((e) => `[${e.tool}]\\n${e.message}`);\n\treturn sections.join(\"\\n\\n\");\n}\n\n// ── Tool check parsing (success case) ──────────────────────────────\n\nexport interface ToolCheck {\n\ttool: string;\n\tok: boolean;\n}\n\n/**\n * Parse lint-staged/hook stderr output to discover which tools ran\n * and whether they succeeded. Used for clean post-commit summary.\n */\nexport function parseToolChecks(stderr: string): ToolCheck[] {\n\tif (!stderr) return [];\n\n\tconst checks: ToolCheck[] = [];\n\t// Match [COMPLETED] and [FAILED] status lines from lint-staged\n\tfor (const match of stderr.matchAll(/\\[(COMPLETED|FAILED)\\]\\s+(.+)/g)) {\n\t\tconst status = match[1];\n\t\tconst command = match[2].trim();\n\n\t\tif (isLintStagedMeta(command)) continue;\n\n\t\tconst tool = extractToolName(command);\n\t\tif (!tool) continue;\n\n\t\tchecks.push({ tool, ok: status === \"COMPLETED\" });\n\t}\n\n\t// Deduplicate by tool name (keep last occurrence — final status)\n\tconst seen = new Map<string, ToolCheck>();\n\tfor (const c of checks) {\n\t\tseen.set(c.tool, c);\n\t}\n\n\treturn [...seen.values()];\n}\n\n/** Heuristic: skip lint-staged internal metadata lines */\nexport function isLintStagedMeta(command: string): boolean {\n\t// Glob patterns in task labels\n\tif (/[*{}[\\]]/.test(command)) return true;\n\t// Task count labels: \"src/ — 3 files\", \"src/ — no files\"\n\t// The dash can be em-dash (—), en-dash (–), or plain hyphen (-)\n\tif (/\\s[-–—]\\s(\\d+\\s)?files?$/.test(command)) return true;\n\tif (/\\s[-–—]\\sno\\s files$/.test(command)) return true;\n\t// Internal lint-staged lifecycle messages\n\tif (\n\t\t/^(Running tasks|Applying modifications|Cleaning up|Backing up|Backed up|Updating Git)/.test(\n\t\t\tcommand,\n\t\t)\n\t)\n\t\treturn true;\n\t// Ends with ellipsis (e.g. \"Backing up original state...\")\n\tif (/\\.{3}$/.test(command)) return true;\n\treturn false;\n}\n\n/** Extract a display-friendly tool name from a lint-staged command */\nexport function extractToolName(command: string): string | null {\n\t// Step 1: Unwrap sh -c '...' wrapper\n\tconst unwrapped = unwrapShC(command);\n\tif (unwrapped !== null) command = unwrapped;\n\n\t// Step 2: Find the meaningful command in a && chain (skip cd segments)\n\tcommand = findMeaningfulCommand(command);\n\n\treturn parseToolFromTokens(command.split(/\\s+/));\n}\n\n/** Map common script names to their underlying tool */\nconst SCRIPT_MAP: Record<string, string> = {\n\ttypecheck: \"tsc\",\n\tlint: \"eslint\",\n\tformat: \"prettier\",\n};\n\n/** Package managers that use [run|exec] <script|tool> pattern */\nconst PKG_MANAGERS = [\"npm\", \"yarn\", \"pnpm\", \"bun\"];\n\n/** Parse tool name from a tokenized command */\nfunction parseToolFromTokens(tokens: string[]): string | null {\n\tconst first = tokens[0];\n\n\t// Safety: don't return the shell itself as a tool name\n\tif (first === \"sh\" || first === \"bash\" || first === \"zsh\") return null;\n\n\t// npm/yarn/pnpm/bun [run|exec] <script/tool>\n\tif (PKG_MANAGERS.includes(first)) {\n\t\treturn parsePackageManagerTool(tokens);\n\t}\n\n\t// npx <tool>\n\tif (first === \"npx\") return tokens[1] ?? null;\n\n\t// uv run <tool> / uv tool run <tool>\n\tif (first === \"uv\") return parseUvTool(tokens);\n\n\t// Direct tool invocation (biome, eslint, tsc, vitest, jest, prettier)\n\treturn first;\n}\n\n/** Extract tool name from npm/yarn/pnpm/bun commands */\nfunction parsePackageManagerTool(tokens: string[]): string | null {\n\tconst sub = tokens[1];\n\t// pnpm exec <tool>\n\tif (sub === \"exec\") return tokens[2] ?? null;\n\t// npm/yarn/pnpm [run] <script>\n\tconst scriptIdx = sub === \"run\" ? 2 : 1;\n\tconst script = tokens[scriptIdx];\n\tif (!script) return null;\n\treturn SCRIPT_MAP[script] ?? script;\n}\n\n/** Extract tool name from uv commands */\nfunction parseUvTool(tokens: string[]): string | null {\n\tif (tokens[1] === \"run\") return tokens[2] ?? null;\n\tif (tokens[1] === \"tool\" && tokens[2] === \"run\") return tokens[3] ?? null;\n\treturn null;\n}\n\n/** Unwrap sh -c 'command' or sh -c \"command\" wrappers */\nfunction unwrapShC(command: string): string | null {\n\t// sh/bash -c 'body' or sh/bash -c \"body\"\n\tconst quoted = command.match(/^(?:sh|bash|zsh)\\s+-c\\s+(['\"])([\\s\\S]*)\\1$/);\n\tif (quoted) return quoted[2];\n\t// sh/bash -c body (no quotes, single word — rare)\n\tconst bare = command.match(/^(?:sh|bash|zsh)\\s+-c\\s+(\\S+)$/);\n\tif (bare) return bare[1];\n\treturn null;\n}\n\n/** Find the meaningful command in a && chain, skipping cd segments */\nfunction findMeaningfulCommand(command: string): string {\n\tconst segments = command\n\t\t.split(/\\s*&&\\s*/)\n\t\t.map((s) => s.trim())\n\t\t.filter(Boolean);\n\tfor (const seg of segments) {\n\t\tif (/^cd\\s/.test(seg)) continue;\n\t\treturn seg;\n\t}\n\treturn segments[segments.length - 1] || command;\n}\n","import type { SpinnerResult } from \"@clack/prompts\";\nimport { extractToolName, isLintStagedMeta } from \"./hooks.js\";\n\nexport interface HookStep {\n\tstatus: \"started\" | \"completed\" | \"failed\";\n\tcommand: string;\n\ttool: string;\n}\n\nexport type ProgressHandler = (step: HookStep) => void;\n\nconst ansiRe = new RegExp(`${String.fromCharCode(0x1b)}\\\\[[0-9;]*m`, \"g\");\n\nexport function createStderrParser(): (chunk: string) => HookStep[] {\n\tlet buffer = \"\";\n\treturn (chunk: string): HookStep[] => {\n\t\tbuffer += chunk;\n\t\tconst steps: HookStep[] = [];\n\t\tconst lines = buffer.split(\"\\n\");\n\t\tbuffer = lines.pop() ?? \"\";\n\t\tfor (const line of lines) {\n\t\t\t// Strip ANSI escape codes before matching (lint-staged wraps markers in color codes)\n\t\t\tconst clean = line.replace(ansiRe, \"\");\n\t\t\tconst match = clean.match(/\\[(STARTED|COMPLETED|FAILED)\\]\\s+(.+)/);\n\t\t\tif (!match) continue;\n\t\t\tconst status = match[1].toLowerCase() as HookStep[\"status\"];\n\t\t\tconst command = match[2].trim();\n\t\t\tif (isLintStagedMeta(command)) continue;\n\t\t\tconst tool = extractToolName(command) ?? command;\n\t\t\tsteps.push({ status, command, tool });\n\t\t}\n\t\treturn steps;\n\t};\n}\n\nexport function createProgressHandler(s: SpinnerResult): ProgressHandler {\n\treturn (step: HookStep) => {\n\t\tif (step.status === \"started\") {\n\t\t\ts.message(step.command);\n\t\t} else if (step.status === \"failed\") {\n\t\t\ts.message(step.command);\n\t\t}\n\t\t// completed: no action — post-commit parseToolChecks summary handles display\n\t};\n}\n","import type { ExecaError } from \"execa\";\nimport { execa } from \"execa\";\nimport { debug } from \"../utils/debug.js\";\nimport { createStderrParser, type ProgressHandler } from \"./hook-progress.js\";\n\nexport class KnownError extends Error {}\n\nexport async function assertGitRepo() {\n\tdebug(\"assertGitRepo\");\n\tconst { failed } = await execa(\"git\", [\"rev-parse\", \"--show-toplevel\"], {\n\t\treject: false,\n\t});\n\tif (failed) {\n\t\tthrow new KnownError(\"The current directory must be a Git repository!\");\n\t}\n}\n\nexport async function getRepoRoot() {\n\tconst { stdout } = await execa(\"git\", [\"rev-parse\", \"--show-toplevel\"]);\n\tdebug(\"getRepoRoot:\", stdout.trim());\n\treturn stdout.trim();\n}\n\nexport interface StagedDiffResult {\n\tfiles: string[];\n\tdiff: string;\n}\n\nexport interface ExcludedFilesResult {\n\texcludedFiles: string[];\n}\n\nexport type DiffResult = StagedDiffResult | ExcludedFilesResult | null;\n\nexport interface ChangedFile {\n\tpath: string;\n\tstatus: string;\n\tstaged: boolean;\n}\n\nconst DEFAULT_EXCLUDES = [\n\t\"package-lock.json\",\n\t\"node_modules/**\",\n\t\"dist/**\",\n\t\"build/**\",\n\t\".next/**\",\n\t\"coverage/**\",\n\t\"*.log\",\n\t\"*.min.js\",\n\t\"*.min.css\",\n\t\"*.lock\",\n\t\".DS_Store\",\n];\n\nexport function getDefaultExcludes(): string[] {\n\treturn [...DEFAULT_EXCLUDES];\n}\n\nexport async function getStagedDiff(exclude?: string[]): Promise<DiffResult> {\n\tconst excludeArgs = (exclude ?? []).map((e) => `:(exclude)${e}`);\n\tconst defaultExcludeArgs = DEFAULT_EXCLUDES.map((e) => `:(exclude)${e}`);\n\n\t// Check all staged files without excludes to detect \"all excluded\" case\n\tconst { stdout: allFiles } = await execa(\"git\", [\"diff\", \"--cached\", \"--name-only\"]);\n\tif (!allFiles) {\n\t\tdebug(\"getStagedDiff: no staged files\");\n\t\treturn null;\n\t}\n\n\t// Check staged files with excludes applied\n\tconst { stdout: files } = await execa(\"git\", [\n\t\t\"diff\",\n\t\t\"--cached\",\n\t\t\"--name-only\",\n\t\t...defaultExcludeArgs,\n\t\t...excludeArgs,\n\t]);\n\n\tif (!files) {\n\t\t// All staged files were excluded\n\t\tconst excludedFiles = allFiles.split(\"\\n\").filter(Boolean);\n\t\tdebug(\"getStagedDiff: all files excluded:\", excludedFiles);\n\t\treturn { excludedFiles };\n\t}\n\n\tconst { stdout: diff } = await execa(\"git\", [\n\t\t\"diff\",\n\t\t\"--cached\",\n\t\t\"--diff-algorithm=minimal\",\n\t\t...defaultExcludeArgs,\n\t\t...excludeArgs,\n\t]);\n\n\tdebug(\"getStagedDiff:\", files.split(\"\\n\").filter(Boolean).length, \"files,\", diff.length, \"chars\");\n\treturn { files: files.split(\"\\n\").filter(Boolean), diff };\n}\n\nexport async function stageAll() {\n\tdebug(\"stageAll: git add -A\");\n\tawait execa(\"git\", [\"add\", \"-A\"]);\n}\n\nexport async function resetStaging() {\n\tdebug(\"resetStaging: git reset HEAD\");\n\tawait execa(\"git\", [\"reset\", \"HEAD\"]);\n}\n\nexport async function getHead() {\n\tconst { stdout } = await execa(\"git\", [\"rev-parse\", \"HEAD\"]);\n\treturn stdout.trim();\n}\n\nexport async function getStatusShort() {\n\tconst { stdout } = await execa(\"git\", [\"status\", \"--short\"]);\n\treturn stdout.trim();\n}\n\nexport async function getChangedFiles(): Promise<ChangedFile[]> {\n\tconst { stdout } = await execa(\"git\", [\"status\", \"--short\"]);\n\tif (!stdout.trim()) return [];\n\tconst files = stdout\n\t\t.split(\"\\n\")\n\t\t.filter(Boolean)\n\t\t.map((line) => {\n\t\t\tconst indexStatus = line[0];\n\t\t\treturn {\n\t\t\t\tstatus: line.slice(0, 2).trim(),\n\t\t\t\tpath: line.slice(3),\n\t\t\t\tstaged: indexStatus !== \" \" && indexStatus !== \"?\",\n\t\t\t};\n\t\t});\n\tdebug(\"getChangedFiles:\", files.length, \"files\");\n\treturn files;\n}\n\nexport async function stageFiles(paths: string[]): Promise<void> {\n\tdebug(\"stageFiles:\", paths);\n\tawait execa(\"git\", [\"add\", ...paths]);\n}\n\nexport interface CommitResult {\n\tok: boolean;\n\terror?: string;\n\t/** Collected stderr from hooks/lint-staged — set on both success and failure */\n\tstderr?: string;\n}\n\nexport async function attemptCommit(\n\tmessage: string,\n\textraArgs: string[] = [],\n\tonProgress?: ProgressHandler,\n): Promise<CommitResult> {\n\tdebug(\"attemptCommit:\", message, extraArgs.length ? extraArgs : \"(no extra args)\");\n\ttry {\n\t\tconst subprocess = execa(\"git\", [\"commit\", \"-m\", message, ...extraArgs]);\n\n\t\t// Collect hook output (lint-staged, biome, etc.) for post-commit display\n\t\tconst stderrChunks: string[] = [];\n\t\tconst parser = onProgress ? createStderrParser() : null;\n\t\tsubprocess.stderr?.on(\"data\", (chunk: Buffer) => {\n\t\t\tconst text = chunk.toString();\n\t\t\tstderrChunks.push(text);\n\t\t\tif (parser && onProgress) {\n\t\t\t\tfor (const step of parser(text)) {\n\t\t\t\t\tonProgress(step);\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\tawait subprocess;\n\t\tdebug(\"attemptCommit: success\");\n\t\treturn { ok: true, stderr: stderrChunks.join(\"\") };\n\t} catch (error) {\n\t\tconst e = error as ExecaError;\n\t\tdebug(\"attemptCommit: failed —\", e.message?.slice(0, 200));\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: e.message,\n\t\t\tstderr: typeof e.stderr === \"string\" ? e.stderr : \"\",\n\t\t};\n\t}\n}\n\nexport async function attemptCommitNoVerify(\n\tmessage: string,\n\tonProgress?: ProgressHandler,\n): Promise<CommitResult> {\n\tdebug(\"attemptCommitNoVerify:\", message);\n\treturn attemptCommit(message, [\"--no-verify\"], onProgress);\n}\n","import { isCancel } from \"@clack/prompts\";\nimport { bold } from \"kolorist\";\nimport { debug } from \"../utils/debug.js\";\n\nexport async function reviewCommitMessage(message: string): Promise<string | null> {\n\tconst { select, text } = await import(\"@clack/prompts\");\n\twhile (true) {\n\t\tconst review = await select({\n\t\t\tmessage: `Review commit message:\\n\\n ${bold(message)}\\n`,\n\t\t\toptions: [\n\t\t\t\t{ label: \"Use as-is\", value: \"use\" },\n\t\t\t\t{ label: \"Edit\", value: \"edit\" },\n\t\t\t\t{ label: \"Cancel\", value: \"cancel\" },\n\t\t\t],\n\t\t});\n\n\t\tif (isCancel(review) || review === \"cancel\") {\n\t\t\tdebug(\"User cancelled at review step\");\n\t\t\treturn null;\n\t\t}\n\n\t\tif (review === \"use\") {\n\t\t\tdebug(\"User accepted message\");\n\t\t\treturn message;\n\t\t}\n\n\t\tif (review === \"edit\") {\n\t\t\tdebug(\"User chose to edit message\");\n\t\t\tconst edited = await text({\n\t\t\t\tmessage: \"Edit commit message:\",\n\t\t\t\tinitialValue: message,\n\t\t\t\tvalidate: (v) => (v?.trim() ? undefined : \"Message cannot be empty\"),\n\t\t\t});\n\t\t\tif (isCancel(edited)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tmessage = String(edited).trim();\n\t\t\tdebug(\"Edited message:\", message);\n\t\t}\n\t}\n}\n","import { createHash } from \"node:crypto\";\nimport { mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport os from \"node:os\";\nimport { join } from \"node:path\";\nimport { debug } from \"./debug.js\";\n\nconst CACHE_DIR = join(os.homedir(), \".cache\", \"commit-mint\");\n\nfunction repoHash(repoPath: string): string {\n\treturn createHash(\"sha256\").update(repoPath).digest(\"hex\").slice(0, 12);\n}\n\nfunction cachePath(repoPath: string): string {\n\treturn join(CACHE_DIR, `${repoHash(repoPath)}.json`);\n}\n\nexport interface CachedCommit {\n\tmessage: string;\n\ttimestamp: number;\n\trepoPath: string;\n}\n\nexport async function saveCachedCommit(repoPath: string, message: string) {\n\tawait mkdir(CACHE_DIR, { recursive: true });\n\tconst data: CachedCommit = {\n\t\tmessage,\n\t\ttimestamp: Date.now(),\n\t\trepoPath,\n\t};\n\tconst path = cachePath(repoPath);\n\tdebug(\"saveCachedCommit: saving to %s\", path);\n\tawait writeFile(path, JSON.stringify(data, null, 2), \"utf8\");\n}\n\nexport async function loadCachedCommit(repoPath: string): Promise<CachedCommit | null> {\n\tconst path = cachePath(repoPath);\n\tdebug(\"loadCachedCommit: loading from %s\", path);\n\ttry {\n\t\tconst raw = await readFile(path, \"utf8\");\n\t\tconst data = JSON.parse(raw) as CachedCommit;\n\t\tdebug(\"loadCachedCommit: found message from %s\", new Date(data.timestamp).toISOString());\n\t\treturn data;\n\t} catch {\n\t\tdebug(\"loadCachedCommit: no cached commit found\");\n\t\treturn null;\n\t}\n}\n","import Groq from \"groq-sdk\";\nimport { debug } from \"../utils/debug.js\";\nimport { createProvider, formatProviderName, type ProviderName } from \"./provider.js\";\n\nconst MAX_DIFF_CHARS = 20000;\n\nexport function mapGroqError(error: unknown, providerLabel?: string): Error {\n\tconst label = providerLabel ?? \"Groq\";\n\tif (error instanceof Groq.AuthenticationError) {\n\t\treturn new Error(\n\t\t\t`Invalid API key for ${label}. Run: cmint config set ${label.toUpperCase()}_API_KEY=<key>`,\n\t\t);\n\t}\n\tif (error instanceof Groq.RateLimitError) {\n\t\treturn new Error(`Rate limited by ${label}. Please wait and try again.`);\n\t}\n\tif (error instanceof Groq.APIConnectionTimeoutError) {\n\t\treturn new Error(\"Request timed out. Check your network or try a smaller diff.\");\n\t}\n\tif (error instanceof Groq.APIError) {\n\t\treturn new Error(`${label} API error: ${error.message}`);\n\t}\n\treturn new Error(`Unexpected error: ${error instanceof Error ? error.message : String(error)}`);\n}\n\nconst CONVENTIONAL_COMMIT_REGEX =\n\t/^(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\\(.+\\))?!?: .+$/;\n\nexport function stripThinkTags(text: string): string {\n\treturn text.replace(/<think[\\s\\S]*?<\\/think>/gi, \"\").trim();\n}\n\nexport function deriveMessageFromReasoning(reasoning: string): string | null {\n\tconst match = reasoning.match(\n\t\t/(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\\(.+\\))?!?: .+/i,\n\t);\n\tif (match) return match[0].trim();\n\n\tconst sentences = reasoning.split(/[.!?]/);\n\tconst first = sentences.find((s) => s.trim().length >= 10);\n\treturn first ? first.trim() : null;\n}\n\nfunction stripContextLines(diff: string): string {\n\treturn diff\n\t\t.split(\"\\n\")\n\t\t.filter((line) => !line.startsWith(\" \"))\n\t\t.join(\"\\n\");\n}\n\nexport function compressDiff(diff: string): string {\n\t// Tier 0 — Full diff\n\tif (diff.length <= MAX_DIFF_CHARS) {\n\t\treturn diff;\n\t}\n\n\t// Tier 1 — Strip context lines\n\tlet result = stripContextLines(diff);\n\tif (result.length <= MAX_DIFF_CHARS) {\n\t\treturn result;\n\t}\n\n\t// Tier 2 — Per-hunk line cap\n\tconst fileDiffs = result.split(/(?=diff --git)/).filter(Boolean);\n\tconst cappedFiles = fileDiffs.map((fd) => {\n\t\tconst parts = fd.split(/(?=\\n@@)/);\n\t\tconst cappedParts = parts.map((part, idx) => {\n\t\t\tif (idx === 0) return part; // Keep file header\n\t\t\tconst lines = part.split(\"\\n\");\n\t\t\tconst header = lines[0]; // @@ line\n\t\t\tconst changedLines = lines.slice(1).filter((l) => l.startsWith(\"+\") || l.startsWith(\"-\"));\n\t\t\tconst keptLines = changedLines.slice(0, 10);\n\t\t\treturn [header, ...keptLines].join(\"\\n\");\n\t\t});\n\t\treturn cappedParts.join(\"\");\n\t});\n\tresult = cappedFiles.join(\"\");\n\tif (result.length <= MAX_DIFF_CHARS) {\n\t\treturn result;\n\t}\n\n\t// Tier 3 — File summary\n\tconst fileMatches = diff.match(/^diff --git a\\/(.+) b\\/(.+)$/gm) || [];\n\tconst summary = fileMatches\n\t\t.map((f) => {\n\t\t\tconst match = f.match(/^diff --git a\\/(.+) b\\/(.+)$/);\n\t\t\treturn match && match[1] === match[2] ? `${match[1]} | changed` : \"\";\n\t\t})\n\t\t.filter(Boolean);\n\treturn `Summary of changes:\\n${summary.join(\"\\n\")}`;\n}\n\nexport function buildStatSummary(diff: string): string {\n\tconst files: { name: string; adds: number; dels: number }[] = [];\n\tlet currentFile = \"\";\n\tlet adds = 0;\n\tlet dels = 0;\n\n\tfor (const line of diff.split(\"\\n\")) {\n\t\tconst match = line.match(/^diff --git a\\/.+ b\\/(.+)$/);\n\t\tif (match) {\n\t\t\tif (currentFile) files.push({ name: currentFile, adds, dels });\n\t\t\tcurrentFile = match[1];\n\t\t\tadds = 0;\n\t\t\tdels = 0;\n\t\t} else if (line.startsWith(\"+\") && !line.startsWith(\"+++\")) {\n\t\t\tadds++;\n\t\t} else if (line.startsWith(\"-\") && !line.startsWith(\"---\")) {\n\t\t\tdels++;\n\t\t}\n\t}\n\tif (currentFile) files.push({ name: currentFile, adds, dels });\n\n\tconst totalAdds = files.reduce((s, f) => s + f.adds, 0);\n\tconst totalDels = files.reduce((s, f) => s + f.dels, 0);\n\n\tconst lines = files.map((f) => ` ${f.name} | +${f.adds} -${f.dels}`);\n\tlines.push(\n\t\t` ${files.length} files changed, ${totalAdds} insertions(+), ${totalDels} deletions(-)`,\n\t);\n\n\treturn lines.join(\"\\n\");\n}\n\nfunction buildSystemPrompt(type?: string): string {\n\tlet prompt =\n\t\t\"You are a commit message generator. Follow the Conventional Commits specification.\\n\" +\n\t\t\"Valid types: build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test.\\n\" +\n\t\t\"Format: type(scope): description\\n\" +\n\t\t\"Use imperative mood, lowercase, no trailing period.\\n\" +\n\t\t\"Output ONLY the commit message, no markdown fences, no explanation.\";\n\n\tif (type && type.trim().length > 0) {\n\t\tprompt += `\\nYou MUST use type: ${type}`;\n\t}\n\n\treturn prompt;\n}\n\nfunction buildUserPrompt(diff: string, hint?: string, statSummary?: string): string {\n\tconst parts: string[] = [];\n\tif (hint) parts.push(`Context: ${hint}`);\n\tif (statSummary) parts.push(`Change summary:\\n${statSummary}`);\n\tparts.push(`Generate a conventional commit for:\\n\\n${diff}`);\n\treturn parts.join(\"\\n\\n\");\n}\n\nfunction isValidConventionalCommit(message: string): boolean {\n\treturn CONVENTIONAL_COMMIT_REGEX.test(message);\n}\n\nexport function extractContentText(\n\tcontent: string | Array<{ type: string; text?: string }> | null | undefined,\n): string {\n\tif (content == null) return \"\";\n\tif (typeof content === \"string\") return content.trim();\n\tif (Array.isArray(content)) {\n\t\treturn content\n\t\t\t.filter((part) => part.type === \"text\" && typeof part.text === \"string\")\n\t\t\t.map((part) => stripThinkTags(part.text as string))\n\t\t\t.join(\"\")\n\t\t\t.trim();\n\t}\n\treturn \"\";\n}\n\n// biome-ignore lint/complexity/noExcessiveLinesPerFunction: AI pipeline — prompt build, call, validate, retry, error mapping\nexport async function generateCommitMessage(\n\tdiff: string,\n\toptions: {\n\t\tapiKey: string;\n\t\tmodel?: string;\n\t\ttype?: string;\n\t\ttimeout?: number;\n\t\thint?: string;\n\t\tprovider?: ProviderName;\n\t\tproxy?: string;\n\t},\n): Promise<string> {\n\tconst timeoutMs = options.timeout ?? 60000;\n\tdebug(\"Timeout: %d ms\", timeoutMs);\n\n\tconst { client, model } = createProvider({\n\t\tprovider: options.provider ?? \"groq\",\n\t\tapiKey: options.apiKey,\n\t\tmodelOverride: options.model,\n\t\ttimeout: timeoutMs,\n\t\tbaseURLOverride: options.proxy,\n\t});\n\n\tdebug(\n\t\t\"generateCommitMessage: model=%s, type=%s, hint=%s\",\n\t\tmodel,\n\t\toptions.type ?? \"none\",\n\t\toptions.hint ?? \"none\",\n\t);\n\n\tconst compressedDiff = compressDiff(diff);\n\tconst statSummary = buildStatSummary(diff);\n\tconst systemPrompt = buildSystemPrompt(options.type);\n\tconst userPrompt = buildUserPrompt(compressedDiff, options.hint, statSummary);\n\n\tdebug(\"Diff: %d chars → compressed to %d chars\", diff.length, compressedDiff.length);\n\tdebug(\"Stat summary:\\n%s\", statSummary);\n\tdebug(\"User prompt length: %d chars\", userPrompt.length);\n\n\t// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Error class instanceof chain for API error mapping\n\t// biome-ignore lint/complexity/noExcessiveLinesPerFunction: API call with streaming, error handling, and retry\n\tasync function callAI(strictSystemPrompt?: string): Promise<string> {\n\t\tconst callStart = Date.now();\n\t\tconst isRetry = !!strictSystemPrompt;\n\t\tdebug(\n\t\t\t\"callAI: %s — model=%s, promptLen=%d, systemLen=%d\",\n\t\t\tisRetry ? \"RETRY (strict)\" : \"INITIAL\",\n\t\t\tmodel,\n\t\t\tuserPrompt.length,\n\t\t\t(strictSystemPrompt ?? systemPrompt).length,\n\t\t);\n\t\ttry {\n\t\t\tconst isReasoningModel = /^(o[1-9]|.*gpt-oss.*|.*gpt-5.*)/i.test(model);\n\t\t\tconst completion = await client.chat.completions.create({\n\t\t\t\tmessages: [\n\t\t\t\t\t{ role: \"system\", content: strictSystemPrompt ?? systemPrompt },\n\t\t\t\t\t{ role: \"user\", content: userPrompt },\n\t\t\t\t],\n\t\t\t\tmodel,\n\t\t\t\ttemperature: 0.3,\n\t\t\t\t...(isReasoningModel ? { max_completion_tokens: 1024 } : { max_tokens: 1024 }),\n\t\t\t\treasoning_format: \"parsed\",\n\t\t\t});\n\n\t\t\tconst elapsed = Date.now() - callStart;\n\t\t\tconst rawContent = completion.choices[0]?.message?.content;\n\t\t\tconst processedContent =\n\t\t\t\ttypeof rawContent === \"string\" ? stripThinkTags(rawContent) : rawContent;\n\t\t\tconst content = extractContentText(processedContent);\n\t\t\tdebug(\n\t\t\t\t\"callAI response (%d ms): choices=%d, finishReason=%s, contentLen=%d, rawType=%s\",\n\t\t\t\telapsed,\n\t\t\t\tcompletion.choices.length,\n\t\t\t\tcompletion.choices[0]?.finish_reason ?? \"(none)\",\n\t\t\t\tcontent.length,\n\t\t\t\ttypeof rawContent,\n\t\t\t);\n\t\t\tdebug(\"callAI raw content: %s\", content.slice(0, 300) || \"(empty)\");\n\t\t\tif (!content) {\n\t\t\t\tconst reasoning = completion.choices[0]?.message?.reasoning;\n\t\t\t\tdebug(\n\t\t\t\t\t\"callAI: content empty, attempting reasoning fallback (reasoningLen=%d)\",\n\t\t\t\t\treasoning?.length ?? 0,\n\t\t\t\t);\n\t\t\t\tif (reasoning) {\n\t\t\t\t\tconst derived = deriveMessageFromReasoning(reasoning);\n\t\t\t\t\tif (derived) {\n\t\t\t\t\t\tdebug(\"callAI: derived message from reasoning: %s\", derived.slice(0, 100));\n\t\t\t\t\t\treturn stripThinkTags(derived);\n\t\t\t\t\t}\n\t\t\t\t\tdebug(\"callAI: could not derive message from reasoning\");\n\t\t\t\t}\n\t\t\t\tthrow new Error(\"AI returned an empty commit message\");\n\t\t\t}\n\t\t\treturn content;\n\t\t} catch (error) {\n\t\t\tconst elapsed = Date.now() - callStart;\n\t\t\tdebug(\n\t\t\t\t\"callAI FAILED after %d ms: %s\",\n\t\t\t\telapsed,\n\t\t\t\terror instanceof Error ? `${error.name}: ${error.message}` : String(error),\n\t\t\t);\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\ttry {\n\t\tconst totalStart = Date.now();\n\t\tlet message = await callAI();\n\t\tdebug(\n\t\t\t\"Validation: message=%s, isValid=%s\",\n\t\t\tmessage.slice(0, 100),\n\t\t\tisValidConventionalCommit(message),\n\t\t);\n\n\t\tif (!isValidConventionalCommit(message)) {\n\t\t\tdebug(\n\t\t\t\t\"Initial message failed conventional commit validation, retrying with strict prompt (elapsed: %d ms)\",\n\t\t\t\tDate.now() - totalStart,\n\t\t\t);\n\t\t\tconst retryMessage = await callAI(\n\t\t\t\t\"You MUST output ONLY a valid conventional commit message. \" +\n\t\t\t\t\t\"Format: type(scope): description. \" +\n\t\t\t\t\t\"If you output anything else your response will be rejected.\\n\" +\n\t\t\t\t\t\"Valid types: build, chore, ci, docs, feat, fix, perf, refactor, revert, style, test.\",\n\t\t\t);\n\t\t\tdebug(\n\t\t\t\t\"Retry validation: message=%s, isValid=%s\",\n\t\t\t\tretryMessage.slice(0, 100),\n\t\t\t\tisValidConventionalCommit(retryMessage),\n\t\t\t);\n\t\t\tif (isValidConventionalCommit(retryMessage)) {\n\t\t\t\tdebug(\"Retry produced valid conventional commit\");\n\t\t\t\tmessage = retryMessage;\n\t\t\t} else {\n\t\t\t\tdebug(\"Retry also failed validation, using original message\");\n\t\t\t}\n\t\t}\n\n\t\tdebug(\"Final message (%d ms total): %s\", Date.now() - totalStart, message);\n\t\treturn message;\n\t} catch (error) {\n\t\tdebug(\"AI error: %s\", error instanceof Error ? error.message : String(error));\n\t\tconst providerLabel = options.provider ? formatProviderName(options.provider) : undefined;\n\t\tthrow mapGroqError(error, providerLabel);\n\t}\n}\n","import { readFileSync } from \"node:fs\";\nimport { access, constants } from \"node:fs/promises\";\nimport { extname, join } from \"node:path\";\nimport { execa } from \"execa\";\nimport picomatch from \"picomatch\";\nimport { debug } from \"../utils/debug.js\";\nimport { extractToolName } from \"./hooks.js\";\n\n/** Config file names, checked in priority order (matches lint-staged naming conventions) */\nconst CONFIG_FILES = [\n\t\".cmintrc\",\n\t\".cmintrc.json\",\n\t\".cmintrc.mjs\",\n\t\".cmintrc.mts\",\n\t\".cmintrc.js\",\n\t\".cmintrc.ts\",\n\t\".cmintrc.cjs\",\n\t\".cmintrc.cts\",\n\t\"cmint.config.mjs\",\n\t\"cmint.config.mts\",\n\t\"cmint.config.js\",\n\t\"cmint.config.ts\",\n\t\"cmint.config.cjs\",\n\t\"cmint.config.cts\",\n] as const;\n\n/** Config shape from .cmintrc — glob keys map to command strings, string arrays, or functions */\nexport interface CheckConfig {\n\t[glob: string]: string | string[] | ((filenames: string[]) => string | string[]);\n}\n\n/** Result of a single check command execution */\nexport interface CheckResult {\n\tok: boolean;\n\ttool: string;\n\tcommand: string;\n\tstdout: string;\n\tstderr: string;\n\tfiles: string[];\n}\n\n/** Aggregate result from running all checks */\nexport interface CheckResults {\n\tok: boolean;\n\tresults: CheckResult[];\n}\n\n/**\n * Detect whether the repo has a cmint config file.\n * Returns the config file path, or null if none found.\n */\nexport async function detectConfig(repoRoot: string): Promise<string | null> {\n\tdebug(\"detectConfig: checking for config in %s\", repoRoot);\n\tfor (const name of CONFIG_FILES) {\n\t\ttry {\n\t\t\tawait access(join(repoRoot, name), constants.R_OK);\n\t\t\tdebug(\"detectConfig: found %s\", name);\n\t\t\treturn join(repoRoot, name);\n\t\t} catch {\n\t\t\t// try next config file name\n\t\t}\n\t}\n\tdebug(\"detectConfig: no config file found\");\n\treturn null;\n}\n\n/**\n * Load and validate the cmint config from a repo root.\n * Throws if the loaded value is missing or not a non-null object.\n */\nexport async function loadConfig(repoRoot: string): Promise<CheckConfig> {\n\tconst configPath = await detectConfig(repoRoot);\n\tif (!configPath) throw new Error(\"No cmint config file found\");\n\n\tdebug(\"loadConfig: loading %s\", configPath);\n\tconst ext = extname(configPath);\n\tconst isJSON = ext === \".json\";\n\tconst isTS = ext === \".ts\" || ext === \".mts\" || ext === \".cts\";\n\tconst isCJS = ext === \".cjs\";\n\tconst needsJiti = isTS || isCJS;\n\n\tlet config: unknown;\n\n\tif (isJSON) {\n\t\tconst raw = readFileSync(configPath, \"utf-8\");\n\t\tconfig = JSON.parse(raw);\n\t} else if (needsJiti) {\n\t\tconst { createJiti } = await import(\"jiti\");\n\t\tconst jiti = createJiti(import.meta.url, {});\n\t\tconst mod = await jiti.import(configPath);\n\t\tconfig = (mod as { default?: unknown }).default ?? mod;\n\t} else {\n\t\t// .js, .mjs, or no extension\n\t\tconst imported = (await import(configPath)) as { default?: unknown };\n\t\tconfig = imported.default;\n\t}\n\n\tif (!config || typeof config !== \"object\" || Array.isArray(config)) {\n\t\tthrow new Error(\"cmint config must export a non-null object with glob\\u2192command mappings\");\n\t}\n\tdebug(\n\t\t\"loadConfig: loaded %d glob patterns\",\n\t\tObject.keys(config as Record<string, unknown>).length,\n\t);\n\treturn config as CheckConfig;\n}\n\n/**\n * Run a shell command and capture its output.\n * Returns a CheckResult with ok=true on success (exit 0), ok=false on failure.\n * Handles ENOENT (command not found) and timeout errors gracefully.\n */\nexport async function runCommand(\n\tcommand: string,\n\ttimeout: number,\n\trepoRoot?: string,\n): Promise<CheckResult> {\n\tdebug(\"runCommand: %s (timeout: %dms)\", command, timeout);\n\tconst tool = extractToolName(command) ?? command.split(\" \")[0];\n\n\ttry {\n\t\tconst result = await execa(command, {\n\t\t\tshell: true,\n\t\t\treject: false,\n\t\t\ttimeout,\n\t\t\tall: true,\n\t\t\tpreferLocal: true,\n\t\t\t...(repoRoot ? { localDir: repoRoot } : {}),\n\t\t});\n\t\tconst ok = !result.failed;\n\t\tdebug(\"runCommand: %s \\u2014 ok=%s\", tool, ok);\n\t\treturn {\n\t\t\tok,\n\t\t\ttool: tool,\n\t\t\tcommand,\n\t\t\tstdout: result.stdout ?? \"\",\n\t\t\tstderr: result.stderr ?? \"\",\n\t\t\tfiles: [],\n\t\t};\n\t} catch (err) {\n\t\tconst msg = err instanceof Error ? err.message : String(err);\n\t\tconst isTimedOut = msg.toLowerCase().includes(\"timed out\");\n\t\tconst isNotFound =\n\t\t\tmsg.toLowerCase().includes(\"enoent\") || msg.toLowerCase().includes(\"not found\");\n\n\t\tdebug(\"runCommand: %s \\u2014 error: %s\", tool, msg);\n\t\treturn {\n\t\t\tok: false,\n\t\t\ttool: tool,\n\t\t\tcommand,\n\t\t\tstdout: \"\",\n\t\t\tstderr: isTimedOut\n\t\t\t\t? `Check timed out after ${timeout}ms`\n\t\t\t\t: isNotFound\n\t\t\t\t\t? `Command not found: ${tool}`\n\t\t\t\t\t: msg,\n\t\t\tfiles: [],\n\t\t};\n\t}\n}\n\n/**\n * Filter a list of file paths by a picomatch glob pattern.\n * When the pattern contains no `/`, files are matched at any depth (matchBase).\n * Dotfiles are included (dot: true).\n */\nexport function matchFiles(pattern: string, files: string[]): string[] {\n\tif (!pattern) return [];\n\tconst matchBase = !pattern.includes(\"/\");\n\tconst isMatch = picomatch(pattern, {\n\t\tdot: true,\n\t\tposixSlashes: true,\n\t\tstrictBrackets: true,\n\t});\n\treturn files.filter((f) => {\n\t\tconst parts = f.split(\"/\");\n\t\tconst target = matchBase ? parts[parts.length - 1] : f;\n\t\treturn isMatch(target);\n\t});\n}\n\n/**\n * Build a shell command string from a base command and a list of file paths.\n * File paths containing spaces are wrapped in double quotes.\n * If no files are provided, the base command is returned as-is.\n */\nexport function buildCommand(command: string, files: string[]): string {\n\tif (files.length === 0) return command;\n\tconst quotedFiles = files.map((f) => (f.includes(\" \") ? `\"${f}\"` : f));\n\treturn `${command} ${quotedFiles.join(\" \")}`;\n}\n\n/**\n * Resolve config commands for a glob entry into an array of command strings.\n * Function commands receive matched filenames; string commands are used as-is.\n */\nfunction resolveCommands(\n\tcommands: string | string[] | ((filenames: string[]) => string | string[]),\n\tmatchedFiles: string[],\n): string[] {\n\tconst isFunction = typeof commands === \"function\";\n\tif (isFunction) {\n\t\tconst resolved = (commands as (files: string[]) => string | string[])(matchedFiles);\n\t\treturn Array.isArray(resolved) ? resolved : [resolved];\n\t}\n\treturn Array.isArray(commands) ? commands : [commands as string];\n}\n\n/**\n * Run resolved commands for a single glob entry, appending results.\n * Returns false if any command fails (for fail-fast signaling).\n */\nasync function runCommandsForGlob(\n\tcmds: string[],\n\tisFunction: boolean,\n\tmatchedFiles: string[],\n\ttimeout: number,\n\tresults: CheckResult[],\n\trepoRoot: string,\n): Promise<boolean> {\n\tfor (const cmd of cmds) {\n\t\tconst fullCommand = isFunction ? cmd : buildCommand(cmd, matchedFiles);\n\t\tdebug(\"runCommandsForGlob: running '%s'\", fullCommand);\n\t\tconst result = await runCommand(fullCommand, timeout, repoRoot);\n\t\tresults.push({ ...result, files: matchedFiles });\n\t\tif (!result.ok) {\n\t\t\tdebug(\"runCommandsForGlob: check failed, stopping (fail-fast)\");\n\t\t\treturn false;\n\t\t}\n\t}\n\treturn true;\n}\n\n/**\n * Run all user-defined checks from .cmintrc against staged files.\n * Returns a no-op result when no config exists.\n * Fail-fast: stops on first error.\n */\nexport async function runAllChecks(\n\trepoRoot: string,\n\tstagedFiles: string[],\n\ttimeout: number,\n): Promise<CheckResults> {\n\tdebug(\"runAllChecks: %d staged files, checking for config in %s\", stagedFiles.length, repoRoot);\n\n\tconst configPath = await detectConfig(repoRoot);\n\tif (!configPath) {\n\t\tdebug(\"runAllChecks: no config found, skipping checks\");\n\t\treturn { ok: true, results: [] };\n\t}\n\n\tconst config = await loadConfig(repoRoot);\n\tdebug(\"runAllChecks: loaded config with %d patterns\", Object.keys(config).length);\n\n\tconst results: CheckResult[] = [];\n\n\tfor (const [glob, commands] of Object.entries(config)) {\n\t\tconst matchedFiles = matchFiles(glob, stagedFiles);\n\t\tconst isFunction = typeof commands === \"function\";\n\n\t\tif (matchedFiles.length === 0) {\n\t\t\tdebug(\"runAllChecks: no files matched pattern '%s'\", glob);\n\t\t\tcontinue;\n\t\t}\n\t\tdebug(\"runAllChecks: pattern '%s' matched %d files\", glob, matchedFiles.length);\n\n\t\tconst cmds = resolveCommands(commands, matchedFiles);\n\t\tconst ok = await runCommandsForGlob(cmds, isFunction, matchedFiles, timeout, results, repoRoot);\n\t\tif (!ok) return { ok: false, results };\n\t}\n\n\tconst ok = results.every((r) => r.ok);\n\tdebug(\"runAllChecks: complete \\u2014 ok=%s, %d results\", ok, results.length);\n\treturn { ok, results };\n}\n","import { debug } from \"../utils/debug.js\";\nimport { mapGroqError } from \"./ai.js\";\nimport type { ChangedFile } from \"./git.js\";\nimport { getDefaultExcludes } from \"./git.js\";\nimport { createProvider, formatProviderName, type ProviderName } from \"./provider.js\";\n\nexport interface CommitGroup {\n\tname: string;\n\tdescription: string;\n\tfiles: string[];\n}\n\nexport interface GroupingResult {\n\tgroups: CommitGroup[];\n\texcluded: string[];\n}\n\nfunction matchesExcludePattern(filePath: string, pattern: string): boolean {\n\tif (pattern === filePath) return true;\n\tif (pattern.endsWith(\"/**\")) {\n\t\tconst prefix = pattern.slice(0, -3);\n\t\treturn filePath === prefix || filePath.startsWith(`${prefix}/`);\n\t}\n\tif (pattern.startsWith(\"*.\")) {\n\t\tconst suffix = pattern.slice(1);\n\t\treturn filePath.endsWith(suffix);\n\t}\n\treturn false;\n}\n\n/** Lockfiles that should be kept when their companion manifest is present */\nconst LOCKFILE_COMPANIONS: Record<string, string> = {\n\t\"package-lock.json\": \"package.json\",\n\t\"pnpm-lock.yaml\": \"package.json\",\n\t\"yarn.lock\": \"package.json\",\n\t\"bun.lock\": \"package.json\",\n\t\"bun.lockb\": \"package.json\",\n};\n\nexport function filterExcludedFiles(files: ChangedFile[]): {\n\tincluded: ChangedFile[];\n\texcluded: string[];\n} {\n\tconst patterns = getDefaultExcludes();\n\tconst included: ChangedFile[] = [];\n\tconst excluded: ChangedFile[] = [];\n\tconst filePaths = new Set(files.map((f) => f.path));\n\n\tfor (const file of files) {\n\t\tconst isExcluded = patterns.some((pattern) => matchesExcludePattern(file.path, pattern));\n\t\tif (isExcluded) {\n\t\t\texcluded.push(file);\n\t\t} else {\n\t\t\tincluded.push(file);\n\t\t}\n\t}\n\n\t// Promote lockfiles whose companion manifest is present\n\tconst stillExcluded: string[] = [];\n\tfor (const file of excluded) {\n\t\tconst companion = LOCKFILE_COMPANIONS[file.path];\n\t\tif (companion && filePaths.has(companion)) {\n\t\t\tincluded.push(file);\n\t\t} else {\n\t\t\tstillExcluded.push(file.path);\n\t\t}\n\t}\n\n\tdebug(\"filterExcludedFiles: %d included, %d excluded\", included.length, stillExcluded.length);\n\treturn { included, excluded: stillExcluded };\n}\n\nfunction statusIndicator(status: string): string {\n\tswitch (status) {\n\t\tcase \"M\":\n\t\t\treturn \"modified\";\n\t\tcase \"A\":\n\t\t\treturn \"added\";\n\t\tcase \"D\":\n\t\t\treturn \"deleted\";\n\t\tcase \"R\":\n\t\t\treturn \"renamed\";\n\t\tcase \"C\":\n\t\t\treturn \"copied\";\n\t\tcase \"?\":\n\t\tcase \"??\":\n\t\t\treturn \"untracked\";\n\t\tdefault:\n\t\t\treturn \"changed\";\n\t}\n}\n\nexport function buildFileSummary(files: ChangedFile[]): string {\n\treturn files.map((f) => `${f.path} (${statusIndicator(f.status)})`).join(\"\\n\");\n}\n\nexport function buildGroupingSystemPrompt(): string {\n\treturn [\n\t\t\"You are analyzing changed files in a git repository. Group them into logical commits based on what changed and why. Each group should be a coherent unit of work.\",\n\t\t\"\",\n\t\t\"Rules:\",\n\t\t\"- Group by feature, fix, or concern (e.g., 'Frontend refactor', 'API changes', 'Test updates')\",\n\t\t\"- Keep related files together (e.g., a component + its test, a model + its migration)\",\n\t\t\"- Separate documentation changes (*.md files, docs/) from code changes — put docs in their own group\",\n\t\t\"- Do not split a single logical change across multiple groups\",\n\t\t\"- If a file does not clearly belong to any group, include it anyway — do not omit files\",\n\t\t\"\",\n\t\t\"Output format: JSON array of objects with keys 'name', 'description', 'files'.\",\n\t\t\"name: short label (3-5 words)\",\n\t\t\"description: 1-2 sentences explaining what this group changes\",\n\t\t\"files: array of exact file paths from the input\",\n\t\t\"\",\n\t\t\"Output ONLY valid JSON. No markdown fences, no explanation.\",\n\t].join(\"\\n\");\n}\n\nfunction buildGroupingUserPrompt(summary: string): string {\n\treturn [\"Group the following changed files into logical commits:\", \"\", summary].join(\"\\n\");\n}\n\nfunction parseGroupingResponse(content: string): CommitGroup[] {\n\tconst jsonText = content\n\t\t.replace(/^```json\\s*/, \"\")\n\t\t.replace(/\\s*```$/, \"\")\n\t\t.trim();\n\tconst parsed = JSON.parse(jsonText) as unknown;\n\n\tif (!Array.isArray(parsed)) {\n\t\tthrow new Error(\"AI response was not a JSON array\");\n\t}\n\n\tconst rawGroups: CommitGroup[] = [];\n\tfor (const item of parsed) {\n\t\tif (\n\t\t\ttypeof item === \"object\" &&\n\t\t\titem !== null &&\n\t\t\t\"name\" in item &&\n\t\t\t\"description\" in item &&\n\t\t\t\"files\" in item &&\n\t\t\tArray.isArray(item.files)\n\t\t) {\n\t\t\trawGroups.push({\n\t\t\t\tname: String(item.name),\n\t\t\t\tdescription: String(item.description),\n\t\t\t\tfiles: item.files.filter((f: unknown) => typeof f === \"string\") as string[],\n\t\t\t});\n\t\t}\n\t}\n\n\treturn rawGroups;\n}\n\n// biome-ignore lint/complexity/noExcessiveLinesPerFunction: Multi-step generation flow\nexport async function generateGroups(\n\tfiles: ChangedFile[],\n\tapiKey: string,\n\tmodel?: string,\n\ttimeout?: number,\n\tprovider?: ProviderName,\n\tproxy?: string,\n): Promise<GroupingResult> {\n\tdebug(\"generateGroups: %d files, model=%s\", files.length, model ?? \"default\");\n\n\tconst { included, excluded } = filterExcludedFiles(files);\n\n\tif (included.length === 0) {\n\t\tdebug(\"generateGroups: no files to group after exclusion\");\n\t\treturn { groups: [], excluded };\n\t}\n\n\tconst summary = buildFileSummary(included);\n\tconst systemPrompt = buildGroupingSystemPrompt();\n\tconst userPrompt = buildGroupingUserPrompt(summary);\n\n\tdebug(\"File summary:\\n%s\", summary);\n\tdebug(\"User prompt length: %d chars\", userPrompt.length);\n\n\tconst timeoutMs = timeout ?? 60000;\n\tconst { client, model: resolvedModel } = createProvider({\n\t\tprovider: provider ?? \"groq\",\n\t\tapiKey,\n\t\tmodelOverride: model,\n\t\ttimeout: timeoutMs,\n\t\tbaseURLOverride: proxy,\n\t});\n\n\ttry {\n\t\tconst completion = await client.chat.completions.create({\n\t\t\tmessages: [\n\t\t\t\t{ role: \"system\", content: systemPrompt },\n\t\t\t\t{ role: \"user\", content: userPrompt },\n\t\t\t],\n\t\t\tmodel: resolvedModel,\n\t\t\ttemperature: 0.3,\n\t\t\tmax_tokens: 2048,\n\t\t});\n\n\t\tconst rawContent = completion.choices[0]?.message?.content;\n\t\tconst content = typeof rawContent === \"string\" ? rawContent.trim() : \"\";\n\n\t\tdebug(\n\t\t\t\"generateGroups response: choices=%d, finishReason=%s, contentLen=%d\",\n\t\t\tcompletion.choices.length,\n\t\t\tcompletion.choices[0]?.finish_reason ?? \"(none)\",\n\t\t\tcontent.length,\n\t\t);\n\t\tdebug(\"generateGroups raw content: %s\", content.slice(0, 500) || \"(empty)\");\n\n\t\tif (!content) {\n\t\t\tthrow new Error(\"AI returned an empty grouping response\");\n\t\t}\n\n\t\tconst rawGroups = parseGroupingResponse(content);\n\n\t\tdebug(\"generateGroups: parsed %d raw groups\", rawGroups.length);\n\t\tconst validated = validateGroups(rawGroups, included);\n\t\tdebug(\"generateGroups: %d validated groups\", validated.length);\n\n\t\treturn { groups: validated, excluded };\n\t} catch (error) {\n\t\tdebug(\"generateGroups error: %s\", error instanceof Error ? error.message : String(error));\n\t\tconst providerLabel = provider ? formatProviderName(provider) : undefined;\n\t\tthrow mapGroqError(error, providerLabel);\n\t}\n}\n\nexport function validateGroups(groups: CommitGroup[], allFiles: ChangedFile[]): CommitGroup[] {\n\tconst seen = new Set<string>();\n\tconst validated: CommitGroup[] = [];\n\n\tfor (const group of groups) {\n\t\tconst uniqueFiles = group.files.filter((f) => {\n\t\t\tif (seen.has(f)) return false;\n\t\t\tseen.add(f);\n\t\t\treturn true;\n\t\t});\n\n\t\tif (uniqueFiles.length > 0) {\n\t\t\tvalidated.push({\n\t\t\t\tname: group.name,\n\t\t\t\tdescription: group.description,\n\t\t\t\tfiles: uniqueFiles,\n\t\t\t});\n\t\t}\n\t}\n\n\t// Find files not in any group\n\tconst ungrouped = allFiles.filter((f) => !seen.has(f.path));\n\n\tif (ungrouped.length > 0) {\n\t\tdebug(\"validateGroups: %d ungrouped files added to 'Other changes'\", ungrouped.length);\n\t\tvalidated.push({\n\t\t\tname: \"Other changes\",\n\t\t\tdescription: \"Miscellaneous changes that did not fit into other groups\",\n\t\t\tfiles: ungrouped.map((f) => f.path),\n\t\t});\n\t}\n\n\treturn validated;\n}\n","import * as p from \"@clack/prompts\";\nimport { bold, cyan, dim, green, red, yellow } from \"kolorist\";\nimport type { ChangedFile } from \"../services/git.js\";\nimport type { CommitGroup } from \"../services/grouping.js\";\nimport { debug } from \"../utils/debug.js\";\n\nexport async function showGroupingConfirmation(\n\tgroups: CommitGroup[],\n\texcluded: string[],\n): Promise<boolean> {\n\tdebug(\"showGroupingConfirmation: %d groups, %d excluded\", groups.length, excluded.length);\n\n\tconst lines: string[] = [];\n\n\tfor (const group of groups) {\n\t\tlines.push(bold(group.name));\n\t\tlines.push(` ${dim(group.description)}`);\n\t\tlines.push(` ${green(String(group.files.length))} file${group.files.length !== 1 ? \"s\" : \"\"}`);\n\t\tfor (const file of group.files) {\n\t\t\tlines.push(` ${dim(\"•\")} ${file}`);\n\t\t}\n\t\tlines.push(\"\");\n\t}\n\n\tif (excluded.length > 0) {\n\t\tlines.push(dim(`Excluded: ${excluded.length} file${excluded.length !== 1 ? \"s\" : \"\"}`));\n\t\tfor (const file of excluded) {\n\t\t\tlines.push(` ${dim(\"•\")} ${dim(file)}`);\n\t\t}\n\t}\n\n\tp.note(lines.join(\"\\n\"), \"Proposed commit groups\");\n\n\tconst choice = await p.select({\n\t\tmessage: \"Proceed with these groupings?\",\n\t\toptions: [\n\t\t\t{ label: \"Yes, commit all groups\", value: \"yes\" },\n\t\t\t{ label: \"No, cancel\", value: \"no\" },\n\t\t],\n\t});\n\n\tif (p.isCancel(choice) || choice === \"no\") {\n\t\tdebug(\"showGroupingConfirmation: user cancelled\");\n\t\treturn false;\n\t}\n\n\tdebug(\"showGroupingConfirmation: user confirmed\");\n\treturn true;\n}\n\nexport function showGroupProgress(current: number, total: number, groupName: string): void {\n\tp.log.info(`Commit group ${current} of ${total}: ${cyan(`\"${groupName}\"`)}`);\n}\n\nconst statusLabel = (status: string): string => {\n\tswitch (status) {\n\t\tcase \"M\":\n\t\t\treturn yellow(\"M\");\n\t\tcase \"A\":\n\t\t\treturn green(\"A\");\n\t\tcase \"D\":\n\t\t\treturn red(\"D\");\n\t\tcase \"?\":\n\t\tcase \"??\":\n\t\t\treturn cyan(\"?\");\n\t\tdefault:\n\t\t\treturn dim(status);\n\t}\n};\n\n/** Display a table of changed files with status indicators */\nexport function showChangedFilesTable(files: ChangedFile[]): void {\n\tif (files.length === 0) return;\n\n\tconst lines = files.map((f) => ` ${statusLabel(f.status)} ${f.path}`);\n\tp.note(lines.join(\"\\n\"), `${files.length} file${files.length !== 1 ? \"s\" : \"\"} changed`);\n}\n\n/** Display a compact grouping summary (only shown when >1 group) */\nexport function showGroupingSummary(groups: CommitGroup[]): void {\n\tif (groups.length <= 1) return;\n\n\tconst lines = groups.map(\n\t\t(g) => `${bold(g.name)} ${dim(\"—\")} ${g.files.length} file${g.files.length !== 1 ? \"s\" : \"\"}`,\n\t);\n\tp.note(lines.join(\"\\n\"), \"Commit groups\");\n}\n\n/** Display combined view: files with status indicators grouped by commit group */\nexport function showGroupedFiles(groups: CommitGroup[], changedFiles: ChangedFile[]): void {\n\tconst statusMap = new Map(changedFiles.map((f) => [f.path, f.status]));\n\n\tconst lines: string[] = [];\n\n\tfor (let i = 0; i < groups.length; i++) {\n\t\tconst group = groups[i];\n\t\tlines.push(\n\t\t\t`${bold(group.name)} ${dim(\"—\")} ${group.files.length} file${group.files.length !== 1 ? \"s\" : \"\"}`,\n\t\t);\n\t\tfor (const file of group.files) {\n\t\t\tconst status = statusMap.get(file) ?? \"M\";\n\t\t\tlines.push(` ${statusLabel(status)} ${file}`);\n\t\t}\n\t\tif (i < groups.length - 1) {\n\t\t\tlines.push(\"\");\n\t\t}\n\t}\n\n\tp.note(lines.join(\"\\n\"), \"Commit groups\");\n}\n","import { spawn } from \"node:child_process\";\n\nexport async function copyToClipboard(content: string): Promise<boolean> {\n\tconst commands: [string, string[]][] = [\n\t\t[\"wl-copy\", []],\n\t\t[\"xclip\", [\"-selection\", \"clipboard\"]],\n\t\t[\"xsel\", [\"--clipboard\", \"--input\"]],\n\t\t[\"pbcopy\", []],\n\t];\n\n\tfor (const [cmd, args] of commands) {\n\t\ttry {\n\t\t\tconst success = await new Promise<boolean>((resolve) => {\n\t\t\t\tconst child = spawn(cmd, args, {\n\t\t\t\t\tstdio: [\"pipe\", \"ignore\", \"ignore\"],\n\t\t\t\t});\n\n\t\t\t\tlet settled = false;\n\t\t\t\tconst done = (result: boolean) => {\n\t\t\t\t\tif (settled) return;\n\t\t\t\t\tsettled = true;\n\t\t\t\t\tresolve(result);\n\t\t\t\t};\n\n\t\t\t\t// Command not found (ENOENT)\n\t\t\t\tchild.on(\"error\", () => done(false));\n\t\t\t\t// Tool failed immediately (e.g. wl-copy on non-Wayland)\n\t\t\t\tchild.on(\"exit\", (code) => {\n\t\t\t\t\tif (code !== 0) done(false);\n\t\t\t\t});\n\n\t\t\t\tchild.stdin.write(content, (err) => {\n\t\t\t\t\tif (err) {\n\t\t\t\t\t\tdone(false);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tchild.stdin.end(() => {\n\t\t\t\t\t\t// Content sent to tool — don't wait for exit since\n\t\t\t\t\t\t// clipboard tools (xclip, wl-copy) hold selection open\n\t\t\t\t\t\tchild.unref();\n\t\t\t\t\t\tdone(true);\n\t\t\t\t\t});\n\t\t\t\t});\n\t\t\t});\n\n\t\t\tif (success) return true;\n\t\t} catch {}\n\t}\n\treturn false;\n}\n","import * as p from \"@clack/prompts\";\nimport { bold, cyan, dim, green, red, yellow } from \"kolorist\";\nimport { copyToClipboard } from \"../services/clipboard.js\";\nimport type { ChangedFile } from \"../services/git.js\";\nimport type { HookError } from \"../services/hooks.js\";\nimport { debug } from \"../utils/debug.js\";\n\nexport type RecoveryResult = \"committed\" | \"cancelled\" | \"failed\";\n\nexport interface StagingChoice {\n\tfiles: string[]; // selected file paths to stage\n\tall: boolean; // whether user chose \"Stage all\"\n}\n\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Staging menu with conditional options + multiselect fallback\n// biome-ignore lint/complexity/noExcessiveLinesPerFunction: Staging menu with file list display + multiselect fallback\nexport async function showStagingMenu(\n\tfiles: ChangedFile[],\n\thasChecks: boolean,\n): Promise<StagingChoice | \"autogroup\" | \"checks\" | \"staged\" | null> {\n\tdebug(\"showStagingMenu: %d files\", files.length);\n\n\t// Build status labels with kolorist colors\n\tconst statusLabel = (status: string): string => {\n\t\tswitch (status) {\n\t\t\tcase \"M\":\n\t\t\t\treturn yellow(\"M\");\n\t\t\tcase \"A\":\n\t\t\t\treturn green(\"A\");\n\t\t\tcase \"D\":\n\t\t\t\treturn red(\"D\");\n\t\t\tcase \"?\":\n\t\t\tcase \"??\":\n\t\t\t\treturn cyan(\"?\");\n\t\t\tdefault:\n\t\t\t\treturn dim(status);\n\t\t}\n\t};\n\n\t// Sort: staged files first, then unstaged\n\tconst sorted = [...files].sort((a, b) => {\n\t\tif (a.staged !== b.staged) return a.staged ? -1 : 1;\n\t\treturn a.path.localeCompare(b.path);\n\t});\n\n\t// Show file list grouped by staged status\n\tconst stagedFiles = sorted.filter((f) => f.staged);\n\tconst unstagedFiles = sorted.filter((f) => !f.staged);\n\tconst lines: string[] = [];\n\tif (stagedFiles.length > 0) {\n\t\tlines.push(\n\t\t\tgreen(bold(\"Staged:\")),\n\t\t\t...stagedFiles.map((f) => ` ${statusLabel(f.status)} ${f.path}`),\n\t\t);\n\t}\n\tif (unstagedFiles.length > 0) {\n\t\tif (lines.length > 0) lines.push(\"\");\n\t\tlines.push(\n\t\t\tyellow(bold(\"Changed:\")),\n\t\t\t...unstagedFiles.map((f) => ` ${statusLabel(f.status)} ${f.path}`),\n\t\t);\n\t}\n\tp.note(lines.join(\"\\n\"), `${files.length} file${files.length !== 1 ? \"s\" : \"\"}`);\n\n\tconst choice = await p.select({\n\t\tmessage: \"Stage files for commit:\",\n\t\toptions: [\n\t\t\t{\n\t\t\t\tlabel: \"Auto-group into commits\",\n\t\t\t\tvalue: \"autogroup\",\n\t\t\t\thint: \"LLM groups files into logical commits\",\n\t\t\t},\n\t\t\t...(stagedFiles.length > 0\n\t\t\t\t? [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlabel: \"Commit staged files only\",\n\t\t\t\t\t\t\tvalue: \"staged\" as const,\n\t\t\t\t\t\t\thint: `${stagedFiles.length} file${stagedFiles.length !== 1 ? \"s\" : \"\"} already staged`,\n\t\t\t\t\t\t},\n\t\t\t\t\t]\n\t\t\t\t: []),\n\t\t\t{\n\t\t\t\tlabel: \"Stage all files\",\n\t\t\t\tvalue: \"all\",\n\t\t\t\thint: `${files.length} file${files.length !== 1 ? \"s\" : \"\"}`,\n\t\t\t},\n\t\t\t...(hasChecks\n\t\t\t\t? [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tlabel: \"Run checks\",\n\t\t\t\t\t\t\tvalue: \"checks\" as const,\n\t\t\t\t\t\t\thint: \"Pre-flight checks from cmint config\",\n\t\t\t\t\t\t},\n\t\t\t\t\t]\n\t\t\t\t: []),\n\t\t\t{ label: \"Select files...\", value: \"select\" },\n\t\t\t{ label: \"Cancel\", value: \"cancel\" },\n\t\t],\n\t});\n\n\tif (p.isCancel(choice) || choice === \"cancel\") {\n\t\treturn null;\n\t}\n\n\tif (choice === \"autogroup\") {\n\t\treturn \"autogroup\";\n\t}\n\n\tif (choice === \"checks\") {\n\t\treturn \"checks\";\n\t}\n\n\tif (choice === \"staged\") {\n\t\treturn \"staged\";\n\t}\n\n\tif (choice === \"all\") {\n\t\treturn { files: files.map((f) => f.path), all: true };\n\t}\n\n\t// Multi-select\n\tconst selected = await p.multiselect({\n\t\tmessage: \"Select files to stage:\",\n\t\toptions: sorted.map((f) => ({\n\t\t\tlabel: `${statusLabel(f.status)} ${f.path}`,\n\t\t\tvalue: f.path,\n\t\t})),\n\t\trequired: true,\n\t});\n\n\tif (p.isCancel(selected)) {\n\t\treturn null;\n\t}\n\n\treturn { files: selected as string[], all: false };\n}\n\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Recovery menu with recursive retry path\n// biome-ignore lint/complexity/noExcessiveLinesPerFunction: Interactive TUI — format errors, handle 5 menu actions, recursive retry\nexport async function showRecoveryMenu(\n\terrors: HookError[],\n\tonRetry: () => Promise<boolean>,\n\tonSkipHooks: (message: string) => Promise<boolean>,\n\tonRestage: () => Promise<boolean>,\n\tmessage: string,\n\trawStderr: string,\n): Promise<RecoveryResult> {\n\tdebug(\"showRecoveryMenu: %d errors\", errors.length);\n\n\tlet clipboardCopied = false;\n\tlet showNote = true;\n\n\twhile (true) {\n\t\tif (showNote) {\n\t\t\tp.note(\n\t\t\t\terrors.map((e) => ` ${red(\"•\")} [${e.tool}] ${e.message}`).join(\"\\n\"),\n\t\t\t\tred(bold(\"Pre-commit hook failed\")),\n\t\t\t);\n\t\t\tshowNote = false;\n\t\t}\n\n\t\tconst choice = await p.select({\n\t\t\tmessage: \"What do you want to do?\",\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tlabel: clipboardCopied\n\t\t\t\t\t\t? `${green(\"✓\")} Copy error report to clipboard`\n\t\t\t\t\t\t: \"Copy error report to clipboard\",\n\t\t\t\t\tvalue: \"clipboard\",\n\t\t\t\t\thint: clipboardCopied ? \"Copied!\" : \"Paste into another terminal for an AI agent\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: \"View full error output\",\n\t\t\t\t\tvalue: \"view\",\n\t\t\t\t\thint: \"Show the raw stderr from hooks\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: \"Skip hooks and commit (--no-verify)\",\n\t\t\t\t\tvalue: \"skip\",\n\t\t\t\t\thint: \"Commit anyway, fix later\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: \"Re-stage files and retry\",\n\t\t\t\t\tvalue: \"restage\",\n\t\t\t\t\thint: \"Pick up fixes from another terminal\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: \"Edit commit message\",\n\t\t\t\t\tvalue: \"edit\",\n\t\t\t\t\thint: \"Modify the message before retrying\",\n\t\t\t\t},\n\t\t\t\t{ label: \"Cancel\", value: \"cancel\" },\n\t\t\t],\n\t\t});\n\n\t\tif (p.isCancel(choice)) {\n\t\t\tdebug(\"showRecoveryMenu: user cancelled\");\n\t\t\tp.outro(yellow(\"Cancelled. Message cached for --retry.\"));\n\t\t\treturn \"cancelled\";\n\t\t}\n\n\t\tdebug(\"showRecoveryMenu: user chose %s\", choice);\n\n\t\tswitch (choice) {\n\t\t\tcase \"clipboard\": {\n\t\t\t\tconst ok = await copyToClipboard(rawStderr);\n\t\t\t\tif (ok) {\n\t\t\t\t\tclipboardCopied = true;\n\t\t\t\t\tp.log.step(green(\"Copied to clipboard.\"));\n\t\t\t\t} else {\n\t\t\t\t\tp.log.warn(red(\"No clipboard tool found. Install xclip, wl-copy, or xsel.\"));\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcase \"view\": {\n\t\t\t\tp.note(rawStderr.trim() || \"(no raw output)\", \"Full error output\");\n\t\t\t\tshowNote = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcase \"skip\": {\n\t\t\t\tp.log.info(yellow(\"Committing with --no-verify...\"));\n\t\t\t\tconst ok = await onSkipHooks(message);\n\t\t\t\tif (ok) {\n\t\t\t\t\tp.outro(green(\"Committed (hooks skipped).\"));\n\t\t\t\t\treturn \"committed\";\n\t\t\t\t} else {\n\t\t\t\t\tp.outro(red(\"Commit failed even with --no-verify.\"));\n\t\t\t\t\treturn \"failed\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tcase \"restage\": {\n\t\t\t\tp.log.info(cyan(\"Re-staging and retrying...\"));\n\t\t\t\tconst ok = await onRestage();\n\t\t\t\tif (ok) {\n\t\t\t\t\tp.outro(green(\"Committed successfully.\"));\n\t\t\t\t\treturn \"committed\";\n\t\t\t\t}\n\t\t\t\t// Re-show errors after failed restage for context\n\t\t\t\tshowNote = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcase \"edit\": {\n\t\t\t\tconst edited = await p.text({\n\t\t\t\t\tmessage: \"Edit commit message:\",\n\t\t\t\t\tinitialValue: message,\n\t\t\t\t\tvalidate: (v) => (v?.trim() ? undefined : \"Message cannot be empty\"),\n\t\t\t\t});\n\t\t\t\tif (p.isCancel(edited)) {\n\t\t\t\t\tp.outro(yellow(\"Cancelled. Message cached for --retry.\"));\n\t\t\t\t\treturn \"cancelled\";\n\t\t\t\t}\n\t\t\t\tconst ok = await onRetry();\n\t\t\t\tif (ok) {\n\t\t\t\t\tp.outro(green(\"Committed successfully.\"));\n\t\t\t\t\treturn \"committed\";\n\t\t\t\t} else {\n\t\t\t\t\tp.outro(red(\"Commit failed again.\"));\n\t\t\t\t\treturn \"failed\";\n\t\t\t\t}\n\t\t\t}\n\t\t\tcase \"cancel\": {\n\t\t\t\tp.outro(dim(\"Message cached for --retry.\"));\n\t\t\t\treturn \"cancelled\";\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport async function showCheckFailureMenu(\n\terrors: HookError[],\n\trawStderr: string,\n): Promise<\"skipped\" | \"cancelled\"> {\n\tdebug(\"showCheckFailureMenu: %d errors\", errors.length);\n\n\tlet clipboardCopied = false;\n\n\tp.note(\n\t\terrors.map((e) => ` ${red(\"•\")} [${e.tool}] ${e.message}`).join(\"\\n\"),\n\t\tred(\"Pre-commit check failed\"),\n\t);\n\n\twhile (true) {\n\t\tconst choice = await p.select({\n\t\t\tmessage: \"What do you want to do?\",\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tlabel: clipboardCopied\n\t\t\t\t\t\t? `${green(\"✓\")} Copy error report to clipboard`\n\t\t\t\t\t\t: \"Copy error report to clipboard\",\n\t\t\t\t\tvalue: \"copy\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: \"View full error output\",\n\t\t\t\t\tvalue: \"view\",\n\t\t\t\t\thint: \"Show the raw stderr from checks\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: \"Skip checks and commit\",\n\t\t\t\t\tvalue: \"skip\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: \"Cancel\",\n\t\t\t\t\tvalue: \"cancel\",\n\t\t\t\t},\n\t\t\t],\n\t\t});\n\n\t\tif (p.isCancel(choice)) {\n\t\t\tdebug(\"showCheckFailureMenu: user cancelled\");\n\t\t\treturn \"cancelled\";\n\t\t}\n\n\t\tdebug(\"showCheckFailureMenu: user chose %s\", choice);\n\n\t\tswitch (choice) {\n\t\t\tcase \"copy\": {\n\t\t\t\tconst ok = await copyToClipboard(rawStderr);\n\t\t\t\tif (ok) {\n\t\t\t\t\tclipboardCopied = true;\n\t\t\t\t\tp.log.step(green(\"Copied to clipboard.\"));\n\t\t\t\t} else {\n\t\t\t\t\tp.log.warn(red(\"No clipboard tool found. Install xclip, wl-copy, or xsel.\"));\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcase \"view\": {\n\t\t\t\tp.note(rawStderr.trim() || \"(no raw output)\", \"Full error output\");\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcase \"skip\": {\n\t\t\t\tp.log.info(\"Skipping checks and proceeding with commit...\");\n\t\t\t\treturn \"skipped\";\n\t\t\t}\n\t\t\tcase \"cancel\": {\n\t\t\t\tp.outro(dim(\"Cancelled.\"));\n\t\t\t\treturn \"cancelled\";\n\t\t\t}\n\t\t}\n\t}\n}\n","import { isCancel, log, outro, spinner } from \"@clack/prompts\";\nimport { dim, green, red } from \"kolorist\";\nimport { generateCommitMessage } from \"../services/ai.js\";\nimport { runAllChecks } from \"../services/checks.js\";\nimport {\n\tgetModelForProvider,\n\tgetProviderApiKey,\n\treadConfig,\n\tsetConfigValue,\n} from \"../services/config.js\";\nimport {\n\tattemptCommit,\n\tattemptCommitNoVerify,\n\ttype ChangedFile,\n\tgetDefaultExcludes,\n\tgetHead,\n\tgetStagedDiff,\n\tresetStaging,\n\tstageFiles,\n} from \"../services/git.js\";\nimport { filterExcludedFiles, generateGroups, validateGroups } from \"../services/grouping.js\";\nimport { createProgressHandler } from \"../services/hook-progress.js\";\nimport { parseHookErrors, parseToolChecks } from \"../services/hooks.js\";\nimport {\n\tformatProviderName,\n\tisValidProvider,\n\tPROVIDER_CONFIGS,\n\tPROVIDER_ENV_KEYS,\n\ttype ProviderName,\n} from \"../services/provider.js\";\nimport { showGroupedFiles, showGroupingConfirmation, showGroupProgress } from \"../ui/grouping.js\";\nimport { type RecoveryResult, showCheckFailureMenu, showRecoveryMenu } from \"../ui/menu.js\";\nimport { reviewCommitMessage } from \"../ui/review-message.js\";\nimport { saveCachedCommit } from \"../utils/cache.js\";\nimport { debug } from \"../utils/debug.js\";\n\nexport interface CommitFlags {\n\tretry: boolean;\n\tauto: boolean;\n\tmessage?: string;\n\thint?: string;\n\tnoCheck?: boolean;\n}\n\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Multi-step auto-group flow with sequential commits, review, and recovery\n// biome-ignore lint/complexity/noExcessiveLinesPerFunction: Sequential multi-commit loop with review, cache, and recovery\nexport async function runAutoGroupFlow(\n\tchangedFiles: ChangedFile[],\n\tflags: CommitFlags,\n): Promise<RecoveryResult> {\n\t// Step 1: Filter excluded files\n\tconst { included, excluded } = filterExcludedFiles(changedFiles);\n\n\t// Step 1b: Commit excluded files with hardcoded message before grouping\n\tif (excluded.length > 0) {\n\t\tdebug(\"Committing %d excluded files upfront:\", excluded.length, excluded);\n\t\tconst message = buildExcludedFilesMessage(excluded);\n\t\tawait resetStaging();\n\t\tawait stageFiles(excluded);\n\n\t\tconst headBefore = await getHead();\n\t\tconst commitResult = await attemptCommit(message);\n\t\tconst headAfter = await getHead();\n\n\t\tif (commitResult.ok || headBefore !== headAfter) {\n\t\t\tdebug(\"Excluded files committed:\", message);\n\t\t} else {\n\t\t\tdebug(\"Excluded files commit failed, continuing without them\");\n\t\t}\n\t}\n\n\t// If only excluded files existed, we're done\n\tif (included.length === 0) {\n\t\tdebug(\"No included files to group, done\");\n\t\toutro(green(\"Done.\"));\n\t\treturn \"committed\";\n\t}\n\n\t// Run user-defined pre-commit checks upfront on all files (before AI grouping)\n\tif (!flags.noCheck) {\n\t\tconst { getRepoRoot } = await import(\"../services/git.js\");\n\t\tconst repoRoot = await getRepoRoot();\n\t\tconst allFiles = included.filter((f) => f.status !== \"D\").map((f) => f.path);\n\t\tdebug(\"Running user checks on %d files...\", allFiles.length);\n\t\tconst ck = spinner();\n\t\tck.start(\"Running checks...\");\n\t\tconst checkResults = await runAllChecks(repoRoot, allFiles, 60000);\n\t\tdebug(\"Check results: ok=%s, count=%d\", checkResults.ok, checkResults.results.length);\n\n\t\tif (!checkResults.ok) {\n\t\t\tck.stop(`${checkResults.results.filter((r) => !r.ok).length} check(s) failed`);\n\t\t\tconst failed = checkResults.results.filter((r) => !r.ok);\n\t\t\tconst rawStderr = failed.map((r) => `[${r.tool}] ${r.stderr}`).join(\"\\n\");\n\t\t\tconst checkErrors = parseHookErrors(rawStderr);\n\t\t\tconst menuResult = await showCheckFailureMenu(checkErrors, rawStderr);\n\t\t\tif (menuResult === \"cancelled\") {\n\t\t\t\treturn \"cancelled\";\n\t\t\t}\n\t\t\t// \"skipped\" → continue to grouping and commits\n\t\t} else {\n\t\t\tck.stop(\"All checks passed\");\n\t\t\tif (checkResults.results.length > 0) {\n\t\t\t\tlog.info(checkResults.results.map((r) => ` ${green(\"✓\")} ${r.tool}`).join(\"\\n\"));\n\t\t\t}\n\t\t}\n\t}\n\n\t// Step 2: Read config and determine provider\n\tconst config = await readConfig();\n\tconst resolvedProvider = config.provider ?? \"groq\";\n\tconst provider: ProviderName = isValidProvider(resolvedProvider) ? resolvedProvider : \"groq\";\n\n\t// Step 3: Ensure API key\n\ttry {\n\t\tawait getProviderApiKey(provider);\n\t\tdebug(\"API key found\");\n\t} catch {\n\t\tdebug(\"No API key found, prompting user\");\n\t\tconst { text: promptText } = await import(\"@clack/prompts\");\n\t\tconst key = await promptText({\n\t\t\tmessage: `Enter your ${formatProviderName(provider)} API key:`,\n\t\t\tplaceholder: provider === \"groq\" ? \"gsk_...\" : \"...\",\n\t\t\tvalidate: (v) => (v?.trim() ? undefined : \"API key is required\"),\n\t\t});\n\t\tif (isCancel(key)) {\n\t\t\toutro(dim(\"Cancelled.\"));\n\t\t\treturn \"cancelled\";\n\t\t}\n\t\tconst configKey = PROVIDER_ENV_KEYS[provider];\n\t\tawait setConfigValue(configKey, String(key).trim());\n\t\tdebug(\"API key saved to config\");\n\t}\n\n\t// Step 4: Call grouping service\n\tconst s = spinner();\n\ts.start(\"Analyzing files...\");\n\tconst apiKey = await getProviderApiKey(provider);\n\tconst result = await generateGroups(\n\t\tincluded,\n\t\tapiKey,\n\t\tgetModelForProvider(config, provider, PROVIDER_CONFIGS[provider].defaultModel),\n\t\tconfig.timeout ? parseInt(config.timeout, 10) : undefined,\n\t\tprovider,\n\t\tconfig.proxy,\n\t);\n\tconst validatedGroups = validateGroups(result.groups, included);\n\ts.stop(\"Files analyzed\");\n\n\tshowGroupedFiles(validatedGroups, included);\n\n\t// Step 5: Show grouping confirmation (skip in auto mode)\n\tif (flags.auto) {\n\t\tdebug(\"Auto mode: skipping grouping confirmation\");\n\t} else {\n\t\tconst confirmed = await showGroupingConfirmation(validatedGroups, excluded);\n\t\tif (!confirmed) {\n\t\t\toutro(dim(\"Cancelled.\"));\n\t\t\treturn \"cancelled\";\n\t\t}\n\t}\n\n\t// Step 6: Sequential multi-commit loop\n\tfor (let i = 0; i < validatedGroups.length; i++) {\n\t\tconst group = validatedGroups[i];\n\t\tshowGroupProgress(i + 1, validatedGroups.length, group.name);\n\n\t\t// Unstage everything first, then stage only this group's files\n\t\tawait resetStaging();\n\t\tawait stageFiles(group.files);\n\n\t\t// Get diff for this group\n\t\tconst diffResult = await getStagedDiff();\n\t\tif (!diffResult || \"excludedFiles\" in diffResult) {\n\t\t\tlog.warn(red(`No changes found for group \"${group.name}\" — skipping.`));\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Generate message\n\t\ts.start(\"Generating commit message...\");\n\t\tlet message: string;\n\t\ttry {\n\t\t\tmessage = await generateMessage(diffResult.diff, flags.hint);\n\t\t} catch (err) {\n\t\t\ts.stop(red(\"Failed to generate message.\"));\n\t\t\toutro(red(err instanceof Error ? err.message : String(err)));\n\t\t\treturn \"cancelled\";\n\t\t}\n\t\ts.stop(\"Message generated\");\n\t\tlog.info(dim(message));\n\n\t\t// Review message (skip in auto mode)\n\t\tif (flags.auto) {\n\t\t\tdebug(\"Auto mode: accepting generated message\");\n\t\t} else {\n\t\t\tconst reviewed = await reviewCommitMessage(message);\n\t\t\tif (reviewed === null) {\n\t\t\t\toutro(dim(\"Cancelled.\"));\n\t\t\t\treturn \"cancelled\";\n\t\t\t}\n\t\t\tmessage = reviewed;\n\t\t}\n\n\t\t// Cache message\n\t\tconst { getRepoRoot } = await import(\"../services/git.js\");\n\t\tconst repoRoot = await getRepoRoot();\n\t\tawait saveCachedCommit(repoRoot, message);\n\n\t\t// Attempt commit\n\t\ts.start(\"Running pre-commit hooks...\");\n\t\tconst headBefore = await getHead();\n\t\tconst commitResult = await attemptCommit(message, [], createProgressHandler(s));\n\t\tconst headAfter = await getHead();\n\n\t\tif (commitResult.ok || headBefore !== headAfter) {\n\t\t\ts.stop(\"Committed successfully.\");\n\t\t\tconst checks = parseToolChecks(commitResult.stderr ?? \"\");\n\t\t\tif (checks.length > 0) {\n\t\t\t\tconst lines = checks.map((c) => ` ${c.ok ? green(\"✓\") : red(\"✗\")} ${c.tool}`);\n\t\t\t\tlog.info(lines.join(\"\\n\"));\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\t// Hook failure — stop sequence, show recovery menu\n\t\ts.stop(\"Commit failed.\");\n\t\tconst errors = parseHookErrors(commitResult.stderr ?? \"\");\n\t\tconst recoveryResult = await showRecoveryMenu(\n\t\t\terrors,\n\t\t\tasync () => (await attemptCommit(message)).ok,\n\t\t\tasync (msg) => (await attemptCommitNoVerify(msg)).ok,\n\t\t\tasync () => {\n\t\t\t\tawait stageFiles(group.files);\n\t\t\t\treturn (await attemptCommit(message)).ok;\n\t\t\t},\n\t\t\tmessage,\n\t\t\tcommitResult.stderr ?? \"\",\n\t\t);\n\t\tif (recoveryResult === \"committed\") {\n\t\t\tif (i < validatedGroups.length - 1) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\treturn \"committed\";\n\t\t}\n\t\treturn recoveryResult;\n\t}\n\n\toutro(green(\"All groups committed.\"));\n\treturn \"committed\";\n}\n\nexport async function generateMessage(diff: string, hint?: string): Promise<string> {\n\tconst config = await readConfig();\n\tconst resolvedProvider = config.provider ?? \"groq\";\n\tconst provider: ProviderName = isValidProvider(resolvedProvider) ? resolvedProvider : \"groq\";\n\tconst apiKey = await getProviderApiKey(provider);\n\tconst model = getModelForProvider(config, provider, PROVIDER_CONFIGS[provider].defaultModel);\n\tdebug(\"Generating message with provider:\", provider, \"model:\", model, \"type:\", config.type);\n\n\treturn generateCommitMessage(diff, {\n\t\tapiKey,\n\t\tmodel,\n\t\ttype: config.type,\n\t\ttimeout: config.timeout ? parseInt(config.timeout, 10) : undefined,\n\t\thint,\n\t\tprovider,\n\t\tproxy: config.proxy,\n\t});\n}\n\nexport function buildExcludedFilesMessage(files: string[]): string {\n\tconst excludes = getDefaultExcludes();\n\tconst isLockfile = (f: string) =>\n\t\texcludes.some((pattern) => {\n\t\t\tif (pattern.endsWith(\".lock\") || pattern.endsWith(\".json\")) {\n\t\t\t\treturn f === pattern || f.endsWith(pattern.replace(\"*.\", \".\"));\n\t\t\t}\n\t\t\treturn false;\n\t\t});\n\n\tif (files.every(isLockfile)) {\n\t\treturn \"chore: update lockfile\";\n\t}\n\n\treturn \"chore: update generated files\";\n}\n","import { log, type spinner } from \"@clack/prompts\";\nimport { green, red } from \"kolorist\";\nimport { attemptCommit, attemptCommitNoVerify, getHead, stageAll } from \"../services/git.js\";\nimport { createProgressHandler } from \"../services/hook-progress.js\";\nimport { parseHookErrors, parseToolChecks } from \"../services/hooks.js\";\nimport { showRecoveryMenu } from \"../ui/menu.js\";\n\n/** Shared recovery menu factory — avoids repeating the same callback set */\nexport function makeRecoveryCallbacks(message: string) {\n\treturn {\n\t\tretry: async () => (await attemptCommit(message)).ok,\n\t\tskipHooks: async (msg: string) => (await attemptCommitNoVerify(msg)).ok,\n\t\trestage: async () => {\n\t\t\tawait stageAll();\n\t\t\treturn (await attemptCommit(message)).ok;\n\t\t},\n\t\tmessage,\n\t};\n}\n\n/**\n * Attempt commit with automatic recovery flow.\n * Handles the attempt → HEAD check → success (tool checks display)\n * / failure (recovery menu) pattern.\n * Caller is responsible for starting the spinner and showing the final outro.\n */\nexport async function commitWithRecovery(\n\tmessage: string,\n\ts: ReturnType<typeof spinner>,\n\theadBefore: string,\n): Promise<\"committed\" | \"cancelled\"> {\n\tconst result = await attemptCommit(message, [], createProgressHandler(s));\n\tconst headAfter = await getHead();\n\n\tif (result.ok || headBefore !== headAfter) {\n\t\ts.stop(\"Committed successfully.\");\n\n\t\tconst checks = parseToolChecks(result.stderr ?? \"\");\n\t\tif (checks.length > 0) {\n\t\t\tconst lines = checks.map((c) => ` ${c.ok ? green(\"✓\") : red(\"✗\")} ${c.tool}`);\n\t\t\tlog.info(lines.join(\"\\n\"));\n\t\t}\n\n\t\treturn \"committed\";\n\t}\n\n\ts.stop(\"Commit failed.\");\n\tconst errors = parseHookErrors(result.stderr ?? \"\");\n\tconst cb = makeRecoveryCallbacks(message);\n\tconst recoveryResult = await showRecoveryMenu(\n\t\terrors,\n\t\tcb.retry,\n\t\tcb.skipHooks,\n\t\tcb.restage,\n\t\tcb.message,\n\t\tresult.stderr ?? \"\",\n\t);\n\n\tif (recoveryResult === \"cancelled\") {\n\t\treturn \"cancelled\";\n\t}\n\n\treturn \"committed\";\n}\n","import { intro, outro, spinner } from \"@clack/prompts\";\nimport { green, red } from \"kolorist\";\nimport { getHead, getRepoRoot } from \"../services/git.js\";\nimport { loadCachedCommit } from \"../utils/cache.js\";\nimport { debug } from \"../utils/debug.js\";\nimport { commitWithRecovery } from \"./commit-utils.js\";\n\n/** Handle --retry mode: load cached message and re-attempt commit */\nexport async function handleRetry(): Promise<void> {\n\tdebug(\"Entering retry mode\");\n\tconst repoRoot = await getRepoRoot();\n\tconst cached = await loadCachedCommit(repoRoot);\n\tif (!cached) {\n\t\toutro(red(\"No cached commit message found. Run cmint without --retry first.\"));\n\t\tprocess.exit(1);\n\t}\n\tintro(\"🌿 commit-mint — retry\");\n\tconst s = spinner();\n\tconst headBefore = await getHead();\n\ts.start(\"Running pre-commit hooks...\");\n\tconst result = await commitWithRecovery(cached.message, s, headBefore);\n\tif (result === \"committed\") {\n\t\toutro(green(\"Committed successfully.\"));\n\t} else {\n\t\tprocess.exit(1);\n\t}\n}\n","import { log, outro, spinner } from \"@clack/prompts\";\nimport { dim, red } from \"kolorist\";\nimport { detectConfig, runAllChecks } from \"../services/checks.js\";\nimport { getChangedFiles, getRepoRoot, stageAll, stageFiles } from \"../services/git.js\";\nimport { parseHookErrors } from \"../services/hooks.js\";\nimport { showCheckFailureMenu, showStagingMenu } from \"../ui/menu.js\";\nimport { debug } from \"../utils/debug.js\";\nimport { type CommitFlags, runAutoGroupFlow } from \"./auto-group.js\";\n\n/** Interactive staging loop for multiple changed files */\n// biome-ignore lint/complexity/noExcessiveLinesPerFunction: Interactive staging loop with conditional branches\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Multi-branch TUI with autogroup, checks, staging options\nexport async function handleStaging(\n\tchangedFiles: Awaited<ReturnType<typeof getChangedFiles>>,\n\tflags: CommitFlags,\n): Promise<{\n\tchangedFiles: Awaited<ReturnType<typeof getChangedFiles>>;\n\tskipStaging: boolean;\n} | null> {\n\tconst repoRoot = await getRepoRoot();\n\tconst checksAvailable = (await detectConfig(repoRoot)) !== null;\n\tdebug(\"checks available:\", checksAvailable);\n\n\tlet stagingResult: Awaited<ReturnType<typeof showStagingMenu>> = null;\n\tlet filesToStage: string[] = [];\n\tlet stageAllFlag = false;\n\tlet skipStaging = false;\n\tlet currentFiles = changedFiles;\n\n\twhile (true) {\n\t\tstagingResult = await showStagingMenu(currentFiles, checksAvailable);\n\n\t\tif (stagingResult === \"autogroup\") {\n\t\t\tif (flags.message) {\n\t\t\t\toutro(red(\"--message flag is not compatible with auto-group mode.\"));\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tconst agResult = await runAutoGroupFlow(currentFiles, flags);\n\t\t\tif (agResult !== \"committed\") {\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tif (stagingResult === \"checks\") {\n\t\t\tawait stageAll();\n\t\t\tconst ckSpinner = spinner();\n\t\t\tckSpinner.start(\"Running checks...\");\n\t\t\tconst allFiles = currentFiles.filter((f) => f.status !== \"D\").map((f) => f.path);\n\t\t\tconst ckResult = await runAllChecks(repoRoot, allFiles, 60000);\n\t\t\tif (ckResult.ok) {\n\t\t\t\tckSpinner.stop(\"All checks passed\");\n\t\t\t\tfor (const r of ckResult.results) if (r.stdout.trim()) log.info(dim(r.stdout.trim()));\n\t\t\t} else {\n\t\t\t\tconst failed = ckResult.results.filter((r) => !r.ok);\n\t\t\t\tckSpinner.stop(`${failed.length} check${failed.length !== 1 ? \"s\" : \"\"} failed`);\n\t\t\t\tfor (const r of failed)\n\t\t\t\t\tlog.info(r.stderr?.trim() || r.stdout?.trim() || `Check failed: ${r.command}`);\n\t\t\t}\n\t\t\tcurrentFiles = await getChangedFiles();\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (stagingResult === \"staged\") {\n\t\t\tskipStaging = true;\n\t\t\tbreak;\n\t\t}\n\n\t\tif (!stagingResult) {\n\t\t\toutro(dim(\"Cancelled.\"));\n\t\t\treturn null;\n\t\t}\n\n\t\tfilesToStage = stagingResult.files;\n\t\tstageAllFlag = stagingResult.all;\n\t\tbreak;\n\t}\n\n\tif (!skipStaging) {\n\t\tconst s = spinner();\n\t\ts.start(`Staging ${filesToStage.length} file${filesToStage.length !== 1 ? \"s\" : \"\"}...`);\n\t\tif (stageAllFlag) {\n\t\t\tawait stageAll();\n\t\t} else {\n\t\t\tawait stageFiles(filesToStage);\n\t\t}\n\t\ts.stop(\"Files staged\");\n\t}\n\n\treturn { changedFiles: currentFiles, skipStaging };\n}\n\n/** Run user-defined pre-commit checks from cmint config */\nexport async function runPreCommitChecks(\n\tchangedFiles: Awaited<ReturnType<typeof getChangedFiles>>,\n\tnoCheck?: boolean,\n): Promise<void> {\n\tif (noCheck) return;\n\tconst checkRoot = await getRepoRoot();\n\tconst stagedFileList = changedFiles\n\t\t.filter((f) => f.staged && f.status !== \"D\")\n\t\t.map((f) => f.path);\n\tif (stagedFileList.length === 0) return;\n\n\tdebug(\"Running user checks on %d staged files...\", stagedFileList.length);\n\tconst checkResults = await runAllChecks(checkRoot, stagedFileList, 60000);\n\tdebug(\"Check results: ok=%s, count=%d\", checkResults.ok, checkResults.results.length);\n\n\tif (!checkResults.ok) {\n\t\tconst failed = checkResults.results.filter((r) => !r.ok);\n\t\tconst rawStderr = failed.map((r) => `[${r.tool}] ${r.stderr}`).join(\"\\n\");\n\t\tconst checkErrors = parseHookErrors(rawStderr);\n\t\tconst menuResult = await showCheckFailureMenu(checkErrors, rawStderr);\n\t\tif (menuResult === \"cancelled\") {\n\t\t\tprocess.exit(1);\n\t\t}\n\t}\n}\n","import { intro, isCancel, log, outro, spinner } from \"@clack/prompts\";\nimport { dim, green, red } from \"kolorist\";\nimport { getProviderApiKey, readConfig, setConfigValue } from \"../services/config.js\";\nimport {\n\tassertGitRepo,\n\tgetChangedFiles,\n\tgetHead,\n\tgetRepoRoot,\n\tgetStagedDiff,\n\tgetStatusShort,\n\tstageFiles,\n} from \"../services/git.js\";\nimport {\n\tformatProviderName,\n\tisValidProvider,\n\tPROVIDER_ENV_KEYS,\n\ttype ProviderName,\n} from \"../services/provider.js\";\nimport { reviewCommitMessage } from \"../ui/review-message.js\";\nimport { saveCachedCommit } from \"../utils/cache.js\";\nimport { debug } from \"../utils/debug.js\";\nimport {\n\tbuildExcludedFilesMessage,\n\ttype CommitFlags,\n\tgenerateMessage,\n\trunAutoGroupFlow,\n} from \"./auto-group.js\";\nimport { commitWithRecovery } from \"./commit-utils.js\";\nimport { handleRetry } from \"./retry.js\";\nimport { handleStaging, runPreCommitChecks } from \"./staging.js\";\n\n// biome-ignore lint/complexity/noExcessiveLinesPerFunction: Sequential CLI lifecycle orchestrator\n// biome-ignore lint/complexity/noExcessiveCognitiveComplexity: Multi-branch state machine (retry/normal, staging, review, recovery)\nexport async function commitCommand(flags: CommitFlags) {\n\tdebug(\"commitCommand called\", { flags });\n\tawait assertGitRepo();\n\n\t// ── Retry mode ──────────────────────────────────────────────────\n\tif (flags.retry) {\n\t\treturn handleRetry();\n\t}\n\n\t// ── Normal mode ─────────────────────────────────────────────────\n\tintro(\"🌿 commit-mint\");\n\n\tconst status = await getStatusShort();\n\tdebug(\"Git status:\", status || \"(empty)\");\n\tif (!status) {\n\t\toutro(dim(\"Nothing to commit.\"));\n\t\treturn;\n\t}\n\n\t// Stage changes\n\tlet changedFiles = await getChangedFiles();\n\tdebug(\"Changed files:\", changedFiles.length);\n\tconst s = spinner();\n\n\ttry {\n\t\tif (flags.auto) {\n\t\t\tif (flags.message) {\n\t\t\t\toutro(red(\"--message flag is not compatible with auto-group mode.\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst agResult = await runAutoGroupFlow(changedFiles, flags);\n\t\t\tif (agResult !== \"committed\") {\n\t\t\t\tprocess.exit(1);\n\t\t\t}\n\t\t\treturn;\n\t\t} else if (changedFiles.length === 1) {\n\t\t\ts.start(`Staging ${changedFiles[0].path}...`);\n\t\t\tawait stageFiles([changedFiles[0].path]);\n\t\t\ts.stop(\"File staged\");\n\t\t} else {\n\t\t\tconst result = await handleStaging(changedFiles, flags);\n\t\t\tif (!result) return;\n\t\t\tchangedFiles = result.changedFiles;\n\t\t}\n\t} catch (err) {\n\t\ts.stop(red(\"Staging failed.\"));\n\t\tconst msg = err instanceof Error ? err.message : String(err);\n\t\tdebug(\"Staging error:\", msg);\n\t\toutro(red(`Failed to stage files: ${msg}`));\n\t\tprocess.exit(1);\n\t}\n\n\t// Refresh file list after staging so staged state is accurate\n\tchangedFiles = await getChangedFiles();\n\n\t// Run user-defined pre-commit checks (before AI message generation)\n\tawait runPreCommitChecks(changedFiles, flags.noCheck);\n\n\t// Get diff for AI\n\tconst diffResult = await getStagedDiff();\n\tif (!diffResult) {\n\t\tdebug(\"No staged changes found after staging\");\n\t\toutro(red(\"No staged changes found.\"));\n\t\tprocess.exit(1);\n\t}\n\n\t// Handle all-staged-files-are-excluded case with hardcoded message\n\tif (\"excludedFiles\" in diffResult) {\n\t\tdebug(\"All staged files are excluded:\", diffResult.excludedFiles);\n\t\tconst message = buildExcludedFilesMessage(diffResult.excludedFiles);\n\n\t\tlog.info(diffResult.excludedFiles.map((f) => ` ${f}`).join(\"\\n\"));\n\n\t\tconst repoRoot = await getRepoRoot();\n\t\tawait saveCachedCommit(repoRoot, message);\n\n\t\ts.start(\"Running pre-commit hooks...\");\n\t\tconst headBefore = await getHead();\n\t\tconst result = await commitWithRecovery(message, s, headBefore);\n\t\tif (result === \"committed\") {\n\t\t\toutro(green(\"Done.\"));\n\t\t\treturn;\n\t\t}\n\t\tif (result === \"cancelled\") {\n\t\t\tprocess.exit(1);\n\t\t}\n\t\treturn;\n\t}\n\n\tdebug(\"Staged files:\", diffResult.files);\n\tdebug(\"Diff length:\", diffResult.diff.length, \"chars\");\n\n\tlog.info(diffResult.files.map((f) => ` ${f}`).join(\"\\n\"));\n\n\t// Generate or use provided message\n\tlet message: string;\n\n\tif (flags.message) {\n\t\tdebug(\"Using provided message:\", flags.message);\n\t\tmessage = flags.message;\n\t} else {\n\t\tconst config = await readConfig();\n\t\tconst provider: ProviderName = isValidProvider(config.provider ?? \"groq\")\n\t\t\t? (config.provider as ProviderName)\n\t\t\t: \"groq\";\n\t\ttry {\n\t\t\tawait getProviderApiKey(provider);\n\t\t\tdebug(\"API key found\");\n\t\t} catch {\n\t\t\tdebug(\"No API key found, prompting user\");\n\t\t\tconst { text: promptText } = await import(\"@clack/prompts\");\n\t\t\tconst configKey = PROVIDER_ENV_KEYS[provider];\n\t\t\tconst key = await promptText({\n\t\t\t\tmessage: `Enter your ${formatProviderName(provider)} API key:`,\n\t\t\t\tplaceholder: provider === \"groq\" ? \"gsk_...\" : \"...\",\n\t\t\t\tvalidate: (v) => (v?.trim() ? undefined : \"API key is required\"),\n\t\t\t});\n\t\t\tif (isCancel(key)) {\n\t\t\t\toutro(dim(\"Cancelled.\"));\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tawait setConfigValue(configKey, String(key).trim());\n\t\t\tdebug(\"API key saved to config\");\n\t\t}\n\n\t\ts.start(\"Generating commit message...\");\n\t\ttry {\n\t\t\tconst genStart = Date.now();\n\t\t\tmessage = await generateMessage(diffResult.diff, flags.hint);\n\t\t\tdebug(\"generateMessage took %d ms\", Date.now() - genStart);\n\t\t\tdebug(\"Generated message:\", message);\n\t\t} catch (err) {\n\t\t\ts.stop(red(\"Failed to generate message.\"));\n\t\t\tdebug(\"Message generation failed:\", err instanceof Error ? err.message : String(err));\n\t\t\toutro(red(err instanceof Error ? err.message : String(err)));\n\t\t\treturn;\n\t\t}\n\t\ts.stop(\"Message generated\");\n\t}\n\n\t// Review message (with optional code review)\n\tconst reviewed = await reviewCommitMessage(message);\n\tif (reviewed === null) {\n\t\toutro(dim(\"Cancelled.\"));\n\t\treturn;\n\t}\n\tmessage = reviewed;\n\n\t// Cache message before attempting commit\n\tconst repoRoot = await getRepoRoot();\n\tawait saveCachedCommit(repoRoot, message);\n\tdebug(\"Message cached for repo:\", repoRoot);\n\n\t// Attempt commit\n\ts.start(\"Running pre-commit hooks...\");\n\tconst headBefore = await getHead();\n\tdebug(\"HEAD before commit:\", headBefore);\n\tconst result = await commitWithRecovery(message, s, headBefore);\n\tdebug(\"Commit result:\", result);\n\n\tif (result === \"committed\") {\n\t\toutro(green(\"Done.\"));\n\t\treturn;\n\t}\n\tif (result === \"cancelled\") {\n\t\tprocess.exit(1);\n\t}\n}\n","import * as p from \"@clack/prompts\";\nimport { bold, dim, green } from \"kolorist\";\nimport { readConfig, writeConfig } from \"../services/config.js\";\nimport {\n\tformatProviderName,\n\tisValidProvider,\n\tPROVIDER_CONFIGS,\n\tPROVIDER_ENV_KEYS,\n\ttype ProviderName,\n} from \"../services/provider.js\";\nimport { debug } from \"../utils/debug.js\";\n\nfunction maskKey(key: string | undefined): string {\n\tif (!key) return dim(\"not set\");\n\tif (key.length <= 8) return \"****\";\n\treturn `${key.slice(0, 4)}${\"*\".repeat(Math.min(key.length - 8, 20))}${key.slice(-4)}`;\n}\n\nfunction buildConfigDisplay(config: Record<string, string | undefined>): string {\n\tconst provider: ProviderName = isValidProvider(config.provider ?? \"groq\")\n\t\t? (config.provider as ProviderName)\n\t\t: \"groq\";\n\tconst keyName = PROVIDER_ENV_KEYS[provider];\n\tconst apiKey = config[keyName];\n\n\tconst lines = [\n\t\t`Provider: ${bold(formatProviderName(provider))}`,\n\t\t`API Key: ${maskKey(apiKey)}`,\n\t\t`Model: ${config.model ?? \"(none)\"}`,\n\t\t`Locale: ${config.locale ?? \"en\"}`,\n\t\t`Max Length: ${config[\"max-length\"] ?? \"100\"}`,\n\t\t`Commit Type: ${config.type || dim(\"(none)\")}`,\n\t\t`Timeout: ${config.timeout ?? \"10000\"}ms`,\n\t\t`Proxy: ${config.proxy || dim(\"(none)\")}`,\n\t];\n\n\treturn lines.join(\"\\n\");\n}\n\nfunction getProvider(config: Record<string, string | undefined>): ProviderName {\n\treturn isValidProvider(config.provider ?? \"groq\") ? (config.provider as ProviderName) : \"groq\";\n}\n\nasync function promptProvider(): Promise<string | symbol> {\n\treturn p.select({\n\t\tmessage: \"Select LLM provider:\",\n\t\toptions: [\n\t\t\t{ label: \"Groq\", value: \"groq\", hint: PROVIDER_CONFIGS.groq.defaultModel },\n\t\t\t{ label: \"Cerebras\", value: \"cerebras\", hint: PROVIDER_CONFIGS.cerebras.defaultModel },\n\t\t\t{ label: \"Mistral\", value: \"mistral\", hint: PROVIDER_CONFIGS.mistral.defaultModel },\n\t\t],\n\t});\n}\n\nasync function promptApiKey(provider: ProviderName): Promise<string | symbol> {\n\tconst keyName = PROVIDER_ENV_KEYS[provider];\n\tconst result = await p.text({\n\t\tmessage: `${formatProviderName(provider)} API key:`,\n\t\tplaceholder: \"Paste your API key\",\n\t\tvalidate: (v) => (!v?.trim() ? \"API key cannot be empty\" : undefined),\n\t});\n\tif (p.isCancel(result)) return result;\n\tawait writeConfig({ [keyName]: result.toString().trim() });\n\tdebug(\"config: %s set\", keyName);\n\treturn result;\n}\n\nasync function promptTextSetting(\n\tlabel: string,\n\tconfigKey: string,\n\tcurrentValue: string | undefined,\n\tvalidate?: (v: string | undefined) => string | undefined,\n): Promise<string | symbol> {\n\tconst result = await p.text({\n\t\tmessage: label,\n\t\tplaceholder: currentValue ?? \"\",\n\t\tinitialValue: currentValue ?? \"\",\n\t\tvalidate,\n\t});\n\tif (p.isCancel(result)) return result;\n\tawait writeConfig({ [configKey]: result.toString().trim() });\n\tdebug(\"config: %s set to %s\", configKey, result);\n\treturn result;\n}\n\nconst requireNumber = (v: string | undefined) => {\n\tif (!v?.trim()) return \"Value cannot be empty\";\n\treturn Number.isNaN(Number(v)) ? \"Must be a number\" : undefined;\n};\n\ntype SettingHandler = () => Promise<string | symbol | undefined>;\n\nfunction getSettingHandlers(\n\tconfig: Record<string, string | undefined>,\n): Record<string, SettingHandler> {\n\tconst provider = getProvider(config);\n\treturn {\n\t\tprovider: async () => {\n\t\t\tconst result = await promptProvider();\n\t\t\tif (p.isCancel(result)) return result;\n\t\t\tawait writeConfig({ provider: result as string });\n\t\t\tdebug(\"config: provider set to %s\", result);\n\t\t},\n\t\tapikey: async () => promptApiKey(provider),\n\t\tmodel: async () => promptTextSetting(\"Model ID:\", \"model\", config.model),\n\t\tlocale: async () => promptTextSetting(\"Locale (e.g. en, ja, ko):\", \"locale\", config.locale),\n\t\tmaxlen: async () =>\n\t\t\tpromptTextSetting(\n\t\t\t\t\"Max commit message length:\",\n\t\t\t\t\"max-length\",\n\t\t\t\tconfig[\"max-length\"],\n\t\t\t\trequireNumber,\n\t\t\t),\n\t\ttype: async () =>\n\t\t\tpromptTextSetting(\"Commit type prefix (e.g. conventional):\", \"type\", config.type),\n\t\ttimeout: async () =>\n\t\t\tpromptTextSetting(\"Timeout (ms):\", \"timeout\", config.timeout, requireNumber),\n\t\tproxy: async () => promptTextSetting(\"Proxy URL:\", \"proxy\", config.proxy),\n\t};\n}\n\nasync function handleEditSetting(\n\tsetting: string,\n\tconfig: Record<string, string | undefined>,\n): Promise<boolean> {\n\tconst handlers = getSettingHandlers(config);\n\tconst handler = handlers[setting];\n\tif (!handler) return false;\n\tconst result = await handler();\n\treturn !p.isCancel(result);\n}\n\nasync function editSettingsLoop(initialConfig: Record<string, string | undefined>): Promise<void> {\n\tlet config = initialConfig;\n\n\twhile (true) {\n\t\t// Re-read config to reflect changes from previous edits\n\t\tconfig = (await readConfig()) as Record<string, string | undefined>;\n\t\tconst provider = getProvider(config);\n\n\t\tconst setting = await p.select({\n\t\t\tmessage: \"Select a setting to edit:\",\n\t\t\toptions: [\n\t\t\t\t{\n\t\t\t\t\tlabel: `LLM Provider ${dim(`(${formatProviderName(provider)})`)}`,\n\t\t\t\t\tvalue: \"provider\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: `API Key ${dim(`(for ${formatProviderName(provider)})`)}`,\n\t\t\t\t\tvalue: \"apikey\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: `Model ${dim(`(${config.model ?? \"(none)\"})`)}`,\n\t\t\t\t\tvalue: \"model\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: `Locale ${dim(`(${config.locale ?? \"en\"})`)}`,\n\t\t\t\t\tvalue: \"locale\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: `Max commit length ${dim(`(${config[\"max-length\"] ?? \"100\"})`)}`,\n\t\t\t\t\tvalue: \"maxlen\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: `Commit type prefix ${dim(`(${config.type || \"(none)\"})`)}`,\n\t\t\t\t\tvalue: \"type\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: `Timeout (ms) ${dim(`(${config.timeout ?? \"10000\"})`)}`,\n\t\t\t\t\tvalue: \"timeout\",\n\t\t\t\t},\n\t\t\t\t{\n\t\t\t\t\tlabel: `Proxy URL ${dim(`(${config.proxy || \"(none)\"})`)}`,\n\t\t\t\t\tvalue: \"proxy\",\n\t\t\t\t},\n\t\t\t\t{ label: \"Done editing\", value: \"done\" },\n\t\t\t],\n\t\t});\n\n\t\tif (p.isCancel(setting) || setting === \"done\") break;\n\n\t\tconst updated = await handleEditSetting(setting as string, config);\n\t\tif (updated) {\n\t\t\tp.log.success(green(\"Updated.\"));\n\t\t}\n\t}\n}\n\nexport async function configCommand(): Promise<void> {\n\tdebug(\"configCommand: starting\");\n\tp.intro(bold(\"🌿 commit-mint config\"));\n\n\twhile (true) {\n\t\tconst config = (await readConfig()) as Record<string, string | undefined>;\n\n\t\tp.note(buildConfigDisplay(config), \"commit-mint config\");\n\n\t\tconst action = await p.select({\n\t\t\tmessage: \"What would you like to do?\",\n\t\t\toptions: [\n\t\t\t\t{ label: \"Edit settings\", value: \"edit\" },\n\t\t\t\t{ label: \"Done\", value: \"done\" },\n\t\t\t],\n\t\t});\n\n\t\tif (p.isCancel(action)) {\n\t\t\tdebug(\"configCommand: cancelled at main menu\");\n\t\t\tp.outro(dim(\"Cancelled.\"));\n\t\t\treturn;\n\t\t}\n\n\t\tif (action === \"done\") {\n\t\t\tdebug(\"configCommand: done\");\n\t\t\tp.outro(\"Config saved.\");\n\t\t\treturn;\n\t\t}\n\n\t\tawait editSettingsLoop(config);\n\t}\n}\n","#!/usr/bin/env node\nimport { cli, command } from \"cleye\";\nimport pkg from \"../package.json\" with { type: \"json\" };\n\nconst { version } = pkg;\n\nimport { commitCommand } from \"./commands/commit.js\";\nimport { configCommand } from \"./commands/config.js\";\nimport { setDebug } from \"./utils/debug.js\";\n\ncli(\n\t{\n\t\tname: \"cmint\",\n\t\tversion,\n\t\tdescription: \"A commit tool that actually handles hook failures\",\n\t\tflags: {\n\t\t\tretry: {\n\t\t\t\ttype: Boolean,\n\t\t\t\tdescription: \"Retry the last failed commit\",\n\t\t\t\talias: \"r\",\n\t\t\t\tdefault: false,\n\t\t\t},\n\t\t\tauto: {\n\t\t\t\ttype: Boolean,\n\t\t\t\tdescription: \"Auto-group files into commits and accept messages (no prompts)\",\n\t\t\t\talias: \"a\",\n\t\t\t\tdefault: false,\n\t\t\t},\n\t\t\tmessage: {\n\t\t\t\ttype: String,\n\t\t\t\tdescription: \"Provide a commit message directly (skip AI generation)\",\n\t\t\t\talias: \"m\",\n\t\t\t},\n\t\t\thint: {\n\t\t\t\ttype: String,\n\t\t\t\tdescription: \"Add context hint for AI commit message generation\",\n\t\t\t\talias: \"H\",\n\t\t\t},\n\t\t\tdebug: {\n\t\t\t\ttype: Boolean,\n\t\t\t\tdescription: \"Enable debug output\",\n\t\t\t\talias: \"d\",\n\t\t\t\tdefault: false,\n\t\t\t},\n\t\t\tnoCheck: {\n\t\t\t\ttype: Boolean,\n\t\t\t\tdescription: \"Skip user-defined pre-commit checks\",\n\t\t\t\talias: \"N\",\n\t\t\t\tdefault: false,\n\t\t\t},\n\t\t},\n\t\tcommands: [\n\t\t\tcommand({ name: \"config\" }, async () => {\n\t\t\t\tawait configCommand();\n\t\t\t}),\n\t\t],\n\t},\n\t(argv) => {\n\t\tsetDebug(argv.flags.debug);\n\t\tcommitCommand(argv.flags);\n\t},\n);\n"],"mappings":"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"}