ai-git-tool 1.2.0 → 1.4.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/LICENSE +21 -0
- package/README.md +74 -23
- package/dist/commands/checkout.js +30 -0
- package/dist/commands/commit.js +55 -0
- package/dist/commands/pr.js +76 -0
- package/dist/commands/push.js +78 -0
- package/dist/index.js +30 -994
- package/dist/services/ai.js +520 -0
- package/dist/services/branch.js +37 -0
- package/dist/services/github.js +479 -0
- package/dist/types.js +2 -0
- package/dist/utils/config.js +98 -0
- package/dist/utils/errors.js +81 -0
- package/dist/utils/git.js +157 -0
- package/dist/utils/text.js +23 -0
- package/dist/utils/ui.js +73 -0
- package/package.json +5 -2
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getStagedDiff = getStagedDiff;
|
|
4
|
+
exports.getCommandOutput = getCommandOutput;
|
|
5
|
+
exports.getChangedFiles = getChangedFiles;
|
|
6
|
+
exports.getCombinedDiff = getCombinedDiff;
|
|
7
|
+
exports.stageAllChanges = stageAllChanges;
|
|
8
|
+
exports.doCommit = doCommit;
|
|
9
|
+
exports.pushCurrentBranch = pushCurrentBranch;
|
|
10
|
+
exports.branchExists = branchExists;
|
|
11
|
+
exports.getCurrentBranch = getCurrentBranch;
|
|
12
|
+
const child_process_1 = require("child_process");
|
|
13
|
+
const errors_js_1 = require("./errors.js");
|
|
14
|
+
/**
|
|
15
|
+
* ステージされた差分を取得
|
|
16
|
+
*/
|
|
17
|
+
function getStagedDiff() {
|
|
18
|
+
(0, errors_js_1.checkIfGitRepository)();
|
|
19
|
+
try {
|
|
20
|
+
return (0, child_process_1.execSync)("git diff --cached", { encoding: "utf-8" });
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
(0, errors_js_1.showFriendlyError)("Git の差分取得に失敗しました", "git diff コマンドの実行に失敗しました", [
|
|
24
|
+
"Git がインストールされているか確認してください: git --version",
|
|
25
|
+
"カレントディレクトリが Git リポジトリか確認してください: git status",
|
|
26
|
+
], ["ai-git commit で変更をコミット", "ai-git checkout で新しいブランチを作成"]);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* コマンドの出力を取得(エラーは無視)
|
|
32
|
+
*/
|
|
33
|
+
function getCommandOutput(command) {
|
|
34
|
+
try {
|
|
35
|
+
return (0, child_process_1.execSync)(command, { encoding: "utf-8", stdio: "pipe" });
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return "";
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 変更されたファイル一覧を取得
|
|
43
|
+
*/
|
|
44
|
+
function getChangedFiles() {
|
|
45
|
+
const staged = getCommandOutput("git diff --cached --name-only");
|
|
46
|
+
const unstaged = getCommandOutput("git diff --name-only");
|
|
47
|
+
const merged = `${staged}\n${unstaged}`
|
|
48
|
+
.split("\n")
|
|
49
|
+
.map((v) => v.trim())
|
|
50
|
+
.filter(Boolean);
|
|
51
|
+
return Array.from(new Set(merged));
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* 全差分を取得(ステージ済み + 未ステージ)
|
|
55
|
+
*/
|
|
56
|
+
function getCombinedDiff() {
|
|
57
|
+
const staged = getCommandOutput("git diff --cached");
|
|
58
|
+
const unstaged = getCommandOutput("git diff");
|
|
59
|
+
return `${staged}\n${unstaged}`;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* すべての変更をステージ
|
|
63
|
+
*/
|
|
64
|
+
function stageAllChanges() {
|
|
65
|
+
const result = (0, child_process_1.spawnSync)("git", ["add", "."], { stdio: "inherit" });
|
|
66
|
+
if (result.status !== 0) {
|
|
67
|
+
(0, errors_js_1.showFriendlyError)("ファイルのステージングに失敗しました", "git add . コマンドが失敗しました", [
|
|
68
|
+
"カレントディレクトリを確認: pwd",
|
|
69
|
+
"Git の状態を確認: git status",
|
|
70
|
+
".gitignore で除外されているファイルがないか確認",
|
|
71
|
+
"ファイルのパーミッションを確認してください",
|
|
72
|
+
], [
|
|
73
|
+
"ai-git commit --no-add (手動で git add する場合)",
|
|
74
|
+
"特定のファイルだけ追加: git add <ファイル名>",
|
|
75
|
+
]);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* コミットを実行
|
|
81
|
+
*/
|
|
82
|
+
function doCommit(message) {
|
|
83
|
+
const result = (0, child_process_1.spawnSync)("git", ["commit", "-m", message], {
|
|
84
|
+
stdio: "inherit",
|
|
85
|
+
});
|
|
86
|
+
if (result.status !== 0) {
|
|
87
|
+
(0, errors_js_1.showFriendlyError)("コミットに失敗しました", "git commit コマンドが失敗しました(pre-commit フックのエラーや空のコミットの可能性があります)", [
|
|
88
|
+
"ステージされたファイルを確認: git status",
|
|
89
|
+
"pre-commit フックがある場合は、エラー内容を確認してください",
|
|
90
|
+
"空のコミットを許可する場合: git commit --allow-empty -m 'メッセージ'",
|
|
91
|
+
], ["エラーを修正後に ai-git commit を再実行"]);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 現在のブランチをリモートにプッシュ
|
|
97
|
+
*/
|
|
98
|
+
function pushCurrentBranch(currentBranch) {
|
|
99
|
+
try {
|
|
100
|
+
(0, child_process_1.execSync)(`git rev-parse --abbrev-ref ${currentBranch}@{upstream}`, {
|
|
101
|
+
encoding: "utf-8",
|
|
102
|
+
stdio: "pipe",
|
|
103
|
+
});
|
|
104
|
+
console.log(`📤 push 中... (origin ${currentBranch})`);
|
|
105
|
+
const pushResult = (0, child_process_1.spawnSync)("git", ["push"], { stdio: "inherit" });
|
|
106
|
+
if (pushResult.status !== 0) {
|
|
107
|
+
(0, errors_js_1.showFriendlyError)("プッシュに失敗しました", "リモートへのプッシュが失敗しました(権限不足やネットワークエラーの可能性があります)", [
|
|
108
|
+
"リモートリポジトリの設定を確認: git remote -v",
|
|
109
|
+
"プッシュ権限があるか確認してください",
|
|
110
|
+
"ネットワーク接続を確認してください",
|
|
111
|
+
"リモートブランチとの競合がないか確認: git pull",
|
|
112
|
+
], [
|
|
113
|
+
"競合を解決後に ai-git push を再実行",
|
|
114
|
+
"ai-git pr で Pull Request を作成(プッシュ済みの場合)",
|
|
115
|
+
]);
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
console.log(`📤 push 中... (origin ${currentBranch} を新規作成)`);
|
|
121
|
+
const pushResult = (0, child_process_1.spawnSync)("git", ["push", "-u", "origin", currentBranch], {
|
|
122
|
+
stdio: "inherit",
|
|
123
|
+
});
|
|
124
|
+
if (pushResult.status !== 0) {
|
|
125
|
+
(0, errors_js_1.showFriendlyError)("新しいブランチのプッシュに失敗しました", "リモートに新しいブランチを作成できませんでした(権限不足やネットワークエラーの可能性があります)", [
|
|
126
|
+
"リモートリポジトリの URL を確認: git remote -v",
|
|
127
|
+
"リモートリポジトリへのプッシュ権限があるか確認",
|
|
128
|
+
"ネットワーク接続を確認してください",
|
|
129
|
+
"SSH キーまたは認証情報が正しく設定されているか確認",
|
|
130
|
+
], [
|
|
131
|
+
"権限を確認後に ai-git push を再実行",
|
|
132
|
+
"手動でプッシュ: git push -u origin " + currentBranch,
|
|
133
|
+
]);
|
|
134
|
+
process.exit(1);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* ブランチが存在するかチェック
|
|
140
|
+
*/
|
|
141
|
+
function branchExists(name) {
|
|
142
|
+
try {
|
|
143
|
+
(0, child_process_1.execSync)(`git show-ref --verify --quiet refs/heads/${name}`, {
|
|
144
|
+
stdio: "pipe",
|
|
145
|
+
});
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
catch {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* 現在のブランチ名を取得
|
|
154
|
+
*/
|
|
155
|
+
function getCurrentBranch() {
|
|
156
|
+
return (0, child_process_1.execSync)("git branch --show-current", { encoding: "utf-8" }).trim();
|
|
157
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.truncateByChars = truncateByChars;
|
|
4
|
+
exports.getOptionValue = getOptionValue;
|
|
5
|
+
/**
|
|
6
|
+
* テキストを指定文字数で切り詰める
|
|
7
|
+
*/
|
|
8
|
+
function truncateByChars(input, maxChars) {
|
|
9
|
+
if (input.length <= maxChars) {
|
|
10
|
+
return input;
|
|
11
|
+
}
|
|
12
|
+
return `${input.slice(0, maxChars)}\n\n... (truncated)`;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* オプション値を取得
|
|
16
|
+
*/
|
|
17
|
+
function getOptionValue(argv, name) {
|
|
18
|
+
const idx = argv.indexOf(name);
|
|
19
|
+
if (idx === -1) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
return argv[idx + 1];
|
|
23
|
+
}
|
package/dist/utils/ui.js
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.askUser = askUser;
|
|
37
|
+
exports.editInEditor = editInEditor;
|
|
38
|
+
const readline = __importStar(require("readline"));
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const os = __importStar(require("os"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const child_process_1 = require("child_process");
|
|
43
|
+
/**
|
|
44
|
+
* ユーザーに質問して回答を取得
|
|
45
|
+
*/
|
|
46
|
+
function askUser(question) {
|
|
47
|
+
const rl = readline.createInterface({
|
|
48
|
+
input: process.stdin,
|
|
49
|
+
output: process.stdout,
|
|
50
|
+
});
|
|
51
|
+
return new Promise((resolve) => {
|
|
52
|
+
rl.question(question, (answer) => {
|
|
53
|
+
rl.close();
|
|
54
|
+
resolve(answer.trim().toLowerCase());
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* エディタでテキストを編集
|
|
60
|
+
*/
|
|
61
|
+
function editInEditor(message) {
|
|
62
|
+
const tmpFile = path.join(os.tmpdir(), `commit-msg-${Date.now()}.txt`);
|
|
63
|
+
fs.writeFileSync(tmpFile, message, "utf-8");
|
|
64
|
+
const editor = process.env.EDITOR || "vi";
|
|
65
|
+
const result = (0, child_process_1.spawnSync)(editor, [tmpFile], { stdio: "inherit" });
|
|
66
|
+
if (result.error) {
|
|
67
|
+
console.error(`Error: Failed to open editor: ${result.error.message}`);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
}
|
|
70
|
+
const edited = fs.readFileSync(tmpFile, "utf-8").trim();
|
|
71
|
+
fs.unlinkSync(tmpFile);
|
|
72
|
+
return edited;
|
|
73
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ai-git-tool",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"description": "AI-powered git commit and PR description generator using Groq API",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -9,7 +9,10 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsc",
|
|
11
11
|
"dev": "tsx src/index.ts",
|
|
12
|
-
"prepublishOnly": "npm run build"
|
|
12
|
+
"prepublishOnly": "npm run build",
|
|
13
|
+
"release:patch": "npm version patch && git push --follow-tags",
|
|
14
|
+
"release:minor": "npm version minor && git push --follow-tags",
|
|
15
|
+
"release:major": "npm version major && git push --follow-tags"
|
|
13
16
|
},
|
|
14
17
|
"keywords": [
|
|
15
18
|
"git",
|