@kyubiware/commit-mint 0.4.0 → 0.4.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 +3 -1
- package/dist/cli.mjs.map +1 -1
- package/package.json +2 -1
package/dist/cli.mjs
CHANGED
|
@@ -26,7 +26,7 @@ var __exportAll = (all, no_symbols) => {
|
|
|
26
26
|
//#region package.json
|
|
27
27
|
var package_default = {
|
|
28
28
|
name: "@kyubiware/commit-mint",
|
|
29
|
-
version: "0.4.
|
|
29
|
+
version: "0.4.1",
|
|
30
30
|
description: "A commit tool that actually handles hook failures",
|
|
31
31
|
type: "module",
|
|
32
32
|
bin: { "cmint": "./dist/cli.mjs" },
|
|
@@ -34,6 +34,7 @@ var package_default = {
|
|
|
34
34
|
scripts: {
|
|
35
35
|
"build": "tsdown src/cli.ts --format esm --dts --clean",
|
|
36
36
|
"dev": "tsx src/cli.ts",
|
|
37
|
+
"dev:auto": "tsx src/cli.ts -a",
|
|
37
38
|
"dev:debug": "tsx src/cli.ts --debug",
|
|
38
39
|
"lint": "biome check .",
|
|
39
40
|
"lint:fix": "biome check --fix .",
|
|
@@ -1429,6 +1430,7 @@ async function runAutoGroupFlow(changedFiles, flags) {
|
|
|
1429
1430
|
return "cancelled";
|
|
1430
1431
|
}
|
|
1431
1432
|
s.stop("Message generated");
|
|
1433
|
+
log.info(dim(message));
|
|
1432
1434
|
if (flags.auto) debug("Auto mode: accepting generated message");
|
|
1433
1435
|
else {
|
|
1434
1436
|
const reviewed = await reviewCommitMessage(message);
|
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/git.ts","../src/services/hooks.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 type { ExecaError } from \"execa\";\nimport { execa } from \"execa\";\nimport { debug } from \"../utils/debug.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): 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\t// We don't stream to the terminal — the success/failure result is enough\n\t\tconst stderrChunks: string[] = [];\n\t\tsubprocess.stderr?.on(\"data\", (chunk: Buffer) => {\n\t\t\tstderrChunks.push(chunk.toString());\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(message: string): Promise<CommitResult> {\n\tdebug(\"attemptCommitNoVerify:\", message);\n\treturn attemptCommit(message, [\"--no-verify\"]);\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\tfor (const match of output.matchAll(/^\\s*\\d+:(\\d+)\\s+(error|warning)\\s+(.+?)\\s+(.+?)$/gm)) {\n\t\terrors.push({\n\t\t\ttool: \"eslint\",\n\t\t\tmessage: `${match[2]}: ${match[3]} (${match[4]})`,\n\t\t\traw: match[0],\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 */\nfunction 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 */\nfunction extractToolName(command: string): string | null {\n\tconst tokens = command.split(/\\s+/);\n\tconst first = tokens[0];\n\n\t// npm/yarn/pnpm run <script>\n\tif ([\"npm\", \"yarn\", \"pnpm\", \"bun\"].includes(first)) {\n\t\t// Skip \"run\" if present\n\t\tconst scriptIdx = tokens[1] === \"run\" ? 2 : 1;\n\t\tconst script = tokens[scriptIdx];\n\t\tif (!script) return null;\n\t\t// Map common script names to their underlying tool\n\t\tconst scriptMap: Record<string, string> = {\n\t\t\ttypecheck: \"tsc\",\n\t\t\tlint: \"eslint\",\n\t\t\tformat: \"prettier\",\n\t\t};\n\t\treturn scriptMap[script] ?? script;\n\t}\n\n\t// npx <tool>\n\tif (first === \"npx\") return tokens[1] ?? null;\n\n\t// Direct tool invocation (biome, eslint, tsc, vitest, jest, prettier)\n\treturn first;\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 { 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\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(\"Committing...\");\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\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 { 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(\"Retrying commit...\");\n\t\tconst result = await attemptCommit(cached.message);\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(\"Committing...\");\n\t\tconst headBefore = await getHead();\n\t\tconst result = await attemptCommit(message);\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(\"Committing...\");\n\tconst headBefore = await getHead();\n\tdebug(\"HEAD before commit:\", headBefore);\n\tconst result = await attemptCommit(message);\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":["mapGroqError","mapGroqError","pkg"],"sources":["../package.json","../src/utils/debug.ts","../src/services/config.ts","../src/services/git.ts","../src/services/hooks.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 type { ExecaError } from \"execa\";\nimport { execa } from \"execa\";\nimport { debug } from \"../utils/debug.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): 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\t// We don't stream to the terminal — the success/failure result is enough\n\t\tconst stderrChunks: string[] = [];\n\t\tsubprocess.stderr?.on(\"data\", (chunk: Buffer) => {\n\t\t\tstderrChunks.push(chunk.toString());\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(message: string): Promise<CommitResult> {\n\tdebug(\"attemptCommitNoVerify:\", message);\n\treturn attemptCommit(message, [\"--no-verify\"]);\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\tfor (const match of output.matchAll(/^\\s*\\d+:(\\d+)\\s+(error|warning)\\s+(.+?)\\s+(.+?)$/gm)) {\n\t\terrors.push({\n\t\t\ttool: \"eslint\",\n\t\t\tmessage: `${match[2]}: ${match[3]} (${match[4]})`,\n\t\t\traw: match[0],\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 */\nfunction 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 */\nfunction extractToolName(command: string): string | null {\n\tconst tokens = command.split(/\\s+/);\n\tconst first = tokens[0];\n\n\t// npm/yarn/pnpm run <script>\n\tif ([\"npm\", \"yarn\", \"pnpm\", \"bun\"].includes(first)) {\n\t\t// Skip \"run\" if present\n\t\tconst scriptIdx = tokens[1] === \"run\" ? 2 : 1;\n\t\tconst script = tokens[scriptIdx];\n\t\tif (!script) return null;\n\t\t// Map common script names to their underlying tool\n\t\tconst scriptMap: Record<string, string> = {\n\t\t\ttypecheck: \"tsc\",\n\t\t\tlint: \"eslint\",\n\t\t\tformat: \"prettier\",\n\t\t};\n\t\treturn scriptMap[script] ?? script;\n\t}\n\n\t// npx <tool>\n\tif (first === \"npx\") return tokens[1] ?? null;\n\n\t// Direct tool invocation (biome, eslint, tsc, vitest, jest, prettier)\n\treturn first;\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 { 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(\"Committing...\");\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\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 { 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(\"Retrying commit...\");\n\t\tconst result = await attemptCommit(cached.message);\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(\"Committing...\");\n\t\tconst headBefore = await getHead();\n\t\tconst result = await attemptCommit(message);\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(\"Committing...\");\n\tconst headBefore = await getHead();\n\tdebug(\"HEAD before commit:\", headBefore);\n\tconst result = await attemptCommit(message);\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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kyubiware/commit-mint",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"description": "A commit tool that actually handles hook failures",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
"scripts": {
|
|
13
13
|
"build": "tsdown src/cli.ts --format esm --dts --clean",
|
|
14
14
|
"dev": "tsx src/cli.ts",
|
|
15
|
+
"dev:auto": "tsx src/cli.ts -a",
|
|
15
16
|
"dev:debug": "tsx src/cli.ts --debug",
|
|
16
17
|
"lint": "biome check .",
|
|
17
18
|
"lint:fix": "biome check --fix .",
|