git-aic 1.1.0 → 1.2.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/README.md CHANGED
@@ -21,13 +21,16 @@ Your workflow. Your control.
21
21
  - **Full Control Over Rules**
22
22
  Modify the system prompt to enforce your own commit conventions and formatting style.
23
23
 
24
+ - **Flexible Prompt Management**
25
+ Edit prompts globally or per repository, and set them from your editor, direct text, or a file.
26
+
24
27
  - **Conventional Commits Compliance**
25
28
  Strictly follows formats like `feat:`, `fix:`, `refactor:`, `chore:`.
26
29
 
27
30
  - **Commit Confirmation & Editing**
28
31
  Before committing, you can:
29
32
  - Accept the suggested commit message
30
- - Edit the message
33
+ - Edit the full message in your editor
31
34
  - Reject it
32
35
  - Retry generation
33
36
 
@@ -122,9 +125,9 @@ To view your current config:
122
125
  git aic config
123
126
  ```
124
127
 
125
- > "\*Note:\*\* it's masked by default for security reasons
128
+ > **Note:** It is masked by default for security reasons.
126
129
 
127
- To view the whole current config api key
130
+ To view the full saved API key:
128
131
 
129
132
  ```bash
130
133
  git aic config --show
@@ -160,6 +163,7 @@ git aic
160
163
 
161
164
  - Prompts you with a generated commit message.
162
165
  - You can **accept, edit, reject, or retry** the message.
166
+ - Editing opens your editor and supports multiline commit messages.
163
167
 
164
168
  ### Commit and Link to Issue
165
169
 
@@ -191,26 +195,73 @@ git aic config
191
195
 
192
196
  - Displays your saved config.
193
197
 
194
- That’s it.
198
+ ### Manage Prompts
195
199
 
196
- No need to manually write commit messages anymore.
200
+ Edit the global prompt:
197
201
 
198
- ## How It Works
202
+ ```bash
203
+ git aic prompt edit
204
+ ```
199
205
 
200
- 1. Captures your staged Git diff
201
- 2. Builds a strict system prompt
202
- 3. Sends the diff to Gemini
203
- 4. Enforces Conventional Commit formatting
204
- 5. Prompts for commit confirmation (accept, edit, retry, reject)
205
- 6. Executes `git commit` automatically
206
- 7. Optionally pushes if `-p` flag is used
206
+ Set the global prompt directly from text:
207
207
 
208
- You can modify commit behavior by editing:
208
+ ```bash
209
+ git aic prompt edit --text "Write concise conventional commits with a short body when needed."
210
+ ```
209
211
 
212
+ Load the global prompt from a file:
213
+
214
+ ```bash
215
+ git aic prompt edit --file ./prompt.txt
210
216
  ```
211
- src/prompt.ts
217
+
218
+ Reset the global prompt:
219
+
220
+ ```bash
221
+ git aic prompt reset
222
+ ```
223
+
224
+ Edit a repository-local prompt:
225
+
226
+ ```bash
227
+ git aic prompt edit --local
212
228
  ```
213
229
 
230
+ Set a repository-local prompt from text:
231
+
232
+ ```bash
233
+ git aic prompt edit --local --text "Use a short subject and a clear explanatory body."
234
+ ```
235
+
236
+ Load a repository-local prompt from a file:
237
+
238
+ ```bash
239
+ git aic prompt edit --local --file ./commit-prompt.txt
240
+ ```
241
+
242
+ Reset the local prompt:
243
+
244
+ ```bash
245
+ git aic prompt reset --local
246
+ ```
247
+
248
+ Prompt resolution order:
249
+
250
+ 1. local prompt from Git config
251
+ 2. global prompt from Git-AIC config
252
+ 3. built-in default prompt
253
+
254
+ ## How It Works
255
+
256
+ 1. Captures your staged Git diff
257
+ 2. Builds a strict system prompt
258
+ 3. Resolves the active prompt from local, global, or default settings
259
+ 4. Sends the prompt and diff to Gemini
260
+ 5. Prompts for commit confirmation (accept, edit, retry, reject)
261
+ 6. Opens your editor when you choose to edit the generated message
262
+ 7. Executes `git commit` automatically
263
+ 8. Optionally pushes if `-p` flag is used
264
+
214
265
  ---
215
266
 
216
267
  ## Technologies Used
@@ -247,7 +298,7 @@ You are **building them to fit your process.**
247
298
 
248
299
  ## License
249
300
 
250
- [**ISC License**](https://github.com/Spectra010s/git-aic/main/#license)
301
+ [**ISC License**](https://github.com/Spectra010s/git-aic/blob/main/LICENSE)
251
302
 
252
303
  ## Author
253
304
 
@@ -261,9 +312,3 @@ Spectra010s
261
312
  This project is a fork and standalone version of:
262
313
 
263
314
  [https://github.com/samueltuoyo15/Commit-Message-Tool](https://github.com/samueltuoyo15/Commit-Message-Tool)
264
-
265
- ---
266
-
267
- ![License](https://img.shields.io/badge/License-ISC-blue.svg)
268
- ![TypeScript](https://img.shields.io/badge/Language-TypeScript-blue?style=flat&logo=typescript&logoColor=white)
269
- ![Node.js](https://img.shields.io/badge/Runtime-Node.js-green?style=flat&logo=nodedotjs&logoColor=white)
package/dist/cli.js CHANGED
@@ -1,20 +1,31 @@
1
1
  #!/usr/bin/env node
2
+ import fs from "fs/promises";
3
+ import { readFileSync } from "fs";
4
+ import { join, dirname } from "path";
5
+ import { fileURLToPath } from "url";
2
6
  import { Command } from "commander";
3
7
  import { simpleGit } from "simple-git";
4
8
  import chalk from "chalk";
5
- import { getGitDiff } from "./git.js";
9
+ import { ensureInsideGitRepo, getGitDiff, getLocalPrompt, resetLocalPrompt, setLocalPrompt, } from "./git.js";
6
10
  import { generateCommitMessage } from "./llm.js";
7
11
  import { getUserConfirmation } from "./confirm.js";
8
- import { getConfig, setApiKey } from "./config.js";
12
+ import { editPromptInEditor } from "./editor.js";
13
+ import { getConfig, resetCustomPrompt, setApiKey, setCustomPrompt, } from "./config.js";
14
+ import { DEFAULT_SYSTEM_PROMPT } from "./prompt.js";
9
15
  process.on("SIGINT", () => {
10
16
  process.exit(0);
11
17
  });
18
+ const __dirname = dirname(fileURLToPath(import.meta.url));
19
+ const pkg = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8"));
12
20
  const git = simpleGit();
13
21
  const program = new Command();
22
+ function getErrorMessage(error) {
23
+ return error instanceof Error ? error.message : String(error);
24
+ }
14
25
  program
15
- .name("git aic")
16
- .description("AI-powered Git commit generator using Google Gemini")
17
- .version("1.0.0")
26
+ .name(pkg.name)
27
+ .description(pkg.description)
28
+ .version(pkg.version)
18
29
  .option("-p, --push", "push after committing")
19
30
  .option("-i, --issue <number>", "Link commit to GitHub issue");
20
31
  program
@@ -44,8 +55,89 @@ program
44
55
  console.log(chalk.yellow("No API key set"));
45
56
  }
46
57
  });
58
+ const promptCommand = program
59
+ .command("prompt")
60
+ .description("Manage the system prompt used for commit generation");
61
+ promptCommand
62
+ .command("edit")
63
+ .description("Edit and save a custom system prompt in your editor")
64
+ .option("--local", "Save the custom prompt in the current repository")
65
+ .option("--global", "Save the custom prompt in the global git-aic config")
66
+ .option("-t, --text <prompt>", "Set the custom prompt from a string")
67
+ .option("-f, --file <path>", "Set the custom prompt from a file")
68
+ .action(async (options) => {
69
+ try {
70
+ const cfg = await getConfig();
71
+ if (options.local && options.global) {
72
+ console.log(chalk.red("Use either --local or --global, not both at the same time."));
73
+ process.exit(1);
74
+ }
75
+ if (options.text && options.file) {
76
+ console.log(chalk.red("Use either --text or --file, not both at the same time."));
77
+ process.exit(1);
78
+ }
79
+ if (options.local) {
80
+ await ensureInsideGitRepo();
81
+ }
82
+ let editedPrompt = "";
83
+ if (options.text) {
84
+ editedPrompt = options.text.trim();
85
+ }
86
+ else if (options.file) {
87
+ editedPrompt = (await fs.readFile(options.file, "utf-8")).trim();
88
+ }
89
+ else {
90
+ const startingPrompt = options.local
91
+ ? ((await getLocalPrompt()) ?? cfg.customPrompt ?? DEFAULT_SYSTEM_PROMPT)
92
+ : (cfg.customPrompt ?? DEFAULT_SYSTEM_PROMPT);
93
+ editedPrompt = await editPromptInEditor(startingPrompt);
94
+ }
95
+ if (!editedPrompt) {
96
+ console.log(chalk.red("Prompt was empty. Nothing saved."));
97
+ process.exit(1);
98
+ }
99
+ if (options.local) {
100
+ await setLocalPrompt(editedPrompt);
101
+ console.log(chalk.green("Local system prompt saved successfully!"));
102
+ }
103
+ else {
104
+ await setCustomPrompt(editedPrompt);
105
+ console.log(chalk.green("Global system prompt saved successfully!"));
106
+ }
107
+ }
108
+ catch (error) {
109
+ console.error(chalk.red("Prompt edit failed:"), getErrorMessage(error));
110
+ process.exit(1);
111
+ }
112
+ });
113
+ promptCommand
114
+ .command("reset")
115
+ .description("Reset the system prompt back to the default")
116
+ .option("--local", "Reset the prompt in the current repository")
117
+ .option("--global", "Reset the prompt in the global git-aic config")
118
+ .action(async (options) => {
119
+ try {
120
+ if (options.local && options.global) {
121
+ console.log(chalk.red("Use either --local or --global, not both at the same time."));
122
+ process.exit(1);
123
+ }
124
+ if (options.local) {
125
+ await ensureInsideGitRepo();
126
+ await resetLocalPrompt();
127
+ console.log(chalk.green("Local system prompt reset to default."));
128
+ return;
129
+ }
130
+ await resetCustomPrompt();
131
+ console.log(chalk.green("Global system prompt reset to default."));
132
+ }
133
+ catch (error) {
134
+ console.error(chalk.red("Prompt reset failed:"), getErrorMessage(error));
135
+ process.exit(1);
136
+ }
137
+ });
47
138
  program.action(async (options) => {
48
139
  try {
140
+ await ensureInsideGitRepo();
49
141
  const diff = await getGitDiff();
50
142
  if (!diff) {
51
143
  console.log(chalk.yellow("No changes to commit!"));
@@ -92,8 +184,8 @@ program.action(async (options) => {
92
184
  const e = error;
93
185
  isAbort = e.code === "ABORT_ERR";
94
186
  }
95
- const msg = isAbort ? "Operation cancelled" : error;
96
- console.error(chalk.red("\n\nCommit failed:"), msg);
187
+ const msg = isAbort ? "Operation cancelled" : getErrorMessage(error);
188
+ console.error(chalk.red("\nCommit failed:"), msg);
97
189
  process.exit(isAbort ? 0 : 1);
98
190
  }
99
191
  });
package/dist/config.js CHANGED
@@ -2,6 +2,7 @@ import fs from "fs/promises";
2
2
  import path from "path";
3
3
  import os from "os";
4
4
  import chalk from "chalk";
5
+ import { getLocalPrompt } from "./git.js";
5
6
  function getConfigPath() {
6
7
  const toolName = "git-aic";
7
8
  if (process.platform === "win32") {
@@ -39,3 +40,22 @@ export async function saveConfig(data) {
39
40
  export async function setApiKey(key) {
40
41
  await saveConfig({ apiKey: key });
41
42
  }
43
+ export async function setCustomPrompt(prompt) {
44
+ await saveConfig({ customPrompt: prompt });
45
+ }
46
+ export async function resetCustomPrompt() {
47
+ const { customPrompt, ...rest } = await getConfig();
48
+ void customPrompt;
49
+ const configPath = getConfigPath();
50
+ const dir = path.dirname(configPath);
51
+ await fs.mkdir(dir, { recursive: true });
52
+ await fs.writeFile(configPath, JSON.stringify(rest, null, 2), "utf-8");
53
+ }
54
+ export async function getResolvedPrompt() {
55
+ const localPrompt = await getLocalPrompt();
56
+ if (localPrompt) {
57
+ return localPrompt;
58
+ }
59
+ const config = await getConfig();
60
+ return config.customPrompt;
61
+ }
package/dist/confirm.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import readline from "node:readline/promises";
2
2
  import chalk from "chalk";
3
+ import { editTextInEditor } from "./editor.js";
3
4
  export const getUserConfirmation = async (message) => {
4
5
  const rl = readline.createInterface({
5
6
  input: process.stdin,
@@ -10,22 +11,16 @@ export const getUserConfirmation = async (message) => {
10
11
  rl.close();
11
12
  const choice = (answer.toLowerCase() || "y").trim();
12
13
  if (choice === "e") {
13
- const editRl = readline.createInterface({
14
- input: process.stdin,
15
- output: process.stdout,
16
- terminal: true,
17
- });
18
- console.log(chalk.cyan("\nEdit the message:"));
19
- editRl.write(message);
20
- let editedMessage = "";
21
- while (!editedMessage.trim()) {
22
- editedMessage = await editRl.question("> ");
14
+ let editedMessage = message;
15
+ while (true) {
16
+ editedMessage = await editTextInEditor(editedMessage, "git-aic-commit-", "COMMIT_EDITMSG");
17
+ if (editedMessage.trim()) {
18
+ return { choice: "y", message: editedMessage };
19
+ }
23
20
  if (!editedMessage.trim()) {
24
- console.log(chalk.red("Commit message cannot be empty. Please type something."));
21
+ console.log(chalk.red("Commit message cannot be empty. Please edit it again."));
25
22
  }
26
23
  }
27
- editRl.close();
28
- return { choice: "y", message: editedMessage };
29
24
  }
30
25
  return { choice, message };
31
26
  };
package/dist/editor.js ADDED
@@ -0,0 +1,83 @@
1
+ import { spawnSync } from "child_process";
2
+ import fs from "fs/promises";
3
+ import os from "os";
4
+ import path from "path";
5
+ function splitCommand(command) {
6
+ const parts = [];
7
+ let current = "";
8
+ let quote = null;
9
+ let escaping = false;
10
+ for (const char of command.trim()) {
11
+ if (escaping) {
12
+ current += char;
13
+ escaping = false;
14
+ continue;
15
+ }
16
+ if (char === "\\") {
17
+ escaping = true;
18
+ continue;
19
+ }
20
+ if (quote) {
21
+ if (char === quote) {
22
+ quote = null;
23
+ }
24
+ else {
25
+ current += char;
26
+ }
27
+ continue;
28
+ }
29
+ if (char === '"' || char === "'") {
30
+ quote = char;
31
+ continue;
32
+ }
33
+ if (/\s/.test(char)) {
34
+ if (current) {
35
+ parts.push(current);
36
+ current = "";
37
+ }
38
+ continue;
39
+ }
40
+ current += char;
41
+ }
42
+ if (escaping || quote) {
43
+ throw new Error("Editor command has invalid quoting.");
44
+ }
45
+ if (current) {
46
+ parts.push(current);
47
+ }
48
+ return parts;
49
+ }
50
+ export function openInEditor(filePath) {
51
+ const editor = process.env.VISUAL || process.env.EDITOR || "editor";
52
+ const [editorCommand, ...editorArgs] = splitCommand(editor);
53
+ if (!editorCommand) {
54
+ throw new Error("No editor found. Set VISUAL or EDITOR, or install an `editor` command.");
55
+ }
56
+ const result = spawnSync(editorCommand, [...editorArgs, filePath], {
57
+ stdio: "inherit",
58
+ });
59
+ if (result.error) {
60
+ if ("code" in result.error && result.error.code === "ENOENT") {
61
+ throw new Error("No editor found. Set VISUAL or EDITOR, or install an `editor` command.");
62
+ }
63
+ throw result.error;
64
+ }
65
+ if (result.status !== 0) {
66
+ throw new Error(`Editor exited with status ${result.status}`);
67
+ }
68
+ }
69
+ export async function editTextInEditor(initialText, prefix = "git-aic-", fileName = "message.txt") {
70
+ const tempDir = await fs.mkdtemp(path.join(os.tmpdir(), prefix));
71
+ const tempFile = path.join(tempDir, fileName);
72
+ try {
73
+ await fs.writeFile(tempFile, `${initialText}\n`, "utf-8");
74
+ openInEditor(tempFile);
75
+ return (await fs.readFile(tempFile, "utf-8")).trim();
76
+ }
77
+ finally {
78
+ await fs.rm(tempDir, { recursive: true, force: true });
79
+ }
80
+ }
81
+ export async function editPromptInEditor(initialPrompt) {
82
+ return editTextInEditor(initialPrompt, "git-aic-prompt-", "prompt.txt");
83
+ }
package/dist/git.js CHANGED
@@ -1,5 +1,20 @@
1
1
  import { simpleGit } from "simple-git";
2
2
  const git = simpleGit();
3
+ const LOCAL_PROMPT_KEY = "aic.prompt";
4
+ export async function isInsideGitRepo() {
5
+ try {
6
+ const result = await git.raw(["rev-parse", "--is-inside-work-tree"]);
7
+ return result.trim() === "true";
8
+ }
9
+ catch {
10
+ return false;
11
+ }
12
+ }
13
+ export async function ensureInsideGitRepo() {
14
+ if (!(await isInsideGitRepo())) {
15
+ throw new Error("Not inside a Git repository.");
16
+ }
17
+ }
3
18
  export const getGitDiff = async () => {
4
19
  try {
5
20
  await git.raw(["config", "core.autocrlf", "true"]);
@@ -18,3 +33,24 @@ export const getGitDiff = async () => {
18
33
  return "";
19
34
  }
20
35
  };
36
+ export async function getLocalPrompt() {
37
+ try {
38
+ const prompt = await git.raw(["config", "--local", "--get", LOCAL_PROMPT_KEY]);
39
+ const trimmed = prompt.trim();
40
+ return trimmed || undefined;
41
+ }
42
+ catch {
43
+ return undefined;
44
+ }
45
+ }
46
+ export async function setLocalPrompt(prompt) {
47
+ await git.raw(["config", "--local", LOCAL_PROMPT_KEY, prompt]);
48
+ }
49
+ export async function resetLocalPrompt() {
50
+ try {
51
+ await git.raw(["config", "--local", "--unset", LOCAL_PROMPT_KEY]);
52
+ }
53
+ catch {
54
+ return;
55
+ }
56
+ }
package/dist/llm.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import axios from "axios";
2
2
  import chalk from "chalk";
3
3
  import { buildPrompt } from "./prompt.js";
4
- import { getConfig } from "./config.js";
4
+ import { getConfig, getResolvedPrompt } from "./config.js";
5
5
  export const generateCommitMessage = async (rawDiff) => {
6
6
  const API_URL = "https://generativelanguage.googleapis.com/v1/models/gemini-2.5-flash:generateContent";
7
7
  const config = await getConfig();
@@ -18,7 +18,7 @@ export const generateCommitMessage = async (rawDiff) => {
18
18
  console.log(chalk.gray("After setting the key, restart your terminal.\n"));
19
19
  process.exit(1);
20
20
  }
21
- const prompt = buildPrompt(rawDiff);
21
+ const prompt = buildPrompt(rawDiff, await getResolvedPrompt());
22
22
  try {
23
23
  const response = await axios.post(API_URL, {
24
24
  contents: [{ parts: [{ text: prompt }] }],
package/dist/prompt.js CHANGED
@@ -1,44 +1,50 @@
1
- export const buildPrompt = (diff) => `
2
- CRITICAL INSTRUCTIONS - READ CAREFULLY:
3
- You are an expert Git commit message writer. You MUST follow ALL these rules:
4
-
5
- 1. FORMAT: Use Conventional Commits format: <type>(<scope>): <description>
6
- - type: MUST be one of: feat, fix, refactor, chore, docs, style, test, perf
7
- - scope: Should be the module/file affected (e.g., "auth", "api", "ui", "config")
8
- - description: Clear, imperative description in present tense
9
-
10
- 2. DESCRIPTION REQUIREMENTS:
11
- - Start with an imperative verb (add, fix, remove, update, refactor, etc.)
12
- - Be specific about what changed
13
- - Keep it under 72 characters total (including type and scope)
14
- - NO trailing punctuation
15
- - NO emojis ever
16
- - MUST be a complete sentence
17
-
18
- 3. MESSAGE STRUCTURE:
19
- - The entire commit message must be exactly one line
20
- - Format: type(scope): description
21
- - Example: "feat(auth): add password reset functionality"
22
- - Example: "fix(api): handle null response in user endpoint"
23
- - Example: "refactor(ui): simplify component state management"
24
-
25
- 4. QUALITY CHECKS - YOUR OUTPUT MUST PASS:
26
- - Contains opening and closing parentheses
27
- - Has a colon after the parentheses
28
- - Description exists and is not empty
29
- - Total length ≤ 72 characters
30
- - No markdown formatting
31
- - No code blocks
32
- - No explanations or notes
33
-
34
- 5. FAILURE MODE:
35
- - If you cannot generate a proper message, return exactly: "chore: update code"
36
-
37
- YOUR TASK:
38
- Analyze this git diff and generate exactly ONE proper commit message following all rules above.
39
-
40
- Git diff:
41
- ${diff}
42
-
43
- Commit message:
1
+ export const DEFAULT_SYSTEM_PROMPT = `
2
+ CRITICAL INSTRUCTIONS - READ CAREFULLY:
3
+ You are an expert Git commit message writer. You MUST follow ALL these rules:
4
+
5
+ 1. FORMAT: Use Conventional Commits format: <type>(<scope>): <description>
6
+ - type: MUST be one of: feat, fix, refactor, chore, docs, style, test, perf
7
+ - scope: Should be the module/file affected (e.g., "auth", "api", "ui", "config")
8
+ - description: Clear, imperative description in present tense
9
+
10
+ 2. DESCRIPTION REQUIREMENTS:
11
+ - Start with an imperative verb (add, fix, remove, update, refactor, etc.)
12
+ - Be specific about what changed
13
+ - Keep it under 72 characters total (including type and scope)
14
+ - NO trailing punctuation
15
+ - NO emojis ever
16
+ - MUST be a complete sentence
17
+
18
+ 3. MESSAGE STRUCTURE:
19
+ - The entire commit message must be exactly one line
20
+ - Format: type(scope): description
21
+ - Example: "feat(auth): add password reset functionality"
22
+ - Example: "fix(api): handle null response in user endpoint"
23
+ - Example: "refactor(ui): simplify component state management"
24
+
25
+ 4. QUALITY CHECKS - YOUR OUTPUT MUST PASS:
26
+ - Contains opening and closing parentheses
27
+ - Has a colon after the parentheses
28
+ - Description exists and is not empty
29
+ - Total length ≤ 72 characters
30
+ - No markdown formatting
31
+ - No code blocks
32
+ - No explanations or notes
33
+
34
+ 5. FAILURE MODE:
35
+ - If you cannot generate a proper message, return exactly: "chore: update code"
36
+
37
+ YOUR TASK:
38
+ Analyze this git diff and generate exactly ONE proper commit message following all rules above.
39
+
40
+ Git diff:
41
+ {{diff}}
42
+
43
+ Commit message:
44
44
  `.trim();
45
+ export const buildPrompt = (diff, systemPrompt = DEFAULT_SYSTEM_PROMPT) => {
46
+ if (systemPrompt.includes("{{diff}}")) {
47
+ return systemPrompt.split("{{diff}}").join(diff);
48
+ }
49
+ return `${systemPrompt.trim()}\n\nGit diff:\n${diff}\n\nCommit message:`.trim();
50
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "git-aic",
3
- "version": "1.1.0",
3
+ "version": "1.2.1",
4
4
  "description": "AI-powered Git commit generator using Google Gemini",
5
5
  "homepage": "https://github.com/Spectra010s/git-aic",
6
6
  "bugs": {
@@ -15,7 +15,7 @@
15
15
  "type": "module",
16
16
  "main": "./dist/cli.js",
17
17
  "bin": {
18
- "git-aic": "./dist/cli.js"
18
+ "git-aic": "dist/cli.js"
19
19
  },
20
20
  "scripts": {
21
21
  "build": "tsc",
package/t.txt DELETED
@@ -1,32 +0,0 @@
1
- # Git Aic v1.1.0
2
-
3
- ## Highlights
4
- - Fully standalone CLI — removed dependency on the original form network.
5
- - AI-powered commit message generation with Google Gemini.
6
- - Commit confirmation now gracefully exits if canceled.
7
- - Empty commit messages are prevented during editing in confirmation prompt.
8
- - `--issue` option added to link commits to GitHub issues.
9
- - Flattened project structure for cleaner code organization.
10
- - Axios errors for LLM requests are now handled properly to avoid crashes.
11
- - CLI config system for managing your API key.
12
- - Environment variable fallback supported.
13
- - README updated with full usage, installation, and features.
14
-
15
- ## Improvements
16
- - TypeScript & type-safe implementation.
17
- - Improved user experience — prompts only run when called.
18
- - Conventional commit compliance enforced.
19
- - Clear separation between developer install (contributors) and user install (global npm).
20
-
21
- ## Notes
22
- - Editable prompt system is not yet included — planned for v1.2.0.
23
- - Users can now run `git aic` globally via npm.
24
-
25
- ## What's Changed
26
- • refactor(project): flatten project structure and update config by @Spectra010s in https://github.com/Spectra010s/git-aic/pull/1
27
- • feat(cli): add --issue option to link commit to an issue, closes #3 by @Spectra010s in https://github.com/Spectra010s/git-aic/pull/4
28
- • prevent empty commit message when editing in confirmation prompt by @Spectra010s in https://github.com/Spectra010s/git-aic/pull/6
29
- • fix(cli): handle graceful process exit on cancellation, closes #7 by @Spectra010s in https://github.com/Spectra010s/git-aic/pull/8
30
- • fix(llm): handle Axios errors for LLM requests by @Spectra010s in https://github.com/Spectra010s/git-aic/pull/10
31
-
32
- Full Changelog: https://github.com/Spectra010s/git-aic/commits/v1.1.0