ai-git-tool 1.1.0 → 1.3.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,122 +1,154 @@
1
- # ai-git
1
+ # ai-git-tool
2
2
 
3
3
  Groq API を使って、ステージ済み差分からコミットメッセージと PR 説明文を自動生成する TypeScript 製 CLI です。
4
4
 
5
- ## 必要環境
6
-
7
- - Node.js `18` 以上
8
- - `git`
9
- - Groq API キー(`GROQ_API_KEY`)
10
-
11
5
  ## セットアップ
12
6
 
13
- ### npm からインストール(推奨)
14
-
15
7
  ```bash
16
8
  npm install -g ai-git-tool
17
9
  ```
18
10
 
19
- ### ローカル開発版をリンク
11
+ ### 環境変数
12
+
13
+ API キーの取得先: [Groq Console](https://console.groq.com/keys)
14
+
15
+ **macOS / Linux (bash/zsh):**
20
16
 
21
17
  ```bash
22
- npm install
23
- npm run build
24
- npm link
18
+ export GROQ_API_KEY="your_api_key"
25
19
  ```
26
20
 
27
- `npm link` 後は、どの Git リポジトリでも `ai-git` が使えます。
21
+ 永続化する場合は `~/.bashrc` `~/.zshrc` に追記してください。
28
22
 
29
- ## 環境変数
23
+ **Windows (コマンドプロンプト):**
30
24
 
31
- ```bash
32
- export GROQ_API_KEY="your_api_key"
25
+ ```cmd
26
+ setx GROQ_API_KEY "your_api_key"
33
27
  ```
34
28
 
35
- 任意でモデル指定も可能です。
29
+ **Windows (PowerShell):**
30
+
31
+ ```powershell
32
+ [System.Environment]::SetEnvironmentVariable("GROQ_API_KEY", "your_api_key", "User")
33
+ ```
34
+
35
+ > `setx` / `SetEnvironmentVariable` はユーザー環境変数として永続保存されます。設定後は**ターミナルを再起動**してください。
36
+
37
+ **Windows (Git Bash):**
36
38
 
37
39
  ```bash
38
- export GROQ_MODEL="llama-3.1-8b-instant"
40
+ echo 'export GROQ_API_KEY="your_api_key"' >> ~/.bashrc
41
+ source ~/.bashrc
39
42
  ```
40
43
 
41
- API キーの取得先: [Groq Console](https://console.groq.com/keys)
44
+ 任意でモデル指定も可能です(デフォルト: `Llama 3.3 70B Versatile`)。
45
+
46
+ ```bash
47
+ # macOS / Linux / Git Bash
48
+ export GROQ_MODEL="llama-3.3-70b-versatile"
49
+
50
+ # Windows コマンドプロンプト
51
+ setx GROQ_MODEL "llama-3.3-70b-versatile"
52
+ ```
42
53
 
43
54
  ## 使い方
44
55
 
45
56
  ### コミットメッセージ生成
46
57
 
47
- 1. コミットメッセージを生成
48
-
49
58
  ```bash
50
- # 通常(タイトル + 箇条書き本文)
51
59
  ai-git commit
52
60
  ```
53
61
 
54
- `ai-git commit` はデフォルトで `git add .` を実行してから生成します。
62
+ デフォルトで `git add .` を実行してからコミットメッセージを生成します。
55
63
 
56
64
  ```bash
57
- # 自動 add を無効化(手動でステージした差分のみ使う)
65
+ # 手動でステージした差分のみ使う
58
66
  ai-git commit --no-add
59
67
  ```
60
68
 
61
- デフォルト言語は日本語です。
69
+ 確認プロンプトで操作を選択できます。
62
70
 
63
- ```bash
64
- # 今回だけ英語で生成
65
- ai-git commit --lang en
71
+ | 入力 | 動作 |
72
+ | ---- | ------------------------------ |
73
+ | `y` | そのままコミット |
74
+ | `n` | 中止 |
75
+ | `e` | エディタで編集してからコミット |
66
76
 
67
- # デフォルト言語を永続化
68
- ai-git --set-lang en
69
- ai-git --set-lang ja
77
+ **生成されるコミットメッセージの形式(Conventional Commits):**
78
+
79
+ ```
80
+ feat(auth): Google ログインを追加する
81
+
82
+ - GoogleAuthProvider の設定を auth.ts に追加する
83
+ - トークン期限切れ時の更新処理を追加する
84
+ - ネットワーク障害時のエラーハンドリングを追加する
85
+ ```
86
+
87
+ ### コミット & プッシュ
88
+
89
+ ```bash
90
+ ai-git push
70
91
  ```
71
92
 
72
- 2. 確認プロンプトで選択
93
+ `git add .` → AI によるコミットメッセージ生成 → コミット → `git push` を一括で実行します。
73
94
 
74
- - `y`: そのままコミット
75
- - `n`: 中止
76
- - `e`: エディタで編集してからコミット
95
+ - upstream が未設定の場合は `git push -u origin <branch>` で自動設定
96
+ - PR は作成しません(PR を作りたい場合は `ai-git pr` を使用)
77
97
 
78
- ### PR作成
98
+ 確認プロンプトで操作を選択できます。
79
99
 
80
- 1. ブランチで作業してコミット
100
+ | 入力 | 動作 |
101
+ | ---- | ----------------------------------------- |
102
+ | `y` | そのままコミット & プッシュ |
103
+ | `n` | 中止 |
104
+ | `e` | エディタで編集してからコミット & プッシュ |
81
105
 
82
106
  ```bash
83
- git checkout -b feature/new-feature
84
- git add .
85
- ai-git commit
107
+ # ステージ済みの差分のみ使う
108
+ ai-git push --no-add
86
109
  ```
87
110
 
88
- 2. PR説明文を生成してPR作成
111
+ ### PR 作成
89
112
 
90
113
  ```bash
91
114
  ai-git pr
92
-
93
- # 言語指定も可能
94
- ai-git pr --lang en
95
115
  ```
96
116
 
97
- `ai-git pr` は自動的に以下を実行します:
117
+ 自動的に以下を実行します。
118
+
119
+ - ブランチがまだ push されていない場合: `git push -u origin <branch>`
120
+ - ローカルに新しいコミットがある場合: `git push`
121
+ - PR 説明文を生成して PR を作成
122
+
123
+ 確認プロンプトで操作を選択できます。
124
+
125
+ | 入力 | 動作 |
126
+ | ---- | -------------------------- |
127
+ | `y` | PR を作成 |
128
+ | `n` | 中止 |
129
+ | `e` | エディタで編集してから作成 |
130
+
131
+ **生成される PR 説明文の形式:**
132
+
133
+ ```markdown
134
+ ## Summary
135
+
136
+ 変更の全体像を 1〜2 文で説明
98
137
 
99
- - ブランチがまだpushされていない場合、`git push -u origin <branch>` を実行
100
- - ローカルに新しいコミットがある場合、`git push` を実行
101
- - PR説明文を生成してPRを作成
138
+ ## Changes
102
139
 
103
- 3. 確認プロンプトで選択
140
+ - 具体的な変更内容(3〜7 項目)
104
141
 
105
- - `y`: PRを作成
106
- - `n`: 中止
107
- - `e`: エディタで編集してから作成
142
+ ## Test plan
143
+
144
+ - テスト・確認方法(2〜4 項目)
145
+ ```
108
146
 
109
147
  **前提条件:**
110
148
 
111
149
  - GitHub CLI (`gh`) がインストール済み ([インストール方法](https://cli.github.com/))
112
150
  - `gh auth login` で認証済み
113
151
 
114
- **生成されるPR説明文のフォーマット:**
115
-
116
- - ## Summary: 変更の概要(2-3文)
117
- - ## Changes: 具体的な変更内容(箇条書き)
118
- - ## Test plan: テスト方法(箇条書き)
119
-
120
152
  ### ブランチ作成(自動命名)
121
153
 
122
154
  変更差分(ステージ済み + 未ステージ)からブランチ名を推定して作成します。
@@ -127,21 +159,94 @@ ai-git checkout
127
159
 
128
160
  命名例:
129
161
 
130
- - `feat/auth-login-flow`
131
- - `fix/api-error-handling`
132
- - `docs/readme-update`
162
+ ```
163
+ feat/google-login
164
+ fix/api-error-handling
165
+ docs/readme-update
166
+ ```
167
+
168
+ ### 言語設定
169
+
170
+ デフォルト言語は日本語です。
171
+
172
+ ```bash
173
+ # 今回だけ英語で生成
174
+ ai-git commit --lang en
175
+ ai-git pr --lang en
176
+
177
+ # デフォルト言語を永続化
178
+ ai-git --set-lang en
179
+ ai-git --set-lang ja
180
+ ```
181
+
182
+ ### ヘルプ
133
183
 
134
- 推定できない場合は `feat/update-xxxxxx` のような名前を自動で使います。
184
+ ```bash
185
+ ai-git --help
186
+ ```
135
187
 
136
188
  ## 開発
137
189
 
138
190
  ```bash
139
- npm run dev
191
+ npm install
140
192
  npm run build
193
+ npm link # どの Git リポジトリでも ai-git が使えるようになります
194
+ ```
195
+
196
+ ```bash
197
+ npm run dev
141
198
  ```
142
199
 
143
200
  ## トラブルシューティング
144
201
 
145
- - `No staged changes found. Run \`git add\` first.`: `git add` してから実行
146
- - `GROQ_API_KEY が未設定です`: `GROQ_API_KEY` を設定
147
- - `413 Request too large` / `TPM` 超過: `git add -p` でステージを分割
202
+ ### エラーメッセージについて
203
+
204
+ ai-git Git 初心者にも優しいエラーメッセージを表示します。エラーが発生した場合、以下の情報が表示されます:
205
+
206
+ - **何が起こったか**(エラーの内容)
207
+ - **なぜ起こったか**(原因)
208
+ - **どうすればいいか**(解決方法)
209
+ - **ai-git のどのコマンドが使えるか**(次のステップ)
210
+
211
+ ### よくあるエラーと対処法
212
+
213
+ | エラー | 原因 | 対処 |
214
+ | ---------------------------------------------- | ------------------------------------------ | ----------------------------------------------------------------------- |
215
+ | `ステージされた変更が見つかりません` | コミットする変更がステージングエリアにない | `git add .` でステージ、または `ai-git push` を使用 |
216
+ | `GROQ_API_KEY が未設定です` | AI 機能に必要な API キーが設定されていない | [Groq Console](https://console.groq.com/keys) で API キーを取得して設定 |
217
+ | `これは Git リポジトリではありません` | Git が初期化されていないディレクトリで実行 | `git init` で初期化、または Git リポジトリに移動 |
218
+ | `GitHub CLI (gh) がインストールされていません` | PR 作成に必要な gh コマンドがない | [GitHub CLI](https://cli.github.com/) をインストール |
219
+ | `GitHub CLI の認証が必要です` | GitHub にログインしていない | `gh auth login` で認証 |
220
+ | `ベースブランチを検出できませんでした` | main/master/develop ブランチが存在しない | リモートから取得: `git fetch origin` |
221
+ | `413 Request too large` / TPM 超過 | 差分が大きすぎる、またはレート制限 | 自動で縮小して再試行されます。それでも失敗する場合は少し待つ |
222
+
223
+ ### Git の基本操作
224
+
225
+ ai-git を使う前に、以下の Git コマンドを覚えておくと便利です:
226
+
227
+ ```bash
228
+ # 現在の状態を確認
229
+ git status
230
+
231
+ # 変更をステージング
232
+ git add <ファイル名> # 特定のファイルだけ
233
+ git add . # すべての変更
234
+
235
+ # コミット履歴を確認
236
+ git log --oneline
237
+
238
+ # ブランチの確認
239
+ git branch -a
240
+
241
+ # リモートの確認
242
+ git remote -v
243
+ ```
244
+
245
+ ### 推奨ワークフロー
246
+
247
+ Git 初心者の方は、以下の流れで使うのがおすすめです:
248
+
249
+ 1. **変更を加える** - ファイルを編集
250
+ 2. **状態を確認** - `git status` で変更を確認
251
+ 3. **コミット** - `ai-git commit` または `ai-git push`
252
+ 4. **PR 作成** - `ai-git pr`(必要に応じて)
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runCheckoutCommand = runCheckoutCommand;
4
+ const child_process_1 = require("child_process");
5
+ const errors_js_1 = require("../utils/errors.js");
6
+ const ai_js_1 = require("../services/ai.js");
7
+ const branch_js_1 = require("../services/branch.js");
8
+ /**
9
+ * checkout コマンドの実行
10
+ */
11
+ async function runCheckoutCommand() {
12
+ const suggested = await (0, ai_js_1.suggestBranchName)();
13
+ const branchName = (0, branch_js_1.ensureAvailableBranchName)(suggested);
14
+ const result = (0, child_process_1.spawnSync)("git", ["checkout", "-b", branchName], {
15
+ stdio: "inherit",
16
+ });
17
+ if (result.status !== 0) {
18
+ (0, errors_js_1.showFriendlyError)("ブランチ作成に失敗しました", "git checkout -b コマンドが失敗しました(未コミットの変更がある可能性があります)", [
19
+ "現在の変更を確認: git status",
20
+ "変更をコミットしてから新しいブランチを作成する",
21
+ "変更を一時退避: git stash",
22
+ "または、変更を含めたままブランチを作成: git checkout -b <ブランチ名>",
23
+ ], [
24
+ "ai-git commit でまず変更をコミット",
25
+ "ai-git push でコミット&プッシュしてから新しいブランチを作成",
26
+ ]);
27
+ process.exit(1);
28
+ }
29
+ console.log(`✅ ブランチを作成しました: ${branchName}`);
30
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runCommitCommand = runCommitCommand;
4
+ const git_js_1 = require("../utils/git.js");
5
+ const ui_js_1 = require("../utils/ui.js");
6
+ const errors_js_1 = require("../utils/errors.js");
7
+ const ai_js_1 = require("../services/ai.js");
8
+ /**
9
+ * commit コマンドの実行
10
+ */
11
+ async function runCommitCommand(language, noAdd) {
12
+ if (!noAdd) {
13
+ console.log("📦 変更をステージしています... (git add .)");
14
+ (0, git_js_1.stageAllChanges)();
15
+ }
16
+ const diff = (0, git_js_1.getStagedDiff)();
17
+ if (!diff.trim()) {
18
+ (0, errors_js_1.showFriendlyError)("ステージされた変更が見つかりません", "コミットする変更がステージングエリアにありません", [
19
+ "変更したファイルを確認: git status",
20
+ "すべての変更をステージ: git add .",
21
+ "特定のファイルだけステージ: git add <ファイル名>",
22
+ ], [
23
+ "ai-git commit --no-add (手動で git add した後)",
24
+ "ai-git push (自動で git add してコミット&プッシュ)",
25
+ ]);
26
+ process.exit(1);
27
+ }
28
+ console.log("🤖 コミットメッセージを生成中... (compact summary input)");
29
+ const message = await (0, ai_js_1.generateCommitMessage)(diff, language);
30
+ console.log(`\n📝 Generated commit message:\n`);
31
+ message.split("\n").forEach((line) => {
32
+ console.log(` ${line}`);
33
+ });
34
+ console.log();
35
+ const answer = await (0, ui_js_1.askUser)("Use this message? [y/n/e(edit)]: ");
36
+ let finalMessage = message;
37
+ if (answer === "e" || answer === "edit") {
38
+ finalMessage = (0, ui_js_1.editInEditor)(message);
39
+ if (!finalMessage) {
40
+ console.log("Aborted: empty message.");
41
+ process.exit(0);
42
+ }
43
+ console.log(`\n✏️ Edited message:\n`);
44
+ finalMessage.split("\n").forEach((line) => {
45
+ console.log(` ${line}`);
46
+ });
47
+ console.log();
48
+ }
49
+ else if (answer !== "y" && answer !== "yes") {
50
+ console.log("Aborted.");
51
+ process.exit(0);
52
+ }
53
+ (0, git_js_1.doCommit)(finalMessage);
54
+ console.log(`\n✅ Committed successfully!`);
55
+ }
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runPRCommand = runPRCommand;
4
+ const git_js_1 = require("../utils/git.js");
5
+ const ui_js_1 = require("../utils/ui.js");
6
+ const errors_js_1 = require("../utils/errors.js");
7
+ const github_js_1 = require("../services/github.js");
8
+ const ai_js_1 = require("../services/ai.js");
9
+ /**
10
+ * pr コマンドの実行
11
+ */
12
+ async function runPRCommand(language) {
13
+ (0, github_js_1.checkGHCLI)(language);
14
+ (0, github_js_1.checkGHAuth)(language);
15
+ const baseBranch = (0, github_js_1.detectBaseBranch)(language);
16
+ const currentBranch = (0, git_js_1.getCurrentBranch)();
17
+ if (currentBranch === baseBranch) {
18
+ if (language === "ja") {
19
+ (0, errors_js_1.showFriendlyError)(`ベースブランチ (${baseBranch}) から PR を作成できません`, "PR は異なるブランチから作成する必要があります", [
20
+ "新しいブランチを作成してください",
21
+ "または、既存のブランチに切り替えてください: git checkout <ブランチ名>",
22
+ ], [
23
+ "ai-git checkout で新しいブランチを作成",
24
+ "ブランチ作成後に変更をコミット: ai-git commit",
25
+ "その後 PR を作成: ai-git pr",
26
+ ]);
27
+ }
28
+ else {
29
+ (0, errors_js_1.showFriendlyError)(`Cannot create PR from base branch (${baseBranch})`, "PRs must be created from a different branch", [
30
+ "Create a new branch",
31
+ "Or switch to an existing branch: git checkout <branch-name>",
32
+ ], [
33
+ "Use ai-git checkout to create a new branch",
34
+ "Commit changes after creating branch: ai-git commit",
35
+ "Then create PR: ai-git pr",
36
+ ]);
37
+ }
38
+ process.exit(1);
39
+ }
40
+ // ブランチをプッシュ
41
+ (0, github_js_1.pushBranchForPR)(currentBranch, language);
42
+ console.log(`🤖 PR説明文を生成中... (${baseBranch}...${currentBranch}) [compact summary input]`);
43
+ const description = await (0, ai_js_1.generatePRDescription)(baseBranch, language, github_js_1.getBranchDiff);
44
+ console.log(`\n📝 Generated PR:\n`);
45
+ console.log(` Title: ${(0, ai_js_1.extractPRTitle)(description)}`);
46
+ console.log();
47
+ (0, ai_js_1.stripTitleLine)(description)
48
+ .split("\n")
49
+ .forEach((line) => {
50
+ console.log(` ${line}`);
51
+ });
52
+ console.log();
53
+ const answer = await (0, ui_js_1.askUser)("Create PR with this description? [y/n/e(edit)]: ");
54
+ let finalDescription = description;
55
+ if (answer === "e" || answer === "edit") {
56
+ finalDescription = (0, ui_js_1.editInEditor)(description);
57
+ if (!finalDescription) {
58
+ console.log("Aborted: empty description.");
59
+ process.exit(0);
60
+ }
61
+ console.log(`\n✏️ Edited description:\n`);
62
+ finalDescription.split("\n").forEach((line) => {
63
+ console.log(` ${line}`);
64
+ });
65
+ console.log();
66
+ }
67
+ else if (answer !== "y" && answer !== "yes") {
68
+ console.log("Aborted.");
69
+ process.exit(0);
70
+ }
71
+ const fallbackURL = (0, github_js_1.getPullRequestURL)(currentBranch);
72
+ (0, github_js_1.createPR)(finalDescription, baseBranch, fallbackURL, language, ai_js_1.extractPRTitle, ai_js_1.stripTitleLine);
73
+ console.log(`\n✅ PR created successfully!`);
74
+ }
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runPushCommand = runPushCommand;
4
+ const child_process_1 = require("child_process");
5
+ const commit_js_1 = require("./commit.js");
6
+ const git_js_1 = require("../utils/git.js");
7
+ /**
8
+ * 未プッシュのコミットがあるかチェック
9
+ */
10
+ function hasUnpushedCommits(currentBranch) {
11
+ try {
12
+ // upstream が設定されているかチェック
13
+ (0, child_process_1.execSync)(`git rev-parse --abbrev-ref ${currentBranch}@{upstream}`, {
14
+ encoding: "utf-8",
15
+ stdio: "pipe",
16
+ });
17
+ // upstream と比較
18
+ const localCommit = (0, child_process_1.execSync)(`git rev-parse ${currentBranch}`, {
19
+ encoding: "utf-8",
20
+ stdio: "pipe",
21
+ }).trim();
22
+ const remoteCommit = (0, child_process_1.execSync)(`git rev-parse ${currentBranch}@{upstream}`, {
23
+ encoding: "utf-8",
24
+ stdio: "pipe",
25
+ }).trim();
26
+ return localCommit !== remoteCommit;
27
+ }
28
+ catch {
29
+ // upstream が設定されていない場合、コミットがあればプッシュすべき
30
+ try {
31
+ const commitCount = (0, child_process_1.execSync)("git rev-list --count HEAD", {
32
+ encoding: "utf-8",
33
+ stdio: "pipe",
34
+ }).trim();
35
+ return parseInt(commitCount, 10) > 0;
36
+ }
37
+ catch {
38
+ return false;
39
+ }
40
+ }
41
+ }
42
+ /**
43
+ * push コマンドの実行
44
+ */
45
+ async function runPushCommand(language, noAdd) {
46
+ const currentBranch = (0, git_js_1.getCurrentBranch)();
47
+ // ステージされた変更をチェック(--no-add の場合は git add をスキップ)
48
+ if (!noAdd) {
49
+ console.log("📦 変更をステージしています... (git add .)");
50
+ (0, git_js_1.stageAllChanges)();
51
+ }
52
+ const diff = (0, git_js_1.getStagedDiff)();
53
+ const hasStagedChanges = diff.trim().length > 0;
54
+ if (hasStagedChanges) {
55
+ // ステージされた変更がある場合は、通常のコミットフローを実行
56
+ await (0, commit_js_1.runCommitCommand)(language, true); // noAdd=true(すでにステージ済み)
57
+ }
58
+ else {
59
+ // ステージされた変更がない場合、未プッシュのコミットがあるかチェック
60
+ if (hasUnpushedCommits(currentBranch)) {
61
+ console.log("💡 ステージされた変更はありませんが、未プッシュのコミットがあります");
62
+ console.log("📤 コミットをプッシュします...");
63
+ }
64
+ else {
65
+ console.error("❌ プッシュするものがありません");
66
+ console.error("");
67
+ console.error("📋 原因: ステージされた変更も未プッシュのコミットもありません");
68
+ console.error("");
69
+ console.error("💡 解決方法:");
70
+ console.error(" 1. 変更を確認: git status");
71
+ console.error(" 2. 変更をステージ: git add .");
72
+ console.error(" 3. または、まずコミット: ai-git commit");
73
+ process.exit(1);
74
+ }
75
+ }
76
+ (0, git_js_1.pushCurrentBranch)(currentBranch);
77
+ console.log(`\n✅ Push 完了!`);
78
+ }