@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 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 # stage all changes first (git add -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" # combine -a and -p
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 --init # interactive config wizard
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 = run("git", ["diff", "--cached"]);
195
-
196
- if (diff.status !== 0) {
197
- fail(diff.stderr || "Failed to read staged diff.");
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, diff.stdout);
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",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thankarezos/git-ai-commit",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Generate editable git commit messages using a configurable AI CLI",
5
5
  "type": "module",
6
6
  "bin": {