@hifullmoon/aicommit 1.4.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/.aicommit.config.example.json +118 -0
- package/CHANGELOG.md +131 -0
- package/LICENSE +21 -0
- package/README.md +406 -0
- package/README.zh-CN.md +408 -0
- package/SECURITY.md +33 -0
- package/bin/aicommit.js +47 -0
- package/docs/distribution.md +104 -0
- package/docs/examples/aicommit-policy.yml +24 -0
- package/docs/examples/commit-msg +4 -0
- package/docs/examples/extension/aicommit-extension.json +9 -0
- package/docs/examples/extension/index.mjs +32 -0
- package/docs/extensions.md +93 -0
- package/docs/privacy.md +58 -0
- package/docs/provider-compatibility.md +37 -0
- package/docs/provider-presets.md +100 -0
- package/docs/team-policy.md +86 -0
- package/docs/troubleshooting.md +37 -0
- package/package.json +100 -0
- package/presets/provider-presets.json +60 -0
- package/schemas/aicommit-extension.schema.json +27 -0
- package/schemas/aicommit-output.schema.json +86 -0
- package/schemas/aicommit-provider-presets.schema.json +56 -0
- package/schemas/aicommit-split-checkpoint.schema.json +92 -0
- package/schemas/aicommit-split-plan.schema.json +108 -0
- package/schemas/aicommit-team-policy.schema.json +59 -0
- package/src/api.js +740 -0
- package/src/cli.js +558 -0
- package/src/completion.js +136 -0
- package/src/config-command.js +59 -0
- package/src/config.js +524 -0
- package/src/context.js +537 -0
- package/src/credentials.js +123 -0
- package/src/doctor.js +131 -0
- package/src/errors.js +96 -0
- package/src/extension-runner.mjs +36 -0
- package/src/extensions.js +426 -0
- package/src/generation-ui.js +53 -0
- package/src/git.js +458 -0
- package/src/main.js +768 -0
- package/src/metrics.js +375 -0
- package/src/output.js +87 -0
- package/src/policy-command.js +172 -0
- package/src/policy.js +421 -0
- package/src/preset-command.js +91 -0
- package/src/provider-presets.js +361 -0
- package/src/providers.js +306 -0
- package/src/setup.js +268 -0
- package/src/split-checkpoint.js +252 -0
- package/src/split-hunks.js +263 -0
- package/src/split-plan.js +339 -0
- package/src/split.js +2285 -0
- package/src/team-policy.js +95 -0
- package/src/trust.js +31 -0
- package/src/ui.js +488 -0
- package/src/utils.js +165 -0
- package/templates/.aicommit.policy.json +22 -0
package/README.md
ADDED
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
# AICommit
|
|
2
|
+
|
|
3
|
+
[English](README.md) | [简体中文](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
AI-powered git commit message generator: reads your diff, asks an AI model for a conventional commit message, and commits after your confirmation.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install --global @hifullmoon/aicommit
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Or install with Homebrew:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
brew tap hi-fullmoon/aicommit https://github.com/hi-fullmoon/AICommit.git
|
|
17
|
+
brew install hi-fullmoon/aicommit/aicommit
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Requires Node.js >= 18.
|
|
21
|
+
|
|
22
|
+
See the bilingual [installation, upgrade, signature-verification, and rollback guide](docs/distribution.md). Both npm and Homebrew paths have automated install smoke tests.
|
|
23
|
+
|
|
24
|
+
To install a source checkout instead, run `npm install --global .` from the repository root.
|
|
25
|
+
|
|
26
|
+
## Configure
|
|
27
|
+
|
|
28
|
+
The fastest way is the interactive wizard:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
aicommit setup
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
It walks you through picking a provider from the active versioned preset manifest (bundled presets include OpenAI, DeepSeek, OpenRouter, MiniMax, Kimi Code, and Ollama) or entering a custom OpenAI-compatible endpoint, then entering your API key/model, choosing the commit language, and optionally testing the connection. Configuration is written atomically to the user config (`~/.aicommit.config.json`); a malformed existing file is backed up before replacement.
|
|
35
|
+
|
|
36
|
+
To configure by hand, start from [.aicommit.config.example.json](.aicommit.config.example.json). User config is loaded first, then allow-listed generation preferences from `./.aicommit.config.json` are deep-merged over it. Project config may set `language`, `commitPolicy`, `stripFiles`, `temperature`, and lower diff/token/timeout or repository-context ceilings. A project-owned `prompt` is ignored unless the user config explicitly sets `allowProjectPrompt: true`. Connection/provider fields (including `apiKeyEnv`), reasoning request controls, unknown keys, and attempts to raise a ceiling are ignored with a warning. This prevents a cloned repository from redirecting an authenticated request or silently increasing its cost/data scope.
|
|
37
|
+
|
|
38
|
+
To keep a key out of the JSON file, set `"apiKeyEnv": "OPENAI_API_KEY"` (and leave `apiKey` empty), or enter `env:OPENAI_API_KEY` in the setup wizard. Environment variables take priority over every other credential source and are recommended for CI and other stateless environments.
|
|
39
|
+
|
|
40
|
+
AICommit can also read from the Git credential helper already configured on your OS. Enable `credentialHelper.enabled`, store the provider credential through your normal Git/OS credential workflow, and AICommit will call `git credential fill` without prompting. The lookup username defaults to `aicommit` and can be changed with `credentialHelper.username`. Credential resolution order is environment variable → Git credential helper → plaintext user config → keyless localhost. A project config cannot enable a helper or select a credential source.
|
|
41
|
+
|
|
42
|
+
Multiple providers can be defined and switched at runtime with `-p` / `--provider`:
|
|
43
|
+
|
|
44
|
+
```json
|
|
45
|
+
{
|
|
46
|
+
"defaultProvider": "minimax",
|
|
47
|
+
|
|
48
|
+
"providers": {
|
|
49
|
+
"minimax": {
|
|
50
|
+
"providerType": "minimax",
|
|
51
|
+
"apiUrl": "https://api.minimaxi.com/v1/chat/completions",
|
|
52
|
+
"apiKeyEnv": "MINIMAX_API_KEY",
|
|
53
|
+
"modelId": "MiniMax-M3",
|
|
54
|
+
"extraBody": {
|
|
55
|
+
"thinking": { "type": "disabled" },
|
|
56
|
+
"reasoning_split": true
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"deepseek": {
|
|
60
|
+
"providerType": "deepseek",
|
|
61
|
+
"apiUrl": "https://api.deepseek.com/v1/chat/completions",
|
|
62
|
+
"apiKeyEnv": "DEEPSEEK_API_KEY",
|
|
63
|
+
"modelId": "deepseek-v4-flash"
|
|
64
|
+
},
|
|
65
|
+
"openrouter": {
|
|
66
|
+
"providerType": "openrouter",
|
|
67
|
+
"apiUrl": "https://openrouter.ai/api/v1/chat/completions",
|
|
68
|
+
"apiKeyEnv": "OPENROUTER_API_KEY",
|
|
69
|
+
"modelId": "openai/gpt-4o-mini"
|
|
70
|
+
},
|
|
71
|
+
"kimi-code": {
|
|
72
|
+
"providerType": "custom",
|
|
73
|
+
"apiUrl": "https://api.kimi.com/coding/v1/chat/completions",
|
|
74
|
+
"apiKeyEnv": "KIMI_API_KEY",
|
|
75
|
+
"modelId": "kimi-for-coding"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
The selected provider's values are deep-merged over the top-level keys, so shared settings (`language`, `commitPolicy`, `temperature`, `maxTokens`, ...) only need to be set once. Without `-p`, the `defaultProvider` is used (or the first entry in `providers` if `defaultProvider` is omitted). A flat single-model config (top-level `apiUrl`/`apiKey`/`modelId`, no `providers`) still works as before.
|
|
82
|
+
|
|
83
|
+
| Key | Description |
|
|
84
|
+
| -------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
85
|
+
| `providers` | Named provider configs (`apiUrl`/`apiKey`/`modelId`/...) |
|
|
86
|
+
| `defaultProvider` | Provider used when `-p` is not given (renamed from `default`) |
|
|
87
|
+
| `apiUrl` | OpenAI-compatible chat completions endpoint |
|
|
88
|
+
| `apiKey` | API key (empty string allowed for local models) |
|
|
89
|
+
| `apiKeyEnv` | Environment variable containing the API key; takes precedence over `apiKey` (default: empty) |
|
|
90
|
+
| `modelId` | Model identifier |
|
|
91
|
+
| `providerType` | Optional adapter override: `openai`, `openrouter`, `deepseek`, `minimax`, `ollama`, `custom`, or a user-installed `extension:<id>`; otherwise inferred from the endpoint |
|
|
92
|
+
| `commitPolicy` | Versioned commit rules for types, scope, subject length, body, breaking changes, and language |
|
|
93
|
+
| `prompt` | Optional user-approved guidance appended to the authoritative structured policy (default: empty) |
|
|
94
|
+
| `allowProjectPrompt` | User-owned opt-in for accepting `prompt` from project config (default: `false`) |
|
|
95
|
+
| `repositoryContext` | Total and per-category budgets for recent commits, package boundaries, trusted conventions, and commitlint detection |
|
|
96
|
+
| `language` | Commit message language, `zh` or `en` (default: `zh`) |
|
|
97
|
+
| `temperature` | Sampling temperature (default: `0.3`) |
|
|
98
|
+
| `maxTokens` | Max response tokens (default: `1024`) |
|
|
99
|
+
| `timeoutMs` | Per-request timeout in milliseconds (default: `120000`) |
|
|
100
|
+
| `retry` | Transient retry limits: `maxAttempts`, `baseDelayMs`, and `maxDelayMs` (defaults: `3`, `500`, and `5000`) |
|
|
101
|
+
| `credentialHelper` | Opt in to `git credential fill` with `enabled` and `username` (defaults: `false` and `aicommit`) |
|
|
102
|
+
| `metrics` | Local-only metrics controls: `enabled`, absolute `path` or empty for the default, and `maxEntries` (defaults: `true`, empty, and `500`) |
|
|
103
|
+
| `extensions` | User-owned absolute manifest paths plus execution timeout/context ceiling; repository config cannot enable or redirect extensions |
|
|
104
|
+
| `maxDiffChars` | Diff chars sent to the model per call; oversized diffs become a `--stat` summary + truncated hunks (default: `30000`) |
|
|
105
|
+
| `maxFileDiffChars` | Cap on a single file's diff section; bigger sections are truncated to their leading hunks so one huge file can't crowd out the rest (default: `3000`) |
|
|
106
|
+
| `splitMaxDiffChars` | Diff chars sent to the split-planning call; split mode needs less hunk detail than final message generation (default: `16000`) |
|
|
107
|
+
| `splitMaxPlanFiles` | Number of changed files shown to the split planner before extra files are swept into a catch-all commit (default: `100`) |
|
|
108
|
+
| `diffContextLines` | Context lines around each diff hunk (`git diff --unified=<n>`); lower values mean fewer tokens (default: `1`) |
|
|
109
|
+
| `stripFiles` | Extra files to stub out of the diff like lock files, matched by basename with `*`/`?` wildcards, e.g. `["*.min.js", "*.map", "*.snap"]` (default: `[]`; project-level entries are merged with user-level ones, not replaced) |
|
|
110
|
+
| `regenerateWithDiff` | `true` re-sends the full diff on every regenerate for more varied rewrites; `false` (default) only asks the model to reword its previous message, which is far cheaper |
|
|
111
|
+
| `extraBody` | Extra provider-specific JSON fields merged into the request body, except `model`/`messages` (default: `{}`); standard requests send no vendor extensions unless explicitly configured |
|
|
112
|
+
| `reasoning` | Reasoning controls: `mode`, `effort`, `maxTokens`, and `maxDisplayChars`; defaults to `mode: "on"` and streams reasoning automatically |
|
|
113
|
+
|
|
114
|
+
Works with OpenAI, DeepSeek, [OpenRouter](https://openrouter.ai), MiniMax, [Kimi Code](https://www.kimi.com/code/docs/), Ollama (native `/api/chat` or OpenAI-compatible `/v1/chat/completions`), LiteLLM, and other compatible endpoints. HTTPS is required for remote endpoints; plaintext HTTP is accepted only for localhost/loopback.
|
|
115
|
+
|
|
116
|
+
### Kimi Code example
|
|
117
|
+
|
|
118
|
+
Create an API key in the Kimi Code console, export it without storing the secret in JSON, and select the bundled preset in `aicommit setup`. For a manual configuration, use the OpenAI-compatible full endpoint:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
export KIMI_API_KEY='your-kimi-code-api-key'
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
```json
|
|
125
|
+
{
|
|
126
|
+
"defaultProvider": "kimi-code",
|
|
127
|
+
"providers": {
|
|
128
|
+
"kimi-code": {
|
|
129
|
+
"providerType": "custom",
|
|
130
|
+
"apiUrl": "https://api.kimi.com/coding/v1/chat/completions",
|
|
131
|
+
"apiKeyEnv": "KIMI_API_KEY",
|
|
132
|
+
"modelId": "kimi-for-coding"
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Verify the endpoint, key, and model before the first commit:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
aicommit doctor -p kimi-code
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
`kimi-for-coding` is available to all Kimi Code membership tiers and follows the service's rolling model upgrades. Kimi Code membership keys use `api.kimi.com`; Kimi Platform pay-as-you-go keys use a different endpoint and are not interchangeable.
|
|
145
|
+
|
|
146
|
+
See the bilingual [provider compatibility table](docs/provider-compatibility.md) for streaming, reasoning, token-budget, usage, authentication, preset, and extension-adapter boundaries.
|
|
147
|
+
|
|
148
|
+
### Repository policy and bounded context
|
|
149
|
+
|
|
150
|
+
The default generation contract is structured and versioned instead of being embedded in a free-form prompt. A user config can replace declaration arrays such as `types` and `scope.values` to make them stricter:
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"commitPolicy": {
|
|
155
|
+
"version": 1,
|
|
156
|
+
"types": ["feat", "fix", "docs", "refactor", "test", "chore"],
|
|
157
|
+
"scope": { "mode": "optional", "values": ["api", "cli"] },
|
|
158
|
+
"subject": { "maxLength": 72 },
|
|
159
|
+
"body": { "mode": "optional", "maxLines": 8 },
|
|
160
|
+
"breakingChange": "allow",
|
|
161
|
+
"language": "inherit"
|
|
162
|
+
},
|
|
163
|
+
"allowProjectPrompt": false,
|
|
164
|
+
"repositoryContext": {
|
|
165
|
+
"enabled": true,
|
|
166
|
+
"maxChars": 4000,
|
|
167
|
+
"recentCommits": { "enabled": true, "count": 12, "maxChars": 1000 },
|
|
168
|
+
"packageBoundaries": { "enabled": true, "maxEntries": 40, "maxChars": 800 },
|
|
169
|
+
"conventions": {
|
|
170
|
+
"enabled": true,
|
|
171
|
+
"trustedFiles": ["CONTRIBUTING.md"],
|
|
172
|
+
"maxFiles": 4,
|
|
173
|
+
"maxChars": 1400
|
|
174
|
+
},
|
|
175
|
+
"commitlint": { "enabled": true, "maxChars": 800 }
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
Each context category and the whole feature can be disabled independently. `conventions.trustedFiles` is accepted only from user-owned config; paths must stay inside the repository and resolve to regular, non-symlinked files. Project config can disable sources or lower existing ceilings, but cannot add trusted files, re-enable a user-disabled source, or raise any budget. Recognized scalar commitlint rules can set repository-specific types/scopes and lower the subject limit; commitlint files are read as data and never executed. Before a provider call, the terminal shows the categories, counts, and total characters selected.
|
|
181
|
+
|
|
182
|
+
Generated candidates are checked locally for policy format, type/scope, subject and body limits, breaking-change markers, and explicit language. A hard failure gets at most one low-cost correction request without re-sending the diff. Keyword/path alignment with the bounded diff is reported as an advisory warning because it is heuristic.
|
|
183
|
+
|
|
184
|
+
For a deterministic team gate, generate and commit the strict credential-free policy document, then use the same validator from a local `commit-msg` hook and CI:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
aicommit policy template > .aicommit.policy.json
|
|
188
|
+
aicommit policy check --file=.git/COMMIT_EDITMSG
|
|
189
|
+
aicommit policy check --range=origin/main..HEAD --output=json
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
The complete team policy loads after personal settings. When one is present, `-l`/`--lang` is rejected instead of overriding the repository language. Machine output includes a policy fingerprint and issue codes but omits commit-message contents; policy commands never resolve credentials. See the bilingual [team migration guide and executable examples](docs/team-policy.md), plus the published [team-policy schema](schemas/aicommit-team-policy.schema.json).
|
|
193
|
+
|
|
194
|
+
### Provider reliability
|
|
195
|
+
|
|
196
|
+
Every provider adapter maps the same generation contract: messages, streaming, reasoning controls, output-token budget, normalized usage (`inputTokens`, `outputTokens`, `totalTokens`), and finish reason. Endpoint detection normally selects the adapter; set `providerType` when a compatible service uses a custom domain.
|
|
197
|
+
|
|
198
|
+
Requests retry only transient failures: HTTP 429, recoverable 5xx responses, network interruption, and interrupted response bodies. Retries are bounded by `retry.maxAttempts`, use capped exponential backoff, and honor `Retry-After` when present. Authentication, invalid-parameter, and content-safety failures are returned immediately without retrying.
|
|
199
|
+
|
|
200
|
+
### Versioned provider presets
|
|
201
|
+
|
|
202
|
+
Setup defaults live in a strict manifest separate from request adapters and the Git/interaction flow. A compatible provider can be added by updating preset data and referencing an existing adapter:
|
|
203
|
+
|
|
204
|
+
```bash
|
|
205
|
+
aicommit preset show
|
|
206
|
+
aicommit preset validate --file=provider-presets.json
|
|
207
|
+
aicommit preset install --file=provider-presets.json
|
|
208
|
+
aicommit preset rollback
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
The active user manifest is `~/.aicommit/provider-presets.json`; each update keeps the previous valid version for rollback. Manifests declare their own semantic version, supported core range, and adapter-contract version, and cannot contain credentials. Core prerelease versions and build metadata are parsed using SemVer rules; build metadata does not affect compatibility ordering. See the bilingual [preset compatibility/update guide](docs/provider-presets.md) and [published schema](schemas/aicommit-provider-presets.schema.json).
|
|
212
|
+
|
|
213
|
+
### Credential-denied extensions
|
|
214
|
+
|
|
215
|
+
Three minimal extension interfaces are available: bounded repository context, commit-message validation, and provider request/response adaptation. User-installed single-file ESM extensions run outside the CLI process under Node's permission model and declare `credentials: false`; they receive neither resolved credentials nor inherited secret environment variables. Repository config cannot install or select extension code. Node.js 20+ is required only when executable extensions are enabled; the core CLI remains compatible with Node.js 18. See the bilingual [extension contract, security model, and executable example](docs/extensions.md), plus the [manifest schema](schemas/aicommit-extension.schema.json).
|
|
216
|
+
|
|
217
|
+
### Saving tokens
|
|
218
|
+
|
|
219
|
+
Token spend per call is dominated by the diff; aicommit already strips lock files, condenses oversized diffs, and never re-sends the diff on regenerate or retry. To trim further:
|
|
220
|
+
|
|
221
|
+
- Add generated artifacts to `stripFiles` (e.g. `["*.min.js", "*.map", "*.snap"]`) — their content is replaced with a one-line stub.
|
|
222
|
+
- Lower `maxDiffChars` (e.g. `15000`) if your commits are usually small.
|
|
223
|
+
- `diffContextLines` defaults to `1`; set it to `0` to send only changed lines with no context.
|
|
224
|
+
- Lower or disable individual `repositoryContext` categories when their style signal is not useful for your repository.
|
|
225
|
+
|
|
226
|
+
## Privacy and data flow
|
|
227
|
+
|
|
228
|
+
The bilingual [privacy model](docs/privacy.md) maps every local, provider, extension, metric, and distribution trust boundary. The summary below covers the default runtime path.
|
|
229
|
+
|
|
230
|
+
AICommit has no hosted backend and no metrics-upload implementation. At runtime it only makes generation requests to the `apiUrl` selected from your user-owned provider configuration. The API key is sent to that endpoint as authorization; verify custom endpoints before trusting them with credentials or repository content.
|
|
231
|
+
|
|
232
|
+
Commit-generation requests can contain:
|
|
233
|
+
|
|
234
|
+
- the configured system prompt and requested commit language;
|
|
235
|
+
- changed file paths/statuses and the staged diff in normal mode;
|
|
236
|
+
- changed file paths/statuses, tracked diffs, and bounded text previews of untracked files in split mode;
|
|
237
|
+
- bounded recent commit subjects, package boundaries, explicitly trusted convention excerpts, and recognized commitlint constraints when their context categories are enabled;
|
|
238
|
+
- the previous generated message when asking for a lower-cost rewrite;
|
|
239
|
+
- a small fixed prompt when `aicommit doctor` performs its live connectivity check.
|
|
240
|
+
|
|
241
|
+
AICommit does not intentionally send unrelated repository files, historical commit bodies, environment variables, or its local configuration file. Every selected diff, path list, history sample, preview, and convention excerpt is placed inside an explicit JSON envelope marked as untrusted data; the authoritative system policy instructs the model never to follow embedded repository instructions. Lock files, configured `stripFiles`, oversized sections, common sensitive filenames, private-key material, cloud access-key IDs, and credential-like assignments are omitted, truncated, or redacted before the default request. The interactive warning still allows explicitly sending the original diff, so review that choice carefully. Detection and prompt boundaries are guardrails, not complete secret or prompt-injection defenses.
|
|
242
|
+
|
|
243
|
+
Project-level configuration is treated as untrusted: it cannot change the endpoint, provider, credentials, retry policy, metrics, reasoning request controls, or increase user-configured data/cost ceilings. Prefer `apiKeyEnv` or the OS-backed Git credential helper for credentials. The setup wizard can save a literal key in the user config when requested; that file is written atomically with owner-only permissions where the OS supports them.
|
|
244
|
+
|
|
245
|
+
Successful and failed commit runs write a minimal local JSONL metric by default to `~/.aicommit/metrics.jsonl`. Each record contains exactly duration, normalized token usage, a bounded result category, whether the message was edited, and the rewrite count (including automatic policy correction). It never contains the diff, reasoning, commit message, file names, provider, model, or credentials. The file retains the newest 500 records by default and is written with owner-only permissions where supported.
|
|
246
|
+
|
|
247
|
+
Use `aicommit stats` to view first-pass acceptance, edit/rewrite/failure rates, P50/P95 latency, token totals, and recent-vs-previous trends. After ten successful runs it compares two chronological baseline windows and reports progress toward the roadmap's 20% relative edit/rewrite-rate improvement target. `aicommit stats clear|enable|disable` manages the same local store; clearing is permanent. Set `metrics.enabled` to `false`, choose an absolute `metrics.path`, or change `metrics.maxEntries` in the user config. Project config cannot override these settings, and there is no upload implementation.
|
|
248
|
+
|
|
249
|
+
## Usage
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
aicommit setup # interactive configuration wizard
|
|
253
|
+
aicommit doctor # diagnose runtime, config, credentials, and connectivity
|
|
254
|
+
aicommit config show # show the effective config with secrets redacted
|
|
255
|
+
aicommit config validate # validate config without resolving credentials
|
|
256
|
+
aicommit config path # print user and project config paths
|
|
257
|
+
aicommit completion bash # generate Bash completion on stdout
|
|
258
|
+
aicommit stats # show local quality, latency, and token trends
|
|
259
|
+
aicommit stats clear # permanently clear local metric history
|
|
260
|
+
aicommit # generate & commit in current directory
|
|
261
|
+
aicommit /path/to/repo # or a target directory
|
|
262
|
+
aicommit split run # choose staged/all scope, then split logical commits
|
|
263
|
+
aicommit split run --scope=staged # split only the reviewed index snapshot
|
|
264
|
+
aicommit split run --scope=all # split the complete working-tree snapshot
|
|
265
|
+
aicommit split run --scope=staged --split-hunks # experimental same-file hunk splitting
|
|
266
|
+
aicommit --dry-run # generate and review without creating a commit
|
|
267
|
+
aicommit split run --dry-run # review a split plan without creating commits
|
|
268
|
+
aicommit --yes # non-interactively commit already staged changes
|
|
269
|
+
aicommit --yes --dry-run # non-interactively preview all changes; restores staging
|
|
270
|
+
aicommit split run --scope=all --yes # non-interactively plan and commit all working-tree changes
|
|
271
|
+
aicommit split plan --scope=staged --file=/tmp/split-plan.json --yes
|
|
272
|
+
aicommit split apply --file=/tmp/split-plan.json --yes
|
|
273
|
+
aicommit split resume --yes # resume an interrupted split transaction
|
|
274
|
+
aicommit split abort --yes # discard a stale checkpoint; keep commits and changes
|
|
275
|
+
aicommit --reasoning=low # stream low-effort reasoning; Ctrl+O expands/collapses it
|
|
276
|
+
aicommit --no-reasoning # explicitly disable reasoning when supported
|
|
277
|
+
aicommit -l zh # commit message language
|
|
278
|
+
aicommit -p deepseek # switch to the "deepseek" provider
|
|
279
|
+
aicommit --yes --output=json # emit one schema-validated JSON result on stdout
|
|
280
|
+
aicommit -h # help
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
| Option | Description |
|
|
284
|
+
| ------------------ | ---------------------------------------------------------------------------- |
|
|
285
|
+
| `-l`, `--lang` | Commit message language (`zh` or `en`) |
|
|
286
|
+
| `-p`, `--provider` | Use the named provider from `providers` |
|
|
287
|
+
| `--split-hunks` | Opt in to experimental same-file text-hunk planning; disabled by default |
|
|
288
|
+
| `--scope` | `staged` or `all` scope for `aicommit split run` and `aicommit split plan` |
|
|
289
|
+
| `--file` | JSON plan path for `aicommit split plan` and `aicommit split apply` |
|
|
290
|
+
| `--dry-run` | Generate and review a message or split plan without creating commits |
|
|
291
|
+
| `-y`, `--yes` | Accept without prompts; normal mode requires explicitly staged changes |
|
|
292
|
+
| `--reasoning` | Enable reasoning with `low`, `medium`, `high`, `xhigh`, or `max` effort |
|
|
293
|
+
| `--no-reasoning` | Explicitly disable reasoning when the selected provider/model supports it |
|
|
294
|
+
| `--output` | `text` (default) or one JSON object; commit/split JSON flows require `--yes` |
|
|
295
|
+
| `-v`, `--version` | Show version |
|
|
296
|
+
| `-h`, `--help` | Show help |
|
|
297
|
+
|
|
298
|
+
### Configuration inspection
|
|
299
|
+
|
|
300
|
+
`aicommit config show|validate|path` can run outside a repository and accepts an optional target directory. `show` applies the same user/project/team-policy trust filtering and provider selection as commit generation, but recursively masks secrets. `validate` parses, merges, and validates configuration without reading environment credentials or invoking Git credential helpers, making `aicommit config validate --output=json` safe for CI. `path` reports user config, project config, and team-policy locations even when a config file is malformed. `show` and `validate` accept `--provider=<name>`.
|
|
301
|
+
|
|
302
|
+
### Shell completion
|
|
303
|
+
|
|
304
|
+
Completion scripts are generated from the installed CLI and contain no configuration or credentials:
|
|
305
|
+
|
|
306
|
+
```bash
|
|
307
|
+
# Bash
|
|
308
|
+
aicommit completion bash > ~/.local/share/bash-completion/completions/aicommit
|
|
309
|
+
|
|
310
|
+
# Zsh (ensure the destination directory is in $fpath)
|
|
311
|
+
aicommit completion zsh > ~/.zfunc/_aicommit
|
|
312
|
+
|
|
313
|
+
# Fish
|
|
314
|
+
aicommit completion fish > ~/.config/fish/completions/aicommit.fish
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### Machine-readable output
|
|
318
|
+
|
|
319
|
+
Use `--output=json` for scripts and CI. Commit and split flows also require `--yes`, preventing a machine consumer from hanging on an interactive prompt. stdout contains exactly one JSON object; progress, debug details, and diagnostics go to stderr. `doctor --output=json` does not require `--yes`.
|
|
320
|
+
|
|
321
|
+
```json
|
|
322
|
+
{
|
|
323
|
+
"schemaVersion": "1.0",
|
|
324
|
+
"ok": true,
|
|
325
|
+
"message": "fix: handle provider retry limits",
|
|
326
|
+
"plan": null,
|
|
327
|
+
"provider": "openai",
|
|
328
|
+
"model": "gpt-4o",
|
|
329
|
+
"latencyMs": 842,
|
|
330
|
+
"usage": {
|
|
331
|
+
"inputTokens": 420,
|
|
332
|
+
"outputTokens": 18,
|
|
333
|
+
"totalTokens": 438
|
|
334
|
+
},
|
|
335
|
+
"warnings": [],
|
|
336
|
+
"exitReason": "dry_run",
|
|
337
|
+
"committed": false,
|
|
338
|
+
"error": null
|
|
339
|
+
}
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
The published [JSON schema](schemas/aicommit-output.schema.json) covers success, split-plan, doctor/check, and error results. Machine output never includes the diff or model reasoning. Split output exposes only each group message and its assigned paths.
|
|
343
|
+
|
|
344
|
+
Stable process exits are shared by text and JSON modes:
|
|
345
|
+
|
|
346
|
+
| Exit | Category | Meaning |
|
|
347
|
+
| ----- | ----------------------- | --------------------------------------------- |
|
|
348
|
+
| `0` | success | Completed, previewed, or cancelled by policy |
|
|
349
|
+
| `1` | internal | Unexpected internal failure |
|
|
350
|
+
| `2` | config | Arguments, config, or credential setup |
|
|
351
|
+
| `3` | git_state | Repository, index, or commit state |
|
|
352
|
+
| `4` | network | DNS, connection, timeout, or transport |
|
|
353
|
+
| `5` | provider | Provider HTTP/API failure |
|
|
354
|
+
| `6` | response_format | Invalid or unusable model response |
|
|
355
|
+
| `7` | sensitive_data | Non-interactive safety boundary |
|
|
356
|
+
| `8` | concurrent_modification | Protected Git state changed during generation |
|
|
357
|
+
| `130` | interrupt | Interrupted with Ctrl+C |
|
|
358
|
+
|
|
359
|
+
### Diagnostics
|
|
360
|
+
|
|
361
|
+
`aicommit doctor` checks the running Node.js and Git versions, loaded config sources, endpoint security, selected adapter capabilities, redacted credential source, and a live provider connection. It prints source labels such as `env:OPENAI_API_KEY`, `git credential helper`, or `keyless localhost`, never the credential value. Endpoint userinfo, credential-like query parameters, and fragments are also redacted from normal output and credential-resolution errors. Use `aicommit doctor -p <name>` to select a configured provider or `aicommit doctor --output=json` in automation.
|
|
362
|
+
|
|
363
|
+
For stable error categories, Homebrew/npm verification failures, split recovery, preset compatibility, and extension isolation failures, use the bilingual [troubleshooting matrix](docs/troubleshooting.md).
|
|
364
|
+
|
|
365
|
+
Flow: reads the staged diff, sends it to the AI, then lets you **accept** (Enter), **edit** (`e`), or **cancel** (`n`). If nothing is staged but the working tree has unstaged or untracked changes, aicommit offers to stage them for you — all at once (`git add -A`) or file by file — before continuing. Once anything is staged, that index snapshot is authoritative; other working-tree changes are left untouched.
|
|
366
|
+
|
|
367
|
+
`--dry-run` follows the same review flow but stops before `git commit`. Any staging performed by aicommit is restored before it exits. Cancellation and failures use the same index transaction; if another process changed the index concurrently, aicommit leaves it untouched instead of overwriting that work.
|
|
368
|
+
|
|
369
|
+
Before repository content is sent, aicommit detects common sensitive filenames, private-key material, cloud access-key IDs, and credential-like assignments. Split mode scans the complete byte stream of each untracked regular file for these patterns while keeping the model preview bounded; the request reuses that captured preview instead of reopening the file. The default protected request omits sensitive file/private-key sections and redacts detected values; you can cancel or explicitly send the original diff. Untracked symbolic links and non-regular files are never opened for previews. In non-interactive split mode, detection fails closed before the API call because `split run --scope=all --yes` would otherwise auto-stage the sensitive file. This is a safety net, not a replacement for a dedicated secret scanner.
|
|
370
|
+
|
|
371
|
+
The staged index (or complete split-mode working tree, including untracked file bytes) is fingerprinted during generation and checked again immediately before committing. If it changed, the commit is aborted so the generated message cannot describe a different snapshot.
|
|
372
|
+
|
|
373
|
+
Reasoning defaults to `on` with `medium` effort. It is mapped natively for OpenAI reasoning models, DeepSeek, OpenRouter, and MiniMax; models that do not expose reasoning continue normally and show an unavailable notice instead of failing. Official OpenAI endpoints validate the selected effort against the model generation before sending the request, so unsupported combinations such as `o3 --no-reasoning` or `gpt-5.1 --reasoning=max` fail locally with a clear list of supported levels. DeepSeek's current `deepseek-v4-flash` and `deepseek-v4-pro` models receive `thinking: { "type": "enabled" }` plus `reasoning_effort`; `medium`/`xhigh` are normalized to DeepSeek's `high` level.
|
|
374
|
+
|
|
375
|
+
When reasoning mode is `on` (including via `--reasoning=<level>`), aicommit requests a streaming response and displays reasoning as it arrives. The live view follows the newest two terminal lines by default; press `Ctrl+O` to expand or collapse the accumulated text during generation or review. Long expanded output is kept inside the terminal viewport—use `PageUp`/`PageDown` to read every page. Holding `Ctrl+O` counts as one toggle, so key repeat cannot leave duplicate panels behind. Output is sanitized and capped by `reasoning.maxDisplayChars`; providers that do not expose reasoning show a short unavailable notice.
|
|
376
|
+
|
|
377
|
+
```json
|
|
378
|
+
{
|
|
379
|
+
"reasoning": {
|
|
380
|
+
"mode": "on",
|
|
381
|
+
"effort": "medium",
|
|
382
|
+
"maxTokens": 4096,
|
|
383
|
+
"maxDisplayChars": 12000,
|
|
384
|
+
"enabledBody": { "enable_thinking": true },
|
|
385
|
+
"disabledBody": { "enable_thinking": false }
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Split mode
|
|
391
|
+
|
|
392
|
+
`aicommit split run` asks whether to group the staged index snapshot or all staged, unstaged, and untracked changes into logical commits. Use `--scope=staged` or `--scope=all` when the boundary must be explicit, including every non-interactive run. You can review the plan, regenerate messages for selected groups, or edit the plan as JSON before committing. Extension validation errors are shown with the plan and must be corrected by editing or regenerating before commit. Sensitive-content detection fails closed before a non-interactive provider request or automatic staging.
|
|
393
|
+
|
|
394
|
+
For an auditable two-step flow, `aicommit split plan --scope=staged|all --file=<path>` exports a versioned JSON artifact, and `aicommit split apply --file=<path>` rechecks its base commit, change set, and content fingerprint before touching the index. Keep plan files outside the worktree or under `.git` so they cannot become part of their own plan.
|
|
395
|
+
|
|
396
|
+
Execution uses temporary indexes and a code-free checkpoint under `.git/aicommit`. A hook, Git error, interruption, or crash leaves completed commits in history and preserves the pending snapshot; the failure report shows checkpointed, in-flight, pending, and current worktree/index state. Resolve the cause and run `aicommit split resume`. Resume reconciles the possible post-commit crash window before creating anything else, so a completed group is neither duplicated nor omitted. If you intentionally finished or replaced the interrupted work through another Git workflow, run `aicommit split abort`; it removes only the stale checkpoint and never rewrites HEAD, the index, or the worktree. New committing split runs detect a checkpoint before contacting the provider. If planning or preflight fails before the first group, no split commit is created and the real index remains unchanged.
|
|
397
|
+
|
|
398
|
+
Split remains file-level by default. `--split-hunks` opts in to experimental same-file splitting for tracked text modifications with multiple unified-diff hunks. The JSON plan and checkpoint store only hunk IDs, line ranges, and hashes—not patch content. Before the first commit, AICommit applies every selected patch to a temporary index and requires the final tree to reproduce the captured target blobs exactly; parsing, patching, binary/mode-change, or lossless-validation failures fall back to a file-level plan. The worktree is never modified by hunk execution.
|
|
399
|
+
|
|
400
|
+
## Development and releases
|
|
401
|
+
|
|
402
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for local development and pull-request checks, [SECURITY.md](SECURITY.md) for private vulnerability reporting, [RELEASING.md](RELEASING.md) for the executable maintainer process, and the bilingual [distribution guide](docs/distribution.md) for npm/Homebrew install, verification, and user rollback. Releases require a GitHub-verified signed tag, Sigstore/GitHub attestations for the exact npm tarball and SPDX SBOM, npm Trusted Publishing provenance, SHA-256-pinned Homebrew formula, and post-publish smoke tests. `npm run eval` runs the anonymous local quality corpus covering single and mixed changes, renames, generated files, long diffs, Chinese/English output, and malformed weak-model candidates; it is also part of `npm run ci`.
|
|
403
|
+
|
|
404
|
+
## License
|
|
405
|
+
|
|
406
|
+
[MIT](LICENSE)
|