@kyubiware/commit-mint 0.5.5 → 0.6.0

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/README.md CHANGED
@@ -1,270 +1,308 @@
1
1
  # commit-mint
2
2
 
3
- [![npm version](https://img.shields.io/npm/v/@kyubiware/commit-mint.svg)](https://www.npmjs.com/package/@kyubiware/commit-mint)
4
- [![Build Status](https://img.shields.io/github/actions/workflow/status/kyubiware/commit-mint/ci.yml?style=flat-square)](https://github.com/kyubiware/commit-mint/actions)
5
- ![Node.js](https://img.shields.io/badge/Node.js->=18-3c873a?style=flat-square)
6
- [![License](https://img.shields.io/badge/License-MIT-blue?style=flat-square)](LICENSE)
3
+ [![npm](https://img.shields.io/npm/v/@kyubiware/commit-mint.svg)](https://www.npmjs.com/package/@kyubiware/commit-mint)
4
+ [![CI](https://img.shields.io/github/actions/workflow/status/kyubiware/commit-mint/ci.yml)](https://github.com/kyubiware/commit-mint/actions)
5
+ [![Node](https://img.shields.io/badge/node-%3E%3D18-3c873a)](https://nodejs.org)
6
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](LICENSE)
7
7
 
8
- > Auto-group your changes into clean, conventional commits. AI handles the grouping, messages, and hook failures so you don't have to.
8
+ A commit tool that handles hook failures. Generates conventional commit messages
9
+ from your diff, auto-groups unrelated changes into separate commits, runs your
10
+ checks before any API call, and gives you a recovery menu when hooks block the
11
+ commit instead of dumping raw stderr.
9
12
 
10
- ```
11
- ┌ commit-mint
12
-
13
- ◇ Files analyzed
14
-
15
- ● Commit group 1 of 3: "Reading view refactor"
16
-
17
- ◇ Message generated
18
-
19
- ● feat(compound): add compound utilities and token handling for text study
20
-
21
- ◇ Committed successfully.
22
-
23
- ● ✓ prettier
24
- │ ✓ eslint
25
- │ ✓ tsc
26
- │ ✓ vitest
27
-
28
- ● Commit group 2 of 3: "Panel refactor"
29
- ◇ Message generated
30
-
31
- ● feat(text-study): add compound component support to ReadingInspectorPanel
32
-
33
- ◇ Committed successfully.
34
-
35
- └ All groups committed.
36
- ```
37
-
38
- ## Quick start
13
+ ## Install
39
14
 
40
15
  ```bash
41
16
  npm install -g @kyubiware/commit-mint
42
- cmint -a
43
17
  ```
44
18
 
45
- On first run, you'll be prompted for an API key if one isn't set. It's saved for future runs.
19
+ Or run without installing:
46
20
 
47
- ## Features
21
+ ```bash
22
+ npx @kyubiware/commit-mint
23
+ ```
48
24
 
49
- - **Auto-group by intent** — AI reads your diff and groups files into logical commits. No more `feat: update stuff` that bundles unrelated changes.
50
- - **Zero-prompt auto mode** `cmint -a` stages, groups, generates messages, and commits without a single prompt.
51
- - **Hook failures handled in-flow** — Parsed error summary with a recovery menu to copy, skip, retry, or edit. No raw stderr dumps.
52
- - **Multi-provider AI** — Works with Groq, Cerebras, and Mistral out of the box. Per-provider model configuration supported.
53
- - **Built-in pre-commit checks** — Define checks in a cmint config file and run them before AI generation. A failing check never wastes an API call.
54
- - **Message caching on failure** — A failed commit caches its message. Fix the error, run `cmint --retry`, and pick up where you left off.
25
+ Requires Node.js 18+ and git. Run `cmint config` once to set the AI provider and
26
+ API key. The key is saved to `~/.commit-mint` (INI).
55
27
 
56
28
  ## Usage
57
29
 
58
30
  ```bash
59
- # Auto-group and commit everything (no prompts)
60
- cmint -a
31
+ cmint # interactive: stage checks review → commit
32
+ cmint -a # auto-group, generate messages, commit everything
33
+ cmint -m "feat: ..." # skip AI, use your own message
34
+ cmint -H "context" # hint to the AI (e.g. "refactor only, no behavior change")
35
+ cmint -r # retry the last failed commit (cached message)
36
+ cmint -N # skip pre-flight checks
37
+ cmint -d # debug logging to stderr
38
+ cmint config # edit provider, model, locale, etc.
39
+ ```
61
40
 
62
- # Normal interactive flow
63
- cmint
41
+ ## Pre-flight checks (`.cmintrc`)
64
42
 
65
- # Skip AI, provide your own message
66
- cmint -m "feat: add dark mode"
43
+ `.cmintrc` is commit-mint's pre-commit check system. The config syntax is
44
+ identical to [lint-staged](https://github.com/okonet/lint-staged) glob keys
45
+ mapping to shell commands — but the checks run inside commit-mint's flow, not
46
+ as a separate git hook.
67
47
 
68
- # Pass context hint for better messages
69
- cmint -H "refactoring auth module"
48
+ This matters for three reasons:
70
49
 
71
- # Retry last failed commit (uses cached message)
72
- cmint -r
50
+ **1. Checks run before the AI call.** commit-mint runs checks before
51
+ generating the commit message. A failing check short-circuits before any API
52
+ call. With lint-staged, the hook fires after the message is already finalized
53
+ (if the AI call was made) or the user has typed one in — so a broken check
54
+ wastes the message.
73
55
 
74
- # Skip pre-commit checks
75
- cmint -N
56
+ **2. Failures get a recovery menu, not raw stderr.** lint-staged prints whatever
57
+ the tool emitted and exits. commit-mint parses biome, tsc, vitest/jest, eslint,
58
+ and lint-staged output into structured errors. Then commit-mint lets you copy the error report to clipboard,
59
+ so you can paste straight to your coding agent.
76
60
 
77
- # Debug mode
78
- cmint -d
61
+ **3. Live retry.** After your coding agent fixes the error in another terminal, pick "Retry checks" in
62
+ the menu, no need to exit and re-run `cmint`.
63
+
64
+ Same syntax, fewer moving parts, and the checks live in the same process as
65
+ the rest of the commit.
66
+
67
+ ### Config file names
68
+
69
+ Checked in this order. First match wins.
79
70
 
80
- # Configuration
81
- cmint config get GROQ_API_KEY
82
- cmint config set GROQ_API_KEY=gsk_...
83
- cmint config set provider cerebras
84
- cmint config set model openai/gpt-oss-20b
71
+ ```
72
+ .cmintrc
73
+ .cmintrc.json
74
+ .cmintrc.mjs
75
+ .cmintrc.mts
76
+ .cmintrc.js
77
+ .cmintrc.ts
78
+ .cmintrc.cjs
79
+ .cmintrc.cts
80
+ cmint.config.mjs
81
+ cmint.config.mts
82
+ cmint.config.js
83
+ cmint.config.ts
84
+ cmint.config.cjs
85
+ cmint.config.cts
85
86
  ```
86
87
 
87
- | Flag | Description |
88
- |------|-------------|
89
- | `-a, --auto` | Auto-group files into commits, accept all messages |
90
- | `-m, --message` | Provide a commit message directly (skip AI) |
91
- | `-H, --hint` | Add context hint for AI message generation |
92
- | `-r, --retry` | Retry the last failed commit |
93
- | `-N, --noCheck` | Skip pre-commit checks |
94
- | `-d, --debug` | Enable debug output |
95
- | `-h, --help` | Show help |
96
- | `-v, --version` | Show version |
88
+ `.ts`/`.cts`/`.cjs` are loaded via [jiti](https://github.com/unjs/jiti) — use
89
+ TypeScript syntax freely. `.json` is parsed as plain JSON. Everything else is
90
+ loaded as ESM with `import default`.
97
91
 
98
- ## Modes
92
+ ### Config shape
99
93
 
100
- ### Auto mode (`-a`)
94
+ A default export. Each key is a [picomatch](https://github.com/micromatch/picomatch)
95
+ glob; each value is a command string, a string array, or a function that
96
+ returns either.
101
97
 
102
- `cmint -a` runs the full pipeline with no prompts:
98
+ ```ts
99
+ // .cmintrc.ts
100
+ export default {
101
+ "*.{js,ts,json}": "biome check --write --no-errors-on-unmatched --error-on-warnings",
102
+ "*.ts": () => ["tsc --noEmit", "vitest run --passWithNoTests", "npm run build"],
103
+ };
104
+ ```
103
105
 
104
- 1. AI analyzes all changed files
105
- 2. Files are grouped into logical commits by intent
106
- 3. Each group gets its own AI-generated conventional commit message
107
- 4. Groups are committed sequentially
108
- 5. Hook failures per group trigger the recovery menu
106
+ This is the actual `.cmintrc.ts` commit-mint ships with for its own
107
+ development biome on staged JS/TS/JSON, then tsc + vitest + build on staged
108
+ TS.
109
109
 
110
- ### Manual mode
110
+ **String commands** get matched files appended as trailing arguments. Files
111
+ with spaces in their paths are quoted automatically.
111
112
 
112
- Run `cmint` without flags for the interactive flow:
113
+ ```ts
114
+ export default {
115
+ "*.ts": "eslint --fix", // runs `eslint --fix src/foo.ts src/bar.ts`
116
+ };
117
+ ```
113
118
 
114
- 1. **Staging menu** stage all, select files, auto-group, or run checks
115
- 2. **File selection** — multi-select specific files if you don't want everything
116
- 3. **Message review** — review the AI-generated message before committing
117
- 4. **Commit attempt** — hooks run, recovery menu appears on failure
119
+ **String arrays** run sequentially, each as a separate command. First failure
120
+ stops the run.
118
121
 
119
- If only one file changed, it's staged automatically.
122
+ ```ts
123
+ export default {
124
+ "*.ts": ["eslint --fix", "prettier --write"],
125
+ };
126
+ ```
120
127
 
121
- ## Providers
128
+ **Function commands** receive the matched files and return a command or array
129
+ of commands. Use these when the command depends on the file list, or you want
130
+ multiple commands from one glob:
122
131
 
123
- commit-mint supports multiple AI providers with per-provider configuration:
132
+ ```ts
133
+ export default {
134
+ "*.ts": (files) =>
135
+ files.length > 5 ? `vitest run ${files.join(" ")}` : "vitest run",
136
+ };
137
+ ```
124
138
 
125
- | Provider | Env key | Default model |
126
- |----------|---------|---------------|
127
- | **Groq** | `GROQ_API_KEY` | `openai/gpt-oss-20b` |
128
- | **Cerebras** | `CEREBRAS_API_KEY` | `gpt-oss-120b` |
129
- | **Mistral** | `MISTRAL_API_KEY` | `mistral-small` |
139
+ ### Glob matching
130
140
 
131
- Switch providers with `cmint config set provider <name>`. Override the model per-provider with `cmint config set model_cerebras <model>`.
141
+ - Globs without a `/` match at any depth (e.g. `*.ts` matches `src/foo.ts` and
142
+ `a/b/c.ts`).
143
+ - Dotfiles are included.
144
+ - Paths with spaces are quoted before being appended.
132
145
 
133
- > [!TIP]
134
- > All providers use OpenAI-compatible APIs. Groq uses the official SDK; Cerebras and Mistral use a built-in fetch client.
146
+ ### Behavior
135
147
 
136
- ## Recovery menu
148
+ - Checks run after `git add`, before the AI call.
149
+ - Globs are processed in declaration order.
150
+ - Commands run sequentially per glob. First failure stops the run (fail-fast)
151
+ and skips remaining globs.
152
+ - 60s timeout per command. ENOENT (command not found) and timeouts are
153
+ reported back to the menu as their own error.
154
+ - Skipped entirely with `cmint -N`.
155
+
156
+ ### Failure menu
137
157
 
138
- When a pre-commit hook blocks your commit, commit-mint parses the error output and presents an interactive menu:
158
+ When a check fails, the same `parseHookErrors` pipeline that handles git
159
+ hooks runs, and a menu appears:
139
160
 
140
161
  ```
141
- ╭─────────────────────────────────────────────────╮
142
- Pre-commit hook failed │
143
- │ │
144
- │ • biome: src/cli.ts — unused variable │
145
- │ • vitest: 1 test failed in test/cli.test.ts │
146
- │ │
147
- What do you want to do? │
148
- │ │
149
- │ Copy error report to clipboard │
150
- │ View full output │
151
- │ Skip hooks and commit (--no-verify) │
152
- │ Re-stage files and retry │
153
- │ Edit commit message │
154
- │ Cancel │
155
- ╰─────────────────────────────────────────────────╯
162
+ Pre-commit check failed
163
+ [biome] src/services/ai.ts:12:1 lint/suspicious/noExplicitAny — Unexpected any...
164
+ • [tsc] src/services/ai.ts:55:18 — error TS2345: Argument of type 'string' is...
165
+
166
+ What do you want to do?
167
+ Copy error report to clipboard
168
+ View full error output
169
+ Retry checks
170
+ Skip checks and commit
171
+ Cancel
156
172
  ```
157
173
 
158
- | Option | What it does |
159
- |--------|-------------|
160
- | **Copy error report** | Copies parsed, clean error output to clipboard |
161
- | **View full output** | Shows raw stderr from the failed hook |
162
- | **Skip hooks** | Re-runs `git commit --no-verify` with the same message |
163
- | **Re-stage & retry** | Runs `git add -A` again, then retries the commit |
164
- | **Edit message** | Opens a prompt to modify the commit message, then retries |
165
- | **Cancel** | Exits. Commit message is cached for `cmint --retry` |
174
+ - **Copy error report** copies the raw stderr (works with `wl-copy`,
175
+ `xclip`, `xsel`, or `pbcopy`).
176
+ - **View full error output** shows the raw stderr.
177
+ - **Retry checks** re-runs the same checks. Fix in another terminal, hit
178
+ enter, no restart.
179
+ - **Skip checks and commit** proceed to commit despite the failure.
180
+ - **Cancel** exit. The message is cached so `cmint -r` re-attempts with the
181
+ same message.
166
182
 
167
- Errors are parsed from **lint-staged**, **biome**, **TypeScript** (`tsc`), **vitest**/**jest**, and **ESLint**. Unrecognized output falls back to raw stderr.
183
+ For tsc failures specifically, the summary includes up to 3 file:line:column
184
+ diagnostics inline, with a `+N more` line if there are more.
168
185
 
169
- ## Pre-commit checks
186
+ ## Auto-group mode (`-a`)
170
187
 
171
- Define custom checks in a cmint config file at your project root. Supported file names (checked in priority order):
188
+ When you have 10 changed files across 3 concerns, `cmint -a` makes 3 commits,
189
+ each with its own message. The flow:
172
190
 
173
- `.cmintrc`, `.cmintrc.json`, `.cmintrc.{mjs,mts,js,ts,cjs,cts}`, `cmint.config.{mjs,mts,js,ts,cjs,cts}`
191
+ 1. Excluded files (lockfiles, build output) are committed upfront with a
192
+ hardcoded `chore: update lockfile` message.
193
+ 2. `.cmintrc` checks run on the remaining files.
194
+ 3. The AI groups files by intent.
195
+ 4. Each group is staged, diffed, and committed sequentially. A per-group
196
+ message is generated, and (in non-`auto` mode) reviewed.
197
+ 5. A hook failure on any group shows the recovery menu and stops the sequence
198
+ — the remaining groups are not committed.
174
199
 
175
- Checks run after staging, before AI message generation, so a failing check never wastes an API call.
200
+ `cmint` (no `-a`) on multiple files shows a staging menu:
176
201
 
177
- ```js
178
- export default {
179
- // String: matched files are appended as arguments
180
- "*.{js,ts,json}": "biome check --write --no-errors-on-unmatched",
181
-
182
- // Function: receive matched filenames, return command(s)
183
- "*.ts": () => ["tsc --noEmit", "vitest run --passWithNoTests"],
184
- };
202
+ ```
203
+ What do you want to stage?
204
+ Stage all files
205
+ Select files...
206
+ Auto-group into commits
207
+ Run checks
185
208
  ```
186
209
 
187
- Glob patterns use [picomatch](https://github.com/micromatch/picomatch). String commands receive matched files as trailing arguments. Functions receive the matched file list and return one or more commands to run.
210
+ ## Recovery menu
188
211
 
189
- ### TypeScript config
212
+ When a git hook blocks the commit, commit-mint parses the output and shows:
190
213
 
191
- Use `.cmintrc.ts` or `cmint.config.ts` for type safety without adding commit-mint as a project dependency:
214
+ ```
215
+ Pre-commit hook failed
216
+ • [biome] src/cli.ts — unused variable
217
+ • [vitest] 1 test failed in test/cli.test.ts
218
+
219
+ What do you want to do?
220
+ Copy error report to clipboard
221
+ View full error output
222
+ Skip hooks and commit (--no-verify)
223
+ Re-stage files and retry
224
+ Edit commit message
225
+ Cancel
226
+ ```
192
227
 
193
- ```ts
194
- interface Cmintrc {
195
- [glob: string]: string | string[] | ((filenames: string[]) => string | string[]);
196
- }
228
+ Six options, none are dead ends:
197
229
 
198
- export default {
199
- "*.{js,ts,json}": "biome check --write --no-errors-on-unmatched",
200
- "*.ts": () => ["tsc --noEmit", "vitest run --passWithNoTests"],
201
- } satisfies Cmintrc;
202
- ```
230
+ - **Copy error report** — raw stderr to clipboard, formatted for an AI agent.
231
+ - **View full error output** — show the unparsed stderr in a note.
232
+ - **Skip hooks** commit with `--no-verify`. Use when the failure is
233
+ understood and not worth blocking on.
234
+ - **Re-stage** — `git add -A`, retry the commit. Picks up fixes you make in
235
+ another terminal without restarting cmint. If re-stage still fails, the
236
+ menu re-shows the errors.
237
+ - **Edit** — tweak the AI message, then retry.
238
+ - **Cancel** — exit. The message is cached; `cmint -r` re-attempts with the
239
+ same message after you fix the underlying issue.
203
240
 
204
- This gives you editor autocomplete and catches invalid values at edit time no package install needed.
241
+ Hook progress is shown in real time during the commit`[STARTED]` /
242
+ `[COMPLETED]` / `[FAILED]` markers from each task are streamed to stderr as
243
+ they happen.
205
244
 
206
- Checks execute sequentially and fail fast. Each command has a 60-second timeout.
245
+ Errors are parsed from **lint-staged**, **biome**, **tsc**, **vitest**/**jest**,
246
+ and **eslint**. Unrecognized output falls back to a single raw-stderr entry.
207
247
 
208
- ### Check failure menu
248
+ ## Providers
209
249
 
210
- When a check fails, you get a menu with four options:
250
+ | Provider | Env var | Default model |
251
+ | -------- | ----------------- | -------------------- |
252
+ | Groq | `GROQ_API_KEY` | `openai/gpt-oss-20b` |
253
+ | Cerebras | `CEREBRAS_API_KEY` | `gpt-oss-120b` |
254
+ | Mistral | `MISTRAL_API_KEY` | `mistral-small` |
211
255
 
212
- | Option | What it does |
213
- |--------|-------------|
214
- | **Copy error report** | Copies the error output to clipboard |
215
- | **View full output** | Shows the raw check output |
216
- | **Skip checks** | Proceeds without running checks |
217
- | **Cancel** | Exits. Message is cached for `cmint --retry` |
256
+ All three use OpenAI-compatible APIs. Groq uses the official SDK; Cerebras and
257
+ Mistral use a built-in fetch client. Per-provider model overrides: set
258
+ `model_groq`, `model_cerebras`, or `model_mistral` in `~/.commit-mint`.
259
+ Resolution order is `model_<provider>` `model` provider default.
218
260
 
219
- Pass `--noCheck` or `-N` to skip checks entirely.
261
+ `cmint config` walks you through provider, API key, model, locale, and
262
+ timeout.
220
263
 
221
264
  ## Configuration
222
265
 
223
- Stored in `~/.commit-mint` (INI format). Set values via `cmint config set <key> <value>`.
224
-
225
- ```ini
226
- provider=groq
227
- GROQ_API_KEY=gsk_...
228
- model=openai/gpt-oss-20b
229
- locale=en
230
- max-length=100
231
- type=conventional
232
- timeout=10000
233
- proxy=
234
- ```
266
+ `~/.commit-mint` (INI format). Run `cmint config` to edit.
267
+
268
+ | Key | Default | Description |
269
+ | ---------------- | -------------------- | ------------------------------------------------- |
270
+ | `provider` | `groq` | `groq`, `cerebras`, or `mistral` |
271
+ | `model` | `openai/gpt-oss-20b` | Default model; overridable per provider |
272
+ | `model_groq` | — | Override default when provider is `groq` |
273
+ | `model_cerebras` | — | Override default when provider is `cerebras` |
274
+ | `model_mistral` | — | Override default when provider is `mistral` |
275
+ | `locale` | `en` | Locale for generated messages |
276
+ | `max-length` | `100` | Max commit message length |
277
+ | `type` | — | Force commit type prefix |
278
+ | `timeout` | `10000` | AI request timeout in ms |
279
+ | `proxy` | — | Proxy URL for API requests |
280
+
281
+ API key lookup checks the env var first, then the INI file.
235
282
 
236
- | Key | Default | Description |
237
- |-----|---------|-------------|
238
- | `provider` | `groq` | AI provider (`groq`, `cerebras`, or `mistral`) |
239
- | `GROQ_API_KEY` | — | Groq API key (or set `GROQ_API_KEY` env var) |
240
- | `CEREBRAS_API_KEY` | — | Cerebras API key (or set `CEREBRAS_API_KEY` env var) |
241
- | `MISTRAL_API_KEY` | — | Mistral API key (or set `MISTRAL_API_KEY` env var) |
242
- | `model` | `openai/gpt-oss-20b` | Default AI model for message generation |
243
- | `model_groq` | — | Model override for Groq provider |
244
- | `model_cerebras` | — | Model override for Cerebras provider |
245
- | `model_mistral` | — | Model override for Mistral provider |
246
- | `locale` | `en` | Locale for generated messages |
247
- | `max-length` | `100` | Maximum commit message length |
248
- | `type` | — | Commit type prefix (e.g. `conventional`) |
249
- | `timeout` | `10000` | AI request timeout in ms |
250
- | `proxy` | — | Proxy URL for API requests |
283
+ ## Excluded files
251
284
 
252
- Model resolution follows a chain: `model_<provider>` global `model` → provider default. Per-provider keys prevent cross-provider model leaks when switching providers.
285
+ These patterns are filtered from AI generation by default:
253
286
 
254
- ## Retry persistence
287
+ ```
288
+ package-lock.json
289
+ node_modules/** dist/** build/** .next/** coverage/**
290
+ *.log *.min.js *.min.css *.lock .DS_Store
291
+ ```
255
292
 
256
- Failed commit messages are cached to `~/.cache/commit-mint/<repo-hash>.json`. Running `cmint --retry` reuses the last message without regenerating. Fix errors in another terminal, come back, and retry.
293
+ When every staged file matches an exclude, commit-mint uses a hardcoded
294
+ message: `chore: update lockfile` for lockfiles, `chore: update generated
295
+ files` for the rest. In auto-group mode, lockfiles (`package-lock.json`,
296
+ `pnpm-lock.yaml`, `yarn.lock`, `bun.lock`, `bun.lockb`) are promoted
297
+ alongside their companion manifest (e.g. `package-lock.json` stays with
298
+ `package.json`).
257
299
 
258
300
  ## Requirements
259
301
 
260
- - **Node.js 18+**
261
- - **Git** (any modern version)
262
- - **Linux** (primary target; macOS works via `pbcopy`; WSL untested)
263
- - **xclip**, **wl-copy**, **xsel**, or **pbcopy** for clipboard support
302
+ - Node.js 18+
303
+ - git
304
+ - Optional, for clipboard copy: `wl-copy`, `xclip`, `xsel`, or `pbcopy`
264
305
 
265
- ## Non-goals
306
+ ## License
266
307
 
267
- - Not a git hook manager — cmint config checks run in-flow, not via git hooks. For git hooks, use husky or lefthook.
268
- - Not a linter/formatter — use biome, eslint, or prettier.
269
- - Not a git TUI — use lazygit or gitui.
270
- - Not a commitizen replacement — generates conventional commit messages via AI.
308
+ [MIT](LICENSE)