@thankarezos/git-ai-commit 0.1.1 → 0.1.3
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 +3 -0
- package/bin/git-aic.js +81 -10
- package/bin/presets.js +5 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,12 +44,14 @@ First run launches an **interactive wizard** that asks you to pick a provider, e
|
|
|
44
44
|
| `-a`, `--add` | Run `git add -A` before generating |
|
|
45
45
|
| `-p "..."`, `--prompt "..."` | Append extra instructions to the AI prompt |
|
|
46
46
|
| `-ap "..."`, `-pa "..."` | Combine `-a` and `-p` |
|
|
47
|
+
| `--provider <name>`, `-P <name>` | One-off provider override. `<name>` matches a preset command (`claude`, `gemini`, `codex`, `opencode`, `llm`, `ollama`). |
|
|
47
48
|
| `--no-commit` | Generate and edit, but skip the `git commit` |
|
|
48
49
|
| `--commit` | Force commit (overrides `commit: false` in config) |
|
|
49
50
|
| `--require-edit` | Refuse to commit if the saved message is byte-identical to what the AI produced |
|
|
50
51
|
| `--no-require-edit` | Allow committing the AI message unchanged |
|
|
51
52
|
| `--init` | Run the interactive setup wizard |
|
|
52
53
|
| `--config` | Print the active config path and contents |
|
|
54
|
+
| `-v`, `--version` | Print the package version |
|
|
53
55
|
| `-h` | Show usage. (`--help` is intercepted by git, so use `-h`.) |
|
|
54
56
|
|
|
55
57
|
## How it decides to commit
|
|
@@ -100,6 +102,7 @@ The wizard ships with presets for:
|
|
|
100
102
|
- **Claude Code** — `claude -p "{prompt}"` (reads diff from stdin)
|
|
101
103
|
- **Gemini CLI** — `gemini -p "{prompt}"`
|
|
102
104
|
- **Codex CLI** — `codex exec --skip-git-repo-check "{prompt}"`
|
|
105
|
+
- **OpenCode** — `opencode run "{prompt}"`
|
|
103
106
|
- **llm** (Simon Willison) — `llm "{prompt}"`
|
|
104
107
|
- **Ollama** — `ollama run llama3 "{prompt}"`
|
|
105
108
|
- **Custom** — type your own `command` and `args`
|
package/bin/git-aic.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { execFileSync, spawnSync } from "node:child_process";
|
|
4
4
|
import {
|
|
5
5
|
existsSync,
|
|
6
6
|
mkdtempSync,
|
|
@@ -18,6 +18,7 @@ import { extractCommitMessage } from "./extract.js";
|
|
|
18
18
|
import { runProvider } from "./run-provider.js";
|
|
19
19
|
import { applyUserOverrides, getConfiguration } from "./prompts.js";
|
|
20
20
|
import { getConfigPath, loadConfig } from "./get-config-path.js";
|
|
21
|
+
import { PROVIDER_PRESETS } from "./presets.js";
|
|
21
22
|
|
|
22
23
|
function fail(message, code = 1) {
|
|
23
24
|
console.error(message);
|
|
@@ -36,8 +37,10 @@ function parseArgs(argv) {
|
|
|
36
37
|
let shouldCommit = null;
|
|
37
38
|
let requireEdit = null;
|
|
38
39
|
let printConfig = false;
|
|
40
|
+
let printVersion = false;
|
|
39
41
|
let runInit = false;
|
|
40
42
|
let shouldAdd = false;
|
|
43
|
+
let providerName = null;
|
|
41
44
|
|
|
42
45
|
for (let i = 0; i < argv.length; i++) {
|
|
43
46
|
const arg = argv[i];
|
|
@@ -58,6 +61,20 @@ function parseArgs(argv) {
|
|
|
58
61
|
continue;
|
|
59
62
|
}
|
|
60
63
|
|
|
64
|
+
if (arg === "--provider" || arg === "-P") {
|
|
65
|
+
const next = argv[i + 1];
|
|
66
|
+
if (!next || next.startsWith("-")) {
|
|
67
|
+
console.log("Available providers:");
|
|
68
|
+
for (const p of PROVIDER_PRESETS) {
|
|
69
|
+
console.log(` ${p.command.padEnd(10)} ${p.name}`);
|
|
70
|
+
}
|
|
71
|
+
process.exit(0);
|
|
72
|
+
}
|
|
73
|
+
providerName = next;
|
|
74
|
+
i++;
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
|
|
61
78
|
if (arg === "--no-commit") {
|
|
62
79
|
shouldCommit = false;
|
|
63
80
|
continue;
|
|
@@ -83,6 +100,11 @@ function parseArgs(argv) {
|
|
|
83
100
|
continue;
|
|
84
101
|
}
|
|
85
102
|
|
|
103
|
+
if (arg === "-v" || arg === "--version") {
|
|
104
|
+
printVersion = true;
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
|
|
86
108
|
if (arg === "--init") {
|
|
87
109
|
runInit = true;
|
|
88
110
|
continue;
|
|
@@ -92,11 +114,14 @@ function parseArgs(argv) {
|
|
|
92
114
|
console.log(`
|
|
93
115
|
Usage:
|
|
94
116
|
git aic
|
|
95
|
-
git aic -a
|
|
117
|
+
git aic -a # stage all changes first (git add -A)
|
|
96
118
|
git aic -p "extra prompt"
|
|
97
|
-
git aic -ap "extra prompt"
|
|
119
|
+
git aic -ap "extra prompt" # combine -a and -p
|
|
120
|
+
git aic --provider gemini # one-off provider override (also -P)
|
|
121
|
+
git aic --provider # list available providers
|
|
98
122
|
git aic --no-commit
|
|
99
123
|
git aic --config
|
|
124
|
+
git aic -v, --version
|
|
100
125
|
git aic --init
|
|
101
126
|
|
|
102
127
|
Examples:
|
|
@@ -105,7 +130,8 @@ Examples:
|
|
|
105
130
|
git aic -p "prefer docs(specs), mention Asset Management API"
|
|
106
131
|
git aic -ap "mention Asset Management API"
|
|
107
132
|
git aic --no-commit -p "only generate the message"
|
|
108
|
-
git aic --
|
|
133
|
+
git aic --provider claude # use Claude Code for this run
|
|
134
|
+
git aic --init # interactive config wizard
|
|
109
135
|
|
|
110
136
|
Config:
|
|
111
137
|
~/.config/git-aic/config.json
|
|
@@ -124,8 +150,10 @@ Environment:
|
|
|
124
150
|
shouldCommit,
|
|
125
151
|
requireEdit,
|
|
126
152
|
printConfig,
|
|
153
|
+
printVersion,
|
|
127
154
|
runInit,
|
|
128
155
|
shouldAdd,
|
|
156
|
+
providerName,
|
|
129
157
|
};
|
|
130
158
|
}
|
|
131
159
|
|
|
@@ -139,8 +167,36 @@ function buildPrompt(extraPrompt) {
|
|
|
139
167
|
return cfg.prompt.join("\n").replaceAll(token, extraPrompt || extraPromptFallback);
|
|
140
168
|
}
|
|
141
169
|
|
|
170
|
+
function getVersion() {
|
|
171
|
+
const packageJsonPath = new URL("../package.json", import.meta.url);
|
|
172
|
+
const packageJson = JSON.parse(readFileSync(packageJsonPath, "utf8"));
|
|
173
|
+
return packageJson.version;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function readStagedDiff() {
|
|
177
|
+
try {
|
|
178
|
+
return execFileSync(
|
|
179
|
+
"git",
|
|
180
|
+
["diff", "--cached", "--no-ext-diff"],
|
|
181
|
+
{
|
|
182
|
+
encoding: "utf8",
|
|
183
|
+
maxBuffer: 50 * 1024 * 1024,
|
|
184
|
+
}
|
|
185
|
+
);
|
|
186
|
+
} catch (error) {
|
|
187
|
+
const detail = error?.message ? `\n${error.message}` : "";
|
|
188
|
+
throw new Error(`Failed to read staged diff.${detail}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
142
192
|
|
|
143
193
|
const args = parseArgs(process.argv.slice(2));
|
|
194
|
+
|
|
195
|
+
if (args.printVersion) {
|
|
196
|
+
console.log(getVersion());
|
|
197
|
+
process.exit(0);
|
|
198
|
+
}
|
|
199
|
+
|
|
144
200
|
const configPath = getConfigPath();
|
|
145
201
|
|
|
146
202
|
if (args.runInit) {
|
|
@@ -163,6 +219,18 @@ try {
|
|
|
163
219
|
|
|
164
220
|
applyUserOverrides(config);
|
|
165
221
|
|
|
222
|
+
if (args.providerName) {
|
|
223
|
+
const wanted = args.providerName.toLowerCase();
|
|
224
|
+
const preset = PROVIDER_PRESETS.find(
|
|
225
|
+
(p) => p.command.toLowerCase() === wanted
|
|
226
|
+
);
|
|
227
|
+
if (!preset) {
|
|
228
|
+
const names = PROVIDER_PRESETS.map((p) => p.command).join(", ");
|
|
229
|
+
fail(`Unknown provider: ${args.providerName}. Available: ${names}`);
|
|
230
|
+
}
|
|
231
|
+
config.provider = { command: preset.command, args: preset.args };
|
|
232
|
+
}
|
|
233
|
+
|
|
166
234
|
if (args.printConfig) {
|
|
167
235
|
console.log(getConfigPath());
|
|
168
236
|
console.log(JSON.stringify(config, null, 2));
|
|
@@ -191,17 +259,20 @@ if (hasStagedChanges.status === 0) {
|
|
|
191
259
|
fail("No staged changes found. Use: git add <files>");
|
|
192
260
|
}
|
|
193
261
|
|
|
194
|
-
const diff =
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
}
|
|
262
|
+
const diff = readStagedDiff();
|
|
263
|
+
const MAX_DIFF_CHARS = 120_000;
|
|
264
|
+
const safeDiff =
|
|
265
|
+
diff.length > MAX_DIFF_CHARS
|
|
266
|
+
? `${diff.slice(0, MAX_DIFF_CHARS)}\n\n[Diff truncated because it was too large.]`
|
|
267
|
+
: diff;
|
|
199
268
|
|
|
200
269
|
const prompt = buildPrompt(args.extraPrompt);
|
|
201
270
|
|
|
271
|
+
console.log(`Using provider: ${config.provider.command}`);
|
|
272
|
+
|
|
202
273
|
let raw;
|
|
203
274
|
try {
|
|
204
|
-
raw = runProvider(config.provider, prompt,
|
|
275
|
+
raw = runProvider(config.provider, prompt, safeDiff);
|
|
205
276
|
} catch (error) {
|
|
206
277
|
fail(error.message);
|
|
207
278
|
}
|
package/bin/presets.js
CHANGED
|
@@ -14,6 +14,11 @@ export const PROVIDER_PRESETS = [
|
|
|
14
14
|
command: "codex",
|
|
15
15
|
args: ["exec", "--skip-git-repo-check", "{prompt}"]
|
|
16
16
|
},
|
|
17
|
+
{
|
|
18
|
+
name: "OpenCode",
|
|
19
|
+
command: "opencode",
|
|
20
|
+
args: ["run", "{prompt}"]
|
|
21
|
+
},
|
|
17
22
|
{
|
|
18
23
|
name: "llm (Simon Willison)",
|
|
19
24
|
command: "llm",
|