ai-git-tool 1.0.0 → 1.2.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.
Files changed (3) hide show
  1. package/README.md +125 -68
  2. package/dist/index.js +198 -30
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -1,121 +1,151 @@
1
- # ai-git
1
+ # ai-git-tool
2
2
 
3
3
  Groq API を使って、ステージ済み差分からコミットメッセージと PR 説明文を自動生成する TypeScript 製 CLI です。
4
4
 
5
- ## 必要環境
5
+ ## セットアップ
6
6
 
7
- - Node.js `18` 以上
8
- - `git`
9
- - Groq API キー(`GROQ_API_KEY`)
7
+ ```bash
8
+ npm install -g ai-git-tool
9
+ ```
10
10
 
11
- ## セットアップ
11
+ ### 環境変数
12
12
 
13
- ### npm からインストール(推奨)
13
+ API キーの取得先: [Groq Console](https://console.groq.com/keys)
14
+
15
+ **macOS / Linux (bash/zsh):**
14
16
 
15
17
  ```bash
16
- npm install -g @imakento/ai-git
18
+ export GROQ_API_KEY="your_api_key"
17
19
  ```
18
20
 
19
- ### ローカル開発版をリンク
21
+ 永続化する場合は `~/.bashrc` や `~/.zshrc` に追記してください。
20
22
 
21
- ```bash
22
- npm install
23
- npm run build
24
- npm link
23
+ **Windows (コマンドプロンプト):**
24
+
25
+ ```cmd
26
+ setx GROQ_API_KEY "your_api_key"
27
+ ```
28
+
29
+ **Windows (PowerShell):**
30
+
31
+ ```powershell
32
+ [System.Environment]::SetEnvironmentVariable("GROQ_API_KEY", "your_api_key", "User")
25
33
  ```
26
34
 
27
- `npm link` 後は、どの Git リポジトリでも `ai-git` が使えます。
35
+ > `setx` / `SetEnvironmentVariable` はユーザー環境変数として永続保存されます。設定後は**ターミナルを再起動**してください。
28
36
 
29
- ## 環境変数
37
+ **Windows (Git Bash):**
30
38
 
31
39
  ```bash
32
- export GROQ_API_KEY="your_api_key"
40
+ echo 'export GROQ_API_KEY="your_api_key"' >> ~/.bashrc
41
+ source ~/.bashrc
33
42
  ```
34
43
 
35
- 任意でモデル指定も可能です。
44
+ 任意でモデル指定も可能です(デフォルト: `llama-3.1-8b-instant`)。
36
45
 
37
46
  ```bash
38
- export GROQ_MODEL="llama-3.1-8b-instant"
39
- ```
47
+ # macOS / Linux / Git Bash
48
+ export GROQ_MODEL="llama-3.3-70b-versatile"
40
49
 
41
- API キーの取得先: [Groq Console](https://console.groq.com/keys)
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
- git add .
59
+ ai-git commit
51
60
  ```
52
61
 
53
- 2. コミットメッセージを生成
62
+ デフォルトで `git add .` を実行してからコミットメッセージを生成します。
54
63
 
55
64
  ```bash
56
- # 通常(タイトル + 箇条書き本文)
57
- ai-git commit
65
+ # 手動でステージした差分のみ使う
66
+ ai-git commit --no-add
58
67
  ```
59
68
 
60
- デフォルト言語は日本語です。
69
+ 確認プロンプトで操作を選択できます。
61
70
 
62
- ```bash
63
- # 今回だけ英語で生成
64
- ai-git commit --lang en
71
+ | 入力 | 動作 |
72
+ |------|------|
73
+ | `y` | そのままコミット |
74
+ | `n` | 中止 |
75
+ | `e` | エディタで編集してからコミット |
65
76
 
66
- # デフォルト言語を永続化
67
- ai-git --set-lang en
68
- 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
69
91
  ```
70
92
 
71
- 3. 確認プロンプトで選択
93
+ `git add .` → AI によるコミットメッセージ生成 → コミット → `git push` を一括で実行します。
72
94
 
73
- - `y`: そのままコミット
74
- - `n`: 中止
75
- - `e`: エディタで編集してからコミット
95
+ - upstream が未設定の場合は `git push -u origin <branch>` で自動設定
96
+ - PR は作成しません(PR を作りたい場合は `ai-git pr` を使用)
76
97
 
77
- ### PR作成
98
+ 確認プロンプトで操作を選択できます。
78
99
 
79
- 1. ブランチで作業してコミット
100
+ | 入力 | 動作 |
101
+ |------|------|
102
+ | `y` | そのままコミット & プッシュ |
103
+ | `n` | 中止 |
104
+ | `e` | エディタで編集してからコミット & プッシュ |
80
105
 
81
106
  ```bash
82
- git checkout -b feature/new-feature
83
- git add .
84
- ai-git commit
107
+ # ステージ済みの差分のみ使う
108
+ ai-git push --no-add
85
109
  ```
86
110
 
87
- 2. PR説明文を生成してPR作成
111
+ ### PR 作成
88
112
 
89
113
  ```bash
90
114
  ai-git pr
91
-
92
- # 言語指定も可能
93
- ai-git pr --lang en
94
115
  ```
95
116
 
96
- `ai-git pr` は自動的に以下を実行します:
117
+ 自動的に以下を実行します。
118
+
119
+ - ブランチがまだ push されていない場合: `git push -u origin <branch>`
120
+ - ローカルに新しいコミットがある場合: `git push`
121
+ - PR 説明文を生成して PR を作成
122
+
123
+ 確認プロンプトで操作を選択できます。
97
124
 
98
- - ブランチがまだpushされていない場合、`git push -u origin <branch>` を実行
99
- - ローカルに新しいコミットがある場合、`git push` を実行
100
- - PR説明文を生成してPRを作成
125
+ | 入力 | 動作 |
126
+ |------|------|
127
+ | `y` | PR を作成 |
128
+ | `n` | 中止 |
129
+ | `e` | エディタで編集してから作成 |
101
130
 
102
- 3. 確認プロンプトで選択
131
+ **生成される PR 説明文の形式:**
103
132
 
104
- - `y`: PRを作成
105
- - `n`: 中止
106
- - `e`: エディタで編集してから作成
133
+ ```markdown
134
+ ## Summary
135
+ 変更の全体像を 2〜3 文で説明
136
+
137
+ ## Changes
138
+ - 具体的な変更内容(3〜7 項目)
139
+
140
+ ## Test plan
141
+ - テスト・確認方法(2〜4 項目)
142
+ ```
107
143
 
108
144
  **前提条件:**
109
145
 
110
146
  - GitHub CLI (`gh`) がインストール済み ([インストール方法](https://cli.github.com/))
111
147
  - `gh auth login` で認証済み
112
148
 
113
- **生成されるPR説明文のフォーマット:**
114
-
115
- - ## Summary: 変更の概要(2-3文)
116
- - ## Changes: 具体的な変更内容(箇条書き)
117
- - ## Test plan: テスト方法(箇条書き)
118
-
119
149
  ### ブランチ作成(自動命名)
120
150
 
121
151
  変更差分(ステージ済み + 未ステージ)からブランチ名を推定して作成します。
@@ -126,21 +156,48 @@ ai-git checkout
126
156
 
127
157
  命名例:
128
158
 
129
- - `feat/auth-login-flow`
130
- - `fix/api-error-handling`
131
- - `docs/readme-update`
159
+ ```
160
+ feat/google-login
161
+ fix/api-error-handling
162
+ docs/readme-update
163
+ ```
164
+
165
+ ### 言語設定
166
+
167
+ デフォルト言語は日本語です。
168
+
169
+ ```bash
170
+ # 今回だけ英語で生成
171
+ ai-git commit --lang en
172
+ ai-git pr --lang en
173
+
174
+ # デフォルト言語を永続化
175
+ ai-git --set-lang en
176
+ ai-git --set-lang ja
177
+ ```
132
178
 
133
- 推定できない場合は `feat/update-xxxxxx` のような名前を自動で使います。
179
+ ### ヘルプ
180
+
181
+ ```bash
182
+ ai-git --help
183
+ ```
134
184
 
135
185
  ## 開発
136
186
 
137
187
  ```bash
138
- npm run dev
188
+ npm install
139
189
  npm run build
190
+ npm link # どの Git リポジトリでも ai-git が使えるようになります
191
+ ```
192
+
193
+ ```bash
194
+ npm run dev
140
195
  ```
141
196
 
142
197
  ## トラブルシューティング
143
198
 
144
- - `No staged changes found. Run \`git add\` first.`: `git add` してから実行
145
- - `GROQ_API_KEY が未設定です`: `GROQ_API_KEY` を設定
146
- - `413 Request too large` / `TPM` 超過: `git add -p` でステージを分割
199
+ | エラー | 対処 |
200
+ |--------|------|
201
+ | `No staged changes found.` | `git add` してから実行 |
202
+ | `GROQ_API_KEY が未設定です` | `GROQ_API_KEY` を設定 |
203
+ | `413 Request too large` / TPM 超過 | `git add -p` でステージを分割 |
package/dist/index.js CHANGED
@@ -51,6 +51,7 @@ const subcommandArgs = args.slice(1);
51
51
  const showHelp = args.includes("--help") || args.includes("-h") || subcommand === "help";
52
52
  const setLangArg = getOptionValue(args, "--set-lang");
53
53
  const langArg = getOptionValue(subcommandArgs, "--lang");
54
+ const noAdd = subcommandArgs.includes("--no-add");
54
55
  const CONFIG_DIR = path.join(os.homedir(), ".ai-commit");
55
56
  const CONFIG_PATH = path.join(CONFIG_DIR, "config.json");
56
57
  const defaultGroqModel = "llama-3.1-8b-instant";
@@ -73,11 +74,13 @@ Usage: ai-git <command> [options]
73
74
 
74
75
  Commands:
75
76
  commit Generate commit message from staged changes
77
+ push Commit with AI message and push to remote (git add . + commit + push)
76
78
  pr Generate PR description and create pull request
77
79
  checkout Create branch from current changes
78
80
 
79
81
  Commit Options:
80
82
  --lang <ja|en> Set language for this run
83
+ --no-add Skip automatic git add .
81
84
 
82
85
  PR Options:
83
86
  --lang <ja|en> Set language for this run
@@ -93,8 +96,11 @@ Environment:
93
96
  process.exit(0);
94
97
  }
95
98
  if (!subcommand ||
96
- (subcommand !== "commit" && subcommand !== "pr" && subcommand !== "checkout")) {
97
- console.error("Error: Please specify a command: 'commit', 'pr' or 'checkout'");
99
+ (subcommand !== "commit" &&
100
+ subcommand !== "push" &&
101
+ subcommand !== "pr" &&
102
+ subcommand !== "checkout")) {
103
+ console.error("Error: Please specify a command: 'commit', 'push', 'pr' or 'checkout'");
98
104
  console.error("Run 'ai-git --help' for usage information");
99
105
  process.exit(1);
100
106
  }
@@ -114,17 +120,69 @@ async function generateCommitMessage(diff) {
114
120
  const inputDiff = truncateByChars(diff, COMMIT_DIFF_COMPACT_CHARS);
115
121
  const prompt = buildPrompt(inputDiff, language);
116
122
  try {
117
- return await generateText(prompt);
123
+ const raw = await generateText(prompt);
124
+ return normalizeGeneratedCommitMessage(raw, diff, language);
118
125
  }
119
126
  catch (error) {
120
127
  if (isRequestTooLargeError(error)) {
121
128
  const smallerDiff = truncateByChars(diff, 1800);
122
- return generateText(buildPrompt(smallerDiff, language));
129
+ const retryRaw = await generateText(buildPrompt(smallerDiff, language));
130
+ return normalizeGeneratedCommitMessage(retryRaw, diff, language);
123
131
  }
124
132
  handleGroqError(error);
125
133
  process.exit(1);
126
134
  }
127
135
  }
136
+ function normalizeGeneratedCommitMessage(raw, diff, lang) {
137
+ const lines = raw
138
+ .split("\n")
139
+ .map((line) => line.replace(/\s+$/g, ""))
140
+ .filter((_, idx, arr) => !(idx > 0 && arr[idx - 1] === "" && arr[idx] === ""));
141
+ if (lines.length === 0) {
142
+ return buildFallbackCommitMessage(diff, lang);
143
+ }
144
+ const subjectLine = lines[0]?.trim() || "";
145
+ const conventionalMatch = /^[a-z]+(\([^)]+\))?:\s+(.+)$/.exec(subjectLine);
146
+ const hasConventionalPrefix = Boolean(conventionalMatch);
147
+ const shortDescription = conventionalMatch?.[2]?.trim() || subjectLine;
148
+ if (!hasConventionalPrefix ||
149
+ looksLikePathOnly(shortDescription) ||
150
+ shortDescription.length < 8) {
151
+ lines[0] = buildFallbackSubjectLine(diff, lang);
152
+ }
153
+ return lines.join("\n").trim();
154
+ }
155
+ function looksLikePathOnly(value) {
156
+ const normalized = value.trim().toLowerCase();
157
+ if (!normalized) {
158
+ return false;
159
+ }
160
+ const hasPathToken = normalized.includes("/") || normalized.includes(".");
161
+ return hasPathToken && /^[a-z0-9/_\-.]+$/.test(normalized);
162
+ }
163
+ function buildFallbackCommitMessage(diff, lang) {
164
+ const subject = buildFallbackSubjectLine(diff, lang);
165
+ if (lang === "ja") {
166
+ return `${subject}\n\n- 差分の主目的を明確にし、変更理由が伝わる形に整える`;
167
+ }
168
+ return `${subject}\n\n- Clarify the main change intent so the reason is easy to understand`;
169
+ }
170
+ function buildFallbackSubjectLine(diff, lang) {
171
+ const files = getChangedFiles();
172
+ const type = inferBranchType(files, diff);
173
+ const rawTopic = inferTopic(files, diff);
174
+ const topic = rawTopic ? rawTopic.replace(/-/g, " ") : "";
175
+ if (lang === "ja") {
176
+ const description = topic
177
+ ? `${topic} の変更意図を分かりやすく整理する`
178
+ : "変更意図が伝わるように更新内容を整理する";
179
+ return `${type}: ${description}`;
180
+ }
181
+ const description = topic
182
+ ? `clarify the intent behind ${topic} changes`
183
+ : "clarify update intent in one clear sentence";
184
+ return `${type}: ${description}`;
185
+ }
128
186
  function buildPrompt(diff, lang) {
129
187
  if (lang === "ja") {
130
188
  return `あなたは git のコミットメッセージ作成の専門家です。
@@ -208,6 +266,13 @@ function doCommit(message) {
208
266
  process.exit(1);
209
267
  }
210
268
  }
269
+ function stageAllChanges() {
270
+ const result = (0, child_process_1.spawnSync)("git", ["add", "."], { stdio: "inherit" });
271
+ if (result.status !== 0) {
272
+ console.error("Error: git add . failed");
273
+ process.exit(1);
274
+ }
275
+ }
211
276
  async function mainCheckout() {
212
277
  const suggested = await suggestBranchName();
213
278
  const branchName = ensureAvailableBranchName(suggested);
@@ -428,15 +493,11 @@ function branchExists(name) {
428
493
  return false;
429
494
  }
430
495
  }
431
- // ── メイン ───────────────────────────────────────────────
432
- async function main() {
433
- if (subcommand === "checkout") {
434
- await mainCheckout();
435
- return;
436
- }
437
- if (subcommand === "pr") {
438
- await mainPR();
439
- return;
496
+ // ── コミットフロー共通処理 ────────────────────────────────
497
+ async function runCommitFlow() {
498
+ if (!noAdd) {
499
+ console.log("📦 変更をステージしています... (git add .)");
500
+ stageAllChanges();
440
501
  }
441
502
  const diff = getStagedDiff();
442
503
  if (!diff.trim()) {
@@ -446,7 +507,6 @@ async function main() {
446
507
  console.log("🤖 コミットメッセージを生成中... (compact summary input)");
447
508
  const message = await generateCommitMessage(diff);
448
509
  console.log(`\n📝 Generated commit message:\n`);
449
- // 詳細モードは複数行なのでインデントして表示
450
510
  message.split("\n").forEach((line) => {
451
511
  console.log(` ${line}`);
452
512
  });
@@ -472,6 +532,53 @@ async function main() {
472
532
  doCommit(finalMessage);
473
533
  console.log(`\n✅ Committed successfully!`);
474
534
  }
535
+ // ── push サブコマンド ─────────────────────────────────────
536
+ async function mainPush() {
537
+ await runCommitFlow();
538
+ const currentBranch = (0, child_process_1.execSync)("git branch --show-current", {
539
+ encoding: "utf-8",
540
+ }).trim();
541
+ // upstream が設定済みか確認し、なければ -u origin で push
542
+ try {
543
+ (0, child_process_1.execSync)(`git rev-parse --abbrev-ref ${currentBranch}@{upstream}`, {
544
+ encoding: "utf-8",
545
+ stdio: "pipe",
546
+ });
547
+ console.log(`📤 push 中... (origin ${currentBranch})`);
548
+ const pushResult = (0, child_process_1.spawnSync)("git", ["push"], { stdio: "inherit" });
549
+ if (pushResult.status !== 0) {
550
+ console.error("❌ git push に失敗しました。");
551
+ process.exit(1);
552
+ }
553
+ }
554
+ catch {
555
+ console.log(`📤 push 中... (origin ${currentBranch} を新規作成)`);
556
+ const pushResult = (0, child_process_1.spawnSync)("git", ["push", "-u", "origin", currentBranch], {
557
+ stdio: "inherit",
558
+ });
559
+ if (pushResult.status !== 0) {
560
+ console.error("❌ git push に失敗しました。");
561
+ process.exit(1);
562
+ }
563
+ }
564
+ console.log(`\n✅ Push 完了!`);
565
+ }
566
+ // ── メイン ───────────────────────────────────────────────
567
+ async function main() {
568
+ if (subcommand === "checkout") {
569
+ await mainCheckout();
570
+ return;
571
+ }
572
+ if (subcommand === "pr") {
573
+ await mainPR();
574
+ return;
575
+ }
576
+ if (subcommand === "push") {
577
+ await mainPush();
578
+ return;
579
+ }
580
+ await runCommitFlow();
581
+ }
475
582
  main().catch((err) => {
476
583
  console.error("❌ 予期しないエラー:", err.message);
477
584
  process.exit(1);
@@ -690,16 +797,24 @@ function getBranchDiff(baseBranch) {
690
797
  function buildPRPrompt(commits, diff, lang) {
691
798
  if (lang === "ja") {
692
799
  return `あなたは GitHub の Pull Request 作成の専門家です。
693
- 次のコミット履歴と差分から、PR の説明文を生成してください。
800
+ 次のコミット履歴と差分から、PR のタイトルと説明文を生成してください。
694
801
 
695
- ルール:
696
- - GitHub の標準フォーマットを使用する
697
- - ## Summary: 2-3文で変更の概要を説明
802
+ 出力フォーマット(必ずこの順番で出力してください):
803
+ 1行目: Title: <Conventional Commits 形式のタイトル(72文字以内、日本語で)>
804
+ 2行目: 空行
805
+ 3行目以降: PR 説明文(以下の形式)
806
+
807
+ 説明文のルール:
808
+ - ## Summary: 1-2文で変更の概要を説明
698
809
  - ## Changes: "- " で始まる箇条書き(3-7個)で具体的な変更内容
699
810
  - ## Test plan: テスト方法の箇条書き(2-4個)
700
811
  - 命令形を使う
701
812
  - WHATとWHYを重視し、HOWは最小限に
702
- - 出力はPR説明文のみ(余計な説明は不要)
813
+ - 出力はタイトルとPR説明文のみ(余計な説明は不要)
814
+
815
+ タイトルの例:
816
+ Title: feat: push サブコマンドを追加する
817
+ Title: fix: コミットメッセージ生成のエラーハンドリングを修正する
703
818
 
704
819
  コミット履歴:
705
820
  ${commits}
@@ -708,16 +823,24 @@ ${commits}
708
823
  ${diff}`;
709
824
  }
710
825
  return `You are an expert at writing GitHub Pull Request descriptions.
711
- Generate a PR description from the following commit history and diff.
826
+ Generate a PR title and description from the following commit history and diff.
712
827
 
713
- Rules:
714
- - Use standard GitHub format
715
- - ## Summary: 2-3 sentences explaining the overall change
828
+ Output format (in this exact order):
829
+ Line 1: Title: <Conventional Commits title, max 72 chars>
830
+ Line 2: empty line
831
+ Line 3+: PR description in the following format
832
+
833
+ Description rules:
834
+ - ## Summary: 1-2 sentences explaining the overall change
716
835
  - ## Changes: bullet points (3-7 items) with "- " prefix detailing specific changes
717
836
  - ## Test plan: bullet points (2-4 items) describing how to test
718
837
  - Use imperative mood
719
838
  - Focus on WHAT and WHY, minimize HOW
720
- - Output ONLY the PR description, no extra explanation
839
+ - Output ONLY the title line and PR description, no extra explanation
840
+
841
+ Title examples:
842
+ Title: feat: add push subcommand
843
+ Title: fix: improve error handling in commit message generation
721
844
 
722
845
  Commit history:
723
846
  ${commits}
@@ -770,10 +893,51 @@ function isRequestTooLargeError(error) {
770
893
  lower.includes("tokens per minute") ||
771
894
  lower.includes("tpm"));
772
895
  }
896
+ /**
897
+ * AI が出力した "Title: <text>" 行からタイトルを抽出する。
898
+ * 見つからない場合は description の先頭テキストからフォールバック。
899
+ */
900
+ function extractPRTitle(raw) {
901
+ const firstLine = raw.split("\n")[0]?.trim() ?? "";
902
+ const titleMatch = /^Title:\s*(.+)$/i.exec(firstLine);
903
+ if (titleMatch?.[1]) {
904
+ return titleMatch[1].trim();
905
+ }
906
+ // フォールバック: Summary 直下の最初の文
907
+ const lines = raw
908
+ .split("\n")
909
+ .map((v) => v.trim())
910
+ .filter(Boolean);
911
+ const summaryIdx = lines.findIndex((l) => l.toLowerCase().startsWith("## summary"));
912
+ let candidate = summaryIdx >= 0
913
+ ? (lines.slice(summaryIdx + 1).find((l) => !l.startsWith("##")) ?? "")
914
+ : (lines.find((l) => !l.startsWith("#") && !l.startsWith("-")) ?? "");
915
+ candidate = candidate
916
+ .replace(/^this pull request\s+(is|does)\s*/i, "")
917
+ .replace(/^この\s*pull request\s*は、?/i, "")
918
+ .replace(/^このprは、?/i, "")
919
+ .replace(/\s+/g, " ")
920
+ .trim();
921
+ const sentenceCut = candidate.search(/[。.!?]/);
922
+ if (sentenceCut > 0) {
923
+ candidate = candidate.slice(0, sentenceCut);
924
+ }
925
+ return candidate || "Update project changes";
926
+ }
927
+ /**
928
+ * "Title: <text>" 行を description 本文から除いて返す。
929
+ */
930
+ function stripTitleLine(raw) {
931
+ const lines = raw.split("\n");
932
+ if (/^Title:\s*/i.test(lines[0]?.trim() ?? "")) {
933
+ // Title 行と直後の空行を除去
934
+ return lines.slice(lines[1]?.trim() === "" ? 2 : 1).join("\n").trimStart();
935
+ }
936
+ return raw;
937
+ }
773
938
  function createPR(description, baseBranch, fallbackURL) {
774
- // Extract title from first non-header line
775
- const lines = description.split("\n");
776
- const titleLine = lines.find((l) => l.trim() && !l.startsWith("#")) || "Pull Request";
939
+ const titleLine = extractPRTitle(description);
940
+ const body = stripTitleLine(description);
777
941
  const result = (0, child_process_1.spawnSync)("gh", [
778
942
  "pr",
779
943
  "create",
@@ -782,7 +946,7 @@ function createPR(description, baseBranch, fallbackURL) {
782
946
  "--title",
783
947
  titleLine.trim(),
784
948
  "--body",
785
- description,
949
+ body,
786
950
  ], { encoding: "utf-8", stdio: "pipe" });
787
951
  if (result.stdout) {
788
952
  process.stdout.write(result.stdout);
@@ -864,8 +1028,12 @@ async function mainPR() {
864
1028
  }
865
1029
  console.log(`🤖 PR説明文を生成中... (${baseBranch}...${currentBranch}) [compact summary input]`);
866
1030
  const description = await generatePRDescription(baseBranch);
867
- console.log(`\n📝 Generated PR description:\n`);
868
- description.split("\n").forEach((line) => {
1031
+ console.log(`\n📝 Generated PR:\n`);
1032
+ console.log(` Title: ${extractPRTitle(description)}`);
1033
+ console.log();
1034
+ stripTitleLine(description)
1035
+ .split("\n")
1036
+ .forEach((line) => {
869
1037
  console.log(` ${line}`);
870
1038
  });
871
1039
  console.log();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-git-tool",
3
- "version": "1.0.0",
3
+ "version": "1.2.0",
4
4
  "description": "AI-powered git commit and PR description generator using Groq API",
5
5
  "main": "dist/index.js",
6
6
  "bin": {