sales-frontend-gemini-cli 0.3.0 → 0.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/dist/common/helper.cjs +59 -8
- package/dist/common/helper.cjs.map +1 -1
- package/dist/common/helper.d.cts +15 -1
- package/dist/common/helper.d.ts +15 -1
- package/dist/common/helper.js +58 -9
- package/dist/common/helper.js.map +1 -1
- package/dist/{pr-review/gemini → etc}/installation-gcloud.cjs +1 -1
- package/dist/etc/installation-gcloud.cjs.map +1 -0
- package/dist/{pr-review/gemini → etc}/installation-gcloud.js +1 -1
- package/dist/etc/installation-gcloud.js.map +1 -0
- package/dist/{pr-review/gemini → etc}/interactive-version/index.cjs +2 -2
- package/dist/etc/interactive-version/index.cjs.map +1 -0
- package/dist/{pr-review/gemini → etc}/interactive-version/index.js +2 -2
- package/dist/etc/interactive-version/index.js.map +1 -0
- package/dist/{pr-review/gemini → etc}/login.cjs +1 -1
- package/dist/etc/login.cjs.map +1 -0
- package/dist/{pr-review/gemini → etc}/login.js +1 -1
- package/dist/etc/login.js.map +1 -0
- package/dist/{pr-review/gemini → etc}/vertex-version/index.cjs +1 -1
- package/dist/etc/vertex-version/index.cjs.map +1 -0
- package/dist/{pr-review/gemini → etc}/vertex-version/index.js +1 -1
- package/dist/etc/vertex-version/index.js.map +1 -0
- package/dist/pr-review/claude/claude-commander.cjs +31 -5
- package/dist/pr-review/claude/claude-commander.cjs.map +1 -1
- package/dist/pr-review/claude/claude-commander.js +31 -5
- package/dist/pr-review/claude/claude-commander.js.map +1 -1
- package/dist/pr-review/claude/installation-claude.cjs +38 -1
- package/dist/pr-review/claude/installation-claude.cjs.map +1 -1
- package/dist/pr-review/claude/installation-claude.js +33 -1
- package/dist/pr-review/claude/installation-claude.js.map +1 -1
- package/dist/pr-review/codex/codex-commander.cjs +88 -0
- package/dist/pr-review/codex/codex-commander.cjs.map +1 -0
- package/dist/pr-review/codex/codex-commander.d.cts +12 -0
- package/dist/pr-review/codex/codex-commander.d.ts +12 -0
- package/dist/pr-review/codex/codex-commander.js +80 -0
- package/dist/pr-review/codex/codex-commander.js.map +1 -0
- package/dist/pr-review/codex/installation-codex.cjs +62 -0
- package/dist/pr-review/codex/installation-codex.cjs.map +1 -0
- package/dist/pr-review/codex/installation-codex.d.cts +3 -0
- package/dist/pr-review/codex/installation-codex.d.ts +3 -0
- package/dist/pr-review/codex/installation-codex.js +55 -0
- package/dist/pr-review/codex/installation-codex.js.map +1 -0
- package/dist/pr-review/gemini/gemini-commander.cjs +28 -5
- package/dist/pr-review/gemini/gemini-commander.cjs.map +1 -1
- package/dist/pr-review/gemini/gemini-commander.js +28 -5
- package/dist/pr-review/gemini/gemini-commander.js.map +1 -1
- package/dist/pr-review/gemini/installation-gemini.cjs +35 -0
- package/dist/pr-review/gemini/installation-gemini.cjs.map +1 -1
- package/dist/pr-review/gemini/installation-gemini.js +30 -0
- package/dist/pr-review/gemini/installation-gemini.js.map +1 -1
- package/dist/pr-review/review-one-by-one.cjs +265 -36
- package/dist/pr-review/review-one-by-one.cjs.map +1 -1
- package/dist/pr-review/review-one-by-one.js +264 -35
- package/dist/pr-review/review-one-by-one.js.map +1 -1
- package/dist/pr-review/review.cjs +233 -19
- package/dist/pr-review/review.cjs.map +1 -1
- package/dist/pr-review/review.js +233 -19
- package/dist/pr-review/review.js.map +1 -1
- package/package.json +1 -1
- package/src/common/form/review-form.md +1 -1
- package/src/common/rules/review-rules.md +2 -0
- package/dist/pr-review/gemini/installation-gcloud.cjs.map +0 -1
- package/dist/pr-review/gemini/installation-gcloud.js.map +0 -1
- package/dist/pr-review/gemini/interactive-version/index.cjs.map +0 -1
- package/dist/pr-review/gemini/interactive-version/index.js.map +0 -1
- package/dist/pr-review/gemini/login.cjs.map +0 -1
- package/dist/pr-review/gemini/login.js.map +0 -1
- package/dist/pr-review/gemini/vertex-version/index.cjs.map +0 -1
- package/dist/pr-review/gemini/vertex-version/index.js.map +0 -1
- /package/dist/{pr-review/gemini → etc}/installation-gcloud.d.cts +0 -0
- /package/dist/{pr-review/gemini → etc}/installation-gcloud.d.ts +0 -0
- /package/dist/{pr-review/gemini → etc}/interactive-version/index.d.cts +0 -0
- /package/dist/{pr-review/gemini → etc}/interactive-version/index.d.ts +0 -0
- /package/dist/{pr-review/gemini → etc}/login.d.cts +0 -0
- /package/dist/{pr-review/gemini → etc}/login.d.ts +0 -0
- /package/dist/{pr-review/gemini → etc}/vertex-version/index.d.cts +0 -0
- /package/dist/{pr-review/gemini → etc}/vertex-version/index.d.ts +0 -0
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { exec, execSync } from 'child_process';
|
|
3
|
-
import
|
|
3
|
+
import fs5 from 'fs';
|
|
4
4
|
import util from 'util';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import readline from 'readline';
|
|
7
7
|
import { fileURLToPath } from 'url';
|
|
8
8
|
|
|
9
9
|
var __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
-
var rulesPath = path.resolve(__dirname, "../../src/
|
|
11
|
-
var namingRulesPath = path.resolve(__dirname, "../../src/
|
|
12
|
-
var codingConventionRulesPath = path.resolve(__dirname, "../../src/
|
|
13
|
-
path.resolve(__dirname, "../../src/
|
|
14
|
-
var reviewFormOneByOnePath = path.resolve(__dirname, "../../src/
|
|
10
|
+
var rulesPath = path.resolve(__dirname, "../../src/common/rules/review-rules.md");
|
|
11
|
+
var namingRulesPath = path.resolve(__dirname, "../../src/common/rules/naming-rule.md");
|
|
12
|
+
var codingConventionRulesPath = path.resolve(__dirname, "../../src/common/rules/coding-convention.md");
|
|
13
|
+
path.resolve(__dirname, "../../src/common/form/review-form.md");
|
|
14
|
+
var reviewFormOneByOnePath = path.resolve(__dirname, "../../src/common/form/review-form-one-by-one.md");
|
|
15
15
|
var REPORT_DIR = ".review-report";
|
|
16
16
|
var tempDiffPath = "temp_diff.txt";
|
|
17
17
|
var AIServices = ["gemini", "claude", "codex"];
|
|
@@ -29,27 +29,39 @@ var ignoreList = [
|
|
|
29
29
|
".review-report/"
|
|
30
30
|
// 생성되는 리포트 폴더도 제외
|
|
31
31
|
];
|
|
32
|
+
function isTestMode(args4 = process.argv.slice(2)) {
|
|
33
|
+
return args4.includes("--test");
|
|
34
|
+
}
|
|
35
|
+
function createTraceLogger(scope, args4 = process.argv.slice(2)) {
|
|
36
|
+
const enabled = isTestMode(args4);
|
|
37
|
+
return (step, detail) => {
|
|
38
|
+
if (!enabled) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
console.log(`[TRACE][${scope}] ${step}${detail ? ` | ${detail}` : ""}`);
|
|
42
|
+
};
|
|
43
|
+
}
|
|
32
44
|
function getNextFilePath(dir, baseName, extension) {
|
|
33
45
|
let counter = 1;
|
|
34
46
|
while (true) {
|
|
35
47
|
const filePath = path.join(dir, `${baseName}-${counter}${extension}`);
|
|
36
|
-
if (!
|
|
48
|
+
if (!fs5.existsSync(filePath)) {
|
|
37
49
|
return filePath;
|
|
38
50
|
}
|
|
39
51
|
counter++;
|
|
40
52
|
}
|
|
41
53
|
}
|
|
42
54
|
function deleteFile(filePath) {
|
|
43
|
-
if (
|
|
44
|
-
|
|
55
|
+
if (fs5.existsSync(filePath)) {
|
|
56
|
+
fs5.unlinkSync(filePath);
|
|
45
57
|
}
|
|
46
58
|
}
|
|
47
59
|
function deleteTempDiff() {
|
|
48
60
|
deleteFile(tempDiffPath);
|
|
49
61
|
}
|
|
50
62
|
function createReportDirectory() {
|
|
51
|
-
if (!
|
|
52
|
-
|
|
63
|
+
if (!fs5.existsSync(REPORT_DIR)) {
|
|
64
|
+
fs5.mkdirSync(REPORT_DIR, { recursive: true });
|
|
53
65
|
}
|
|
54
66
|
}
|
|
55
67
|
function getNowString() {
|
|
@@ -71,25 +83,60 @@ function getGitDiffFilter() {
|
|
|
71
83
|
return { includeParams, excludeParams };
|
|
72
84
|
}
|
|
73
85
|
function openReport(reportPath) {
|
|
86
|
+
const resolvedPath = path.resolve(reportPath);
|
|
87
|
+
const { platform } = process;
|
|
88
|
+
const openWithChrome = () => {
|
|
89
|
+
if (platform === "darwin") {
|
|
90
|
+
execSync(`open -a "Google Chrome" "${resolvedPath}"`, { stdio: "ignore" });
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
if (platform === "linux") {
|
|
94
|
+
execSync(`google-chrome "${resolvedPath}"`, { stdio: "ignore" });
|
|
95
|
+
return true;
|
|
96
|
+
}
|
|
97
|
+
return false;
|
|
98
|
+
};
|
|
99
|
+
const openWithDefaultBrowser = () => {
|
|
100
|
+
if (platform === "darwin") {
|
|
101
|
+
execSync(`open "${resolvedPath}"`, { stdio: "ignore" });
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
if (platform === "linux") {
|
|
105
|
+
execSync(`xdg-open "${resolvedPath}"`, { stdio: "ignore" });
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
return false;
|
|
109
|
+
};
|
|
110
|
+
try {
|
|
111
|
+
if (openWithChrome()) {
|
|
112
|
+
console.log("\u{1F680} Google Chrome\uC5D0\uC11C \uB9AC\uD3EC\uD2B8\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
115
|
+
} catch {
|
|
116
|
+
}
|
|
74
117
|
try {
|
|
75
|
-
|
|
76
|
-
|
|
118
|
+
if (openWithDefaultBrowser()) {
|
|
119
|
+
console.log("\u{1F680} \uAE30\uBCF8 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB9AC\uD3EC\uD2B8\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
77
122
|
} catch (e) {
|
|
78
123
|
console.error("\u26A0\uFE0F \uBE0C\uB77C\uC6B0\uC800 \uC5F4\uAE30 \uC2E4\uD328:", e);
|
|
124
|
+
return;
|
|
79
125
|
}
|
|
126
|
+
console.error(`\u26A0\uFE0F \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD50C\uB7AB\uD3FC\uC785\uB2C8\uB2E4: ${platform}`);
|
|
80
127
|
}
|
|
81
128
|
function getDiffArgs() {
|
|
82
|
-
const
|
|
83
|
-
const commitIndex =
|
|
129
|
+
const args4 = process.argv.slice(2);
|
|
130
|
+
const commitIndex = args4.indexOf("--commit");
|
|
84
131
|
const { includeParams, excludeParams } = getGitDiffFilter();
|
|
85
132
|
let diffArgs = "";
|
|
86
133
|
if (commitIndex !== -1) {
|
|
87
|
-
const commitHash =
|
|
134
|
+
const commitHash = args4[commitIndex + 1];
|
|
88
135
|
if (!commitHash) {
|
|
89
136
|
console.error("\u274C \uCEE4\uBC0B \uD574\uC2DC\uAC00 \uC81C\uACF5\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
|
|
90
137
|
process.exit(1);
|
|
91
138
|
}
|
|
92
|
-
const nextArg =
|
|
139
|
+
const nextArg = args4[commitIndex + 2];
|
|
93
140
|
let n = 0;
|
|
94
141
|
if (nextArg && !nextArg.startsWith("--")) {
|
|
95
142
|
n = parseInt(nextArg, 10);
|
|
@@ -126,7 +173,9 @@ async function showSelectionAIService() {
|
|
|
126
173
|
}
|
|
127
174
|
firstRender = false;
|
|
128
175
|
readline.clearScreenDown(process.stdout);
|
|
129
|
-
process.stdout.write(
|
|
176
|
+
process.stdout.write(
|
|
177
|
+
"\u{1F916} AI \uC11C\uBE44\uC2A4\uB97C \uC120\uD0DD\uD574\uC8FC\uC138\uC694 (\x1B[33m\u2191\u2193 \uBC29\uD5A5\uD0A4\x1B[0m \uC774\uB3D9, \x1B[33mEnter\x1B[0m \uC120\uD0DD):\n"
|
|
178
|
+
);
|
|
130
179
|
AIServices.forEach((service, index) => {
|
|
131
180
|
if (index === selectedIndex) {
|
|
132
181
|
process.stdout.write(` \x1B[36m>\x1B[0m \x1B[36m\u25C9\x1B[0m \x1B[1m${service}\x1B[0m
|
|
@@ -172,20 +221,26 @@ async function showSelectionAIService() {
|
|
|
172
221
|
});
|
|
173
222
|
}
|
|
174
223
|
var args = process.argv.slice(2);
|
|
224
|
+
var trace = createTraceLogger("claude-commander", args);
|
|
175
225
|
var createClaudeCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
226
|
+
trace("createClaudeCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
|
|
176
227
|
let modelOption = "";
|
|
177
228
|
if (args.includes("--review")) {
|
|
178
229
|
modelOption = "--model opus";
|
|
230
|
+
trace("model:review", modelOption);
|
|
179
231
|
} else if (args.includes("--flash")) {
|
|
180
232
|
modelOption = "--model haiku";
|
|
233
|
+
trace("model:flash", modelOption);
|
|
181
234
|
} else {
|
|
182
235
|
const modelIndex = args.indexOf("--model");
|
|
183
236
|
if (modelIndex !== -1 && args[modelIndex + 1]) {
|
|
184
237
|
console.warn("\u26A0\uFE0F \uC9C0\uC815\uD55C \uBAA8\uB378\uC774 \uC5C6\uB294 \uACBD\uC6B0, \uC5D0\uB7EC\uAC00 \uBC1C\uC0DD\uD558\uB2C8 \uC8FC\uC758\uD558\uC138\uC694.");
|
|
185
238
|
modelOption = `--model ${args[modelIndex + 1]}`;
|
|
239
|
+
trace("model:custom", modelOption);
|
|
186
240
|
} else {
|
|
187
241
|
console.warn("\u26A0\uFE0F \uBAA8\uB378\uC774 \uC9C0\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uAE30\uBCF8 \uBAA8\uB378\uC778 sonnet\uC744 \uC0AC\uC6A9\uD569\uB2C8\uB2E4.");
|
|
188
242
|
modelOption = "--model sonnet";
|
|
243
|
+
trace("model:default", modelOption);
|
|
189
244
|
}
|
|
190
245
|
}
|
|
191
246
|
const rules = [
|
|
@@ -193,51 +248,152 @@ var createClaudeCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
|
193
248
|
{ path: namingRulesPath, display: "\uB124\uC774\uBC0D \uADDC\uCE59" },
|
|
194
249
|
{ path: codingConventionRulesPath, display: "\uCF54\uB529 \uCEE8\uBCA4\uC158" }
|
|
195
250
|
];
|
|
196
|
-
const systemPromptFiles = rules.filter((rule) =>
|
|
197
|
-
|
|
251
|
+
const systemPromptFiles = rules.filter((rule) => fs5.existsSync(rule.path)).map((rule) => `--append-system-prompt-file ${rule.path}`).join(" ");
|
|
252
|
+
trace(
|
|
253
|
+
"rules:loaded",
|
|
254
|
+
`count=${systemPromptFiles ? systemPromptFiles.split("--append-system-prompt-file").length - 1 : 0}`
|
|
255
|
+
);
|
|
256
|
+
const reviewFormOption = fs5.existsSync(reviewFormPath2) ? `--append-system-prompt-file ${reviewFormPath2}` : "";
|
|
257
|
+
trace("reviewForm:status", reviewFormOption ? "exists" : "missing");
|
|
198
258
|
const command = `cat ${tempDiffPath2} | claude ${modelOption} ${systemPromptFiles} ${reviewFormOption} -p "\uC704 \uADDC\uCE59\uB4E4\uC744 \uCC38\uACE0\uD558\uC5EC \uC774 diff\uB97C \uCF54\uB4DC\uB9AC\uBDF0\uD574\uC918. \uB9AC\uBDF0\uC591\uC2DD\uC5D0 \uB9DE\uCDB0\uC11C \uC791\uC131\uD574\uC918."`;
|
|
259
|
+
trace("command:created");
|
|
199
260
|
if (args.includes("--test")) {
|
|
200
261
|
const safeCommand = command.replace(/"/g, '\\"');
|
|
262
|
+
trace("test-mode:return-preview");
|
|
201
263
|
return `echo "[TEST MODE] Claude \uBA85\uB839\uC5B4\uAC00 \uC2E4\uD589\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.
|
|
202
264
|
|
|
203
265
|
\uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
|
|
204
266
|
${safeCommand}"`;
|
|
205
267
|
}
|
|
268
|
+
trace("createClaudeCommand:end");
|
|
206
269
|
return command;
|
|
207
270
|
};
|
|
271
|
+
var trace2 = createTraceLogger("installation-claude");
|
|
208
272
|
function checkClaudeCliInstalled() {
|
|
273
|
+
trace2("checkClaudeCliInstalled:start");
|
|
209
274
|
try {
|
|
275
|
+
trace2("version-check:run", "claude --version");
|
|
210
276
|
execSync("claude --version", { stdio: "ignore" });
|
|
277
|
+
trace2("version-check:ok");
|
|
211
278
|
} catch {
|
|
212
|
-
|
|
279
|
+
trace2("version-check:failed", "install-start");
|
|
280
|
+
console.log(
|
|
281
|
+
"\u2139\uFE0F claude-cli\uAC00 \uC124\uCE58\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC124\uCE58\uB97C \uC9C4\uD589\uD569\uB2C8\uB2E4... npm install -g @anthropic-ai/claude-code"
|
|
282
|
+
);
|
|
213
283
|
try {
|
|
214
284
|
execSync("npm install -g @anthropic-ai/claude-code", { stdio: "inherit" });
|
|
285
|
+
trace2("install:ok", "exit(1) for login");
|
|
215
286
|
console.log("\u2705 claude-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
216
287
|
console.log("\u26A0\uFE0F claude-cli \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
217
288
|
console.log(' \uD130\uBBF8\uB110\uC5D0\uC11C "claude" \uB97C \uC785\uB825\uD558\uC5EC \uBE0C\uB77C\uC6B0\uC800 \uB85C\uADF8\uC778\uC744 \uC644\uB8CC\uD55C \uD6C4, \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.');
|
|
218
289
|
process.exit(1);
|
|
219
290
|
} catch (installError) {
|
|
291
|
+
trace2("install:failed");
|
|
220
292
|
console.error("\u274C claude-cli \uC124\uCE58 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4. \uAD8C\uD55C \uBB38\uC81C\uC77C \uC218 \uC788\uC2B5\uB2C8\uB2E4 (sudo \uD544\uC694).");
|
|
221
293
|
console.error(installError);
|
|
222
294
|
process.exit(1);
|
|
223
295
|
}
|
|
224
296
|
}
|
|
297
|
+
trace2("checkClaudeCliInstalled:end");
|
|
225
298
|
}
|
|
226
299
|
var args2 = process.argv.slice(2);
|
|
227
|
-
var
|
|
300
|
+
var trace3 = createTraceLogger("codex-commander", args2);
|
|
301
|
+
var createCodexCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
302
|
+
trace3("createCodexCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
|
|
228
303
|
let modelOption = "";
|
|
229
304
|
if (args2.includes("--review")) {
|
|
230
|
-
modelOption = "--model
|
|
305
|
+
modelOption = "--model gpt-5";
|
|
306
|
+
trace3("model:review", modelOption);
|
|
231
307
|
} else if (args2.includes("--flash")) {
|
|
232
|
-
modelOption = "--model
|
|
308
|
+
modelOption = "--model gpt-5-mini";
|
|
309
|
+
trace3("model:flash", modelOption);
|
|
233
310
|
} else {
|
|
234
311
|
const modelIndex = args2.indexOf("--model");
|
|
235
312
|
if (modelIndex !== -1 && args2[modelIndex + 1]) {
|
|
236
313
|
console.warn("\u26A0\uFE0F \uC9C0\uC815\uD55C \uBAA8\uB378\uC774 \uC5C6\uB294 \uACBD\uC6B0, \uC5D0\uB7EC\uAC00 \uBC1C\uC0DD\uD558\uB2C8 \uC8FC\uC758\uD558\uC138\uC694.");
|
|
237
314
|
modelOption = `--model ${args2[modelIndex + 1]}`;
|
|
315
|
+
trace3("model:custom", modelOption);
|
|
316
|
+
} else {
|
|
317
|
+
console.warn("\u26A0\uFE0F \uBAA8\uB378\uC774 \uC9C0\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uAE30\uBCF8 \uBAA8\uB378\uC778 gpt-5-mini\uB97C \uC0AC\uC6A9\uD569\uB2C8\uB2E4.");
|
|
318
|
+
modelOption = "--model gpt-5-mini";
|
|
319
|
+
trace3("model:default", modelOption);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
const rules = [rulesPath, namingRulesPath, codingConventionRulesPath].filter((filePath) => fs5.existsSync(filePath)).map((filePath) => `- ${filePath}`).join("\n");
|
|
323
|
+
const rulesCount = rules ? rules.split("\n").length : 0;
|
|
324
|
+
trace3("rules:loaded", `count=${rulesCount}`);
|
|
325
|
+
const hasReviewForm = fs5.existsSync(reviewFormPath2);
|
|
326
|
+
const reviewFormLine = hasReviewForm ? `- ${reviewFormPath2}` : "";
|
|
327
|
+
trace3("reviewForm:status", reviewFormLine ? "exists" : "missing");
|
|
328
|
+
const prompt = `\uC544\uB798 \uD30C\uC77C\uB4E4\uC744 \uCC38\uACE0\uD574\uC11C \uCF54\uB4DC \uB9AC\uBDF0\uB97C \uC9C4\uD589\uD574\uC918.
|
|
329
|
+
\uADDC\uCE59 \uD30C\uC77C:
|
|
330
|
+
${rules || "- (\uC5C6\uC74C)"}
|
|
331
|
+
\uB9AC\uBDF0 \uC591\uC2DD \uD30C\uC77C:
|
|
332
|
+
${reviewFormLine || "- (\uC5C6\uC74C)"}
|
|
333
|
+
\uB9AC\uBDF0 \uB300\uC0C1 diff \uD30C\uC77C:
|
|
334
|
+
- ${tempDiffPath2}
|
|
335
|
+
|
|
336
|
+
\uBC18\uB4DC\uC2DC \uB9AC\uBDF0 \uC591\uC2DD\uC5D0 \uB9DE\uCDB0 \uC791\uC131\uD574\uC918.`;
|
|
337
|
+
const command = `codex exec ${modelOption} "${prompt.replace(/"/g, '\\"')}"`;
|
|
338
|
+
trace3("command:created");
|
|
339
|
+
if (args2.includes("--test")) {
|
|
340
|
+
const safeCommand = command.replace(/"/g, '\\"');
|
|
341
|
+
trace3("test-mode:return-preview");
|
|
342
|
+
return `echo "[TEST MODE] Codex \uBA85\uB839\uC5B4\uAC00 \uC2E4\uD589\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.
|
|
343
|
+
|
|
344
|
+
\uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
|
|
345
|
+
${safeCommand}"`;
|
|
346
|
+
}
|
|
347
|
+
trace3("createCodexCommand:end");
|
|
348
|
+
return command;
|
|
349
|
+
};
|
|
350
|
+
var trace4 = createTraceLogger("installation-codex");
|
|
351
|
+
function checkCodexCliInstalled() {
|
|
352
|
+
trace4("checkCodexCliInstalled:start");
|
|
353
|
+
try {
|
|
354
|
+
trace4("version-check:run", "codex --version");
|
|
355
|
+
execSync("codex --version", { stdio: "ignore" });
|
|
356
|
+
trace4("version-check:ok");
|
|
357
|
+
} catch {
|
|
358
|
+
trace4("version-check:failed", "install-start");
|
|
359
|
+
console.log("\u2139\uFE0F codex-cli\uAC00 \uC124\uCE58\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC124\uCE58\uB97C \uC9C4\uD589\uD569\uB2C8\uB2E4... npm install -g @openai/codex");
|
|
360
|
+
try {
|
|
361
|
+
execSync("npm install -g @openai/codex", { stdio: "inherit" });
|
|
362
|
+
trace4("install:ok", "exit(1) for login");
|
|
363
|
+
console.log("\u2705 codex-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
364
|
+
console.log("\u26A0\uFE0F codex-cli \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
365
|
+
console.log(' \uD130\uBBF8\uB110\uC5D0\uC11C "codex login" \uC744 \uC785\uB825\uD558\uC5EC \uB85C\uADF8\uC778\uC744 \uC644\uB8CC\uD55C \uD6C4, \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.');
|
|
366
|
+
process.exit(1);
|
|
367
|
+
} catch (installError) {
|
|
368
|
+
trace4("install:failed");
|
|
369
|
+
console.error("\u274C codex-cli \uC124\uCE58 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4. \uAD8C\uD55C \uBB38\uC81C\uC77C \uC218 \uC788\uC2B5\uB2C8\uB2E4 (sudo \uD544\uC694).");
|
|
370
|
+
console.error(installError);
|
|
371
|
+
process.exit(1);
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
trace4("checkCodexCliInstalled:end");
|
|
375
|
+
}
|
|
376
|
+
var args3 = process.argv.slice(2);
|
|
377
|
+
var trace5 = createTraceLogger("gemini-commander", args3);
|
|
378
|
+
var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
379
|
+
trace5("createGeminiCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
|
|
380
|
+
let modelOption = "";
|
|
381
|
+
if (args3.includes("--review")) {
|
|
382
|
+
modelOption = "--model pro";
|
|
383
|
+
trace5("model:review", modelOption);
|
|
384
|
+
} else if (args3.includes("--flash")) {
|
|
385
|
+
modelOption = "--model flash";
|
|
386
|
+
trace5("model:flash", modelOption);
|
|
387
|
+
} else {
|
|
388
|
+
const modelIndex = args3.indexOf("--model");
|
|
389
|
+
if (modelIndex !== -1 && args3[modelIndex + 1]) {
|
|
390
|
+
console.warn("\u26A0\uFE0F \uC9C0\uC815\uD55C \uBAA8\uB378\uC774 \uC5C6\uB294 \uACBD\uC6B0, \uC5D0\uB7EC\uAC00 \uBC1C\uC0DD\uD558\uB2C8 \uC8FC\uC758\uD558\uC138\uC694.");
|
|
391
|
+
modelOption = `--model ${args3[modelIndex + 1]}`;
|
|
392
|
+
trace5("model:custom", modelOption);
|
|
238
393
|
} else {
|
|
239
394
|
console.warn("\u26A0\uFE0F \uBAA8\uB378\uC774 \uC9C0\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uAE30\uBCF8 \uBAA8\uB378\uC778 gemini-flash\uB97C \uC0AC\uC6A9\uD569\uB2C8\uB2E4.");
|
|
240
395
|
modelOption = "--model flash";
|
|
396
|
+
trace5("model:default", modelOption);
|
|
241
397
|
}
|
|
242
398
|
}
|
|
243
399
|
const rules = [
|
|
@@ -245,76 +401,124 @@ var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
|
245
401
|
{ path: namingRulesPath, display: "\uB124\uC774\uBC0D \uADDC\uCE59" },
|
|
246
402
|
{ path: codingConventionRulesPath, display: "\uCF54\uB529 \uCEE8\uBCA4\uC158" }
|
|
247
403
|
];
|
|
248
|
-
const validRules = rules.filter((rule) =>
|
|
404
|
+
const validRules = rules.filter((rule) => fs5.existsSync(rule.path)).map((rule) => `@${rule.path}`).join(", ");
|
|
405
|
+
const rulesCount = validRules ? validRules.split(",").length : 0;
|
|
406
|
+
trace5("rules:loaded", `count=${rulesCount}`);
|
|
249
407
|
const command = `gemini ${modelOption} -p "\uB2E4\uC74C \uADDC\uCE59\uB4E4\uC744 \uCC38\uACE0\uD574\uC11C(${validRules}) \uC774 diff(@${tempDiffPath2})\uB97C \uB9AC\uBDF0\uD574\uC918. \uB9AC\uBDF0\uC591\uC2DD\uC740 @${reviewFormPath2} \uC5D0 \uB9DE\uCDB0\uC11C \uC791\uC131\uD574\uC918. "`;
|
|
250
|
-
|
|
408
|
+
trace5("command:created");
|
|
409
|
+
if (args3.includes("--test")) {
|
|
251
410
|
const safeCommand = command.replace(/"/g, '\\"');
|
|
411
|
+
trace5("test-mode:return-preview");
|
|
252
412
|
return `echo "[TEST MODE] Gemini \uBA85\uB839\uC5B4\uAC00 \uC2E4\uD589\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.
|
|
253
413
|
|
|
254
414
|
\uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
|
|
255
415
|
${safeCommand}"`;
|
|
256
416
|
}
|
|
417
|
+
trace5("createGeminiCommand:end");
|
|
257
418
|
return command;
|
|
258
419
|
};
|
|
420
|
+
var trace6 = createTraceLogger("installation-gemini");
|
|
259
421
|
function checkGeminiCliInstalled() {
|
|
422
|
+
trace6("checkGeminiCliInstalled:start");
|
|
260
423
|
try {
|
|
424
|
+
trace6("version-check:run", "gemini --version");
|
|
261
425
|
execSync("gemini --version", { stdio: "ignore" });
|
|
426
|
+
trace6("version-check:ok");
|
|
262
427
|
} catch {
|
|
428
|
+
trace6("version-check:failed", "install-start");
|
|
263
429
|
console.log("\u2139\uFE0F gemini-cli\uAC00 \uC124\uCE58\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC124\uCE58\uB97C \uC9C4\uD589\uD569\uB2C8\uB2E4... npm install -g @google/gemini-cli");
|
|
264
430
|
try {
|
|
265
431
|
execSync("npm install -g @google/gemini-cli", { stdio: "inherit" });
|
|
432
|
+
trace6("install:ok", "exit(1) for login");
|
|
266
433
|
console.log("\u2705 gemini-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
267
434
|
console.log("\u26A0\uFE0F Gemini API \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
268
435
|
console.log(' \uD130\uBBF8\uB110\uC5D0\uC11C "gemini" \uB97C \uC785\uB825\uD558\uC5EC \uBE0C\uB77C\uC6B0\uC800 \uB85C\uADF8\uC778\uC744 \uC644\uB8CC\uD55C \uD6C4, \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.');
|
|
269
436
|
process.exit(1);
|
|
270
437
|
} catch (installError) {
|
|
438
|
+
trace6("install:failed");
|
|
271
439
|
console.error("\u274C gemini-cli \uC124\uCE58 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4. \uAD8C\uD55C \uBB38\uC81C\uC77C \uC218 \uC788\uC2B5\uB2C8\uB2E4 (sudo \uD544\uC694).");
|
|
272
440
|
console.error(installError);
|
|
273
441
|
process.exit(1);
|
|
274
442
|
}
|
|
275
443
|
}
|
|
444
|
+
trace6("checkGeminiCliInstalled:end");
|
|
276
445
|
}
|
|
277
446
|
|
|
278
447
|
// src/pr-review/review-one-by-one.ts
|
|
279
448
|
var execAsync = util.promisify(exec);
|
|
280
449
|
async function main() {
|
|
281
|
-
const
|
|
282
|
-
const isTest =
|
|
450
|
+
const args4 = process.argv.slice(2);
|
|
451
|
+
const isTest = isTestMode(args4);
|
|
452
|
+
const trace7 = createTraceLogger("review-one-by-one", args4);
|
|
453
|
+
trace7("main:start", `args=${JSON.stringify(args4)}`);
|
|
454
|
+
trace7("service-selection:start");
|
|
283
455
|
const service = await showSelectionAIService();
|
|
456
|
+
trace7("service-selection:done", `service=${service}`);
|
|
284
457
|
switch (service) {
|
|
285
458
|
case "gemini":
|
|
459
|
+
trace7("install-check:start", "service=gemini");
|
|
286
460
|
checkGeminiCliInstalled();
|
|
461
|
+
trace7("install-check:done", "service=gemini");
|
|
287
462
|
break;
|
|
288
463
|
case "claude":
|
|
464
|
+
trace7("install-check:start", "service=claude");
|
|
289
465
|
checkClaudeCliInstalled();
|
|
466
|
+
trace7("install-check:done", "service=claude");
|
|
467
|
+
break;
|
|
468
|
+
case "codex":
|
|
469
|
+
trace7("install-check:start", "service=codex");
|
|
470
|
+
checkCodexCliInstalled();
|
|
471
|
+
trace7("install-check:done", "service=codex");
|
|
290
472
|
break;
|
|
291
473
|
}
|
|
292
474
|
try {
|
|
475
|
+
trace7("review-flow:start");
|
|
293
476
|
console.log("\u{1F680} AI Code Review\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4...");
|
|
477
|
+
trace7("report-dir:create:start");
|
|
294
478
|
createReportDirectory();
|
|
479
|
+
trace7("report-dir:create:done");
|
|
295
480
|
const { includeParams, excludeParams } = getGitDiffFilter();
|
|
481
|
+
trace7("diff-filter:loaded", `include=${includeParams} | exclude=${excludeParams}`);
|
|
296
482
|
const diffArgs = getDiffArgs();
|
|
483
|
+
trace7("diff-args:build:done", `diffArgs=${diffArgs || "(default)"}`);
|
|
297
484
|
const filesCommand = `git diff --name-only ${diffArgs} -- ${includeParams} ${excludeParams}`;
|
|
485
|
+
trace7("files-command:run", filesCommand);
|
|
298
486
|
const fileList = execSync(filesCommand).toString().split("\n").filter(Boolean);
|
|
487
|
+
trace7("files-command:done", `fileCount=${fileList.length}`);
|
|
299
488
|
if (fileList.length === 0) {
|
|
489
|
+
trace7("empty-file-list:exit");
|
|
300
490
|
console.log("\u2139\uFE0F \uBCC0\uACBD \uC0AC\uD56D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
301
491
|
deleteTempDiff();
|
|
302
492
|
process.exit(0);
|
|
303
493
|
}
|
|
304
494
|
const fullDiffCommand = `git diff ${diffArgs} -- ${includeParams} ${excludeParams}`;
|
|
495
|
+
trace7("full-diff:run");
|
|
305
496
|
const fullDiff = execSync(fullDiffCommand).toString();
|
|
306
497
|
const nowStr = getNowString();
|
|
307
|
-
|
|
498
|
+
trace7("full-diff:done", `length=${fullDiff.length}`);
|
|
499
|
+
trace7("timestamp:created", nowStr);
|
|
500
|
+
trace7("temp-diff:write:start", tempDiffPath);
|
|
501
|
+
fs5.writeFileSync(tempDiffPath, fullDiff);
|
|
502
|
+
trace7("temp-diff:write:done");
|
|
503
|
+
trace7("saved-diff:copy:start");
|
|
308
504
|
const savedDiffPath = getNextFilePath(REPORT_DIR, `${nowStr}-diff`, ".txt");
|
|
309
|
-
|
|
505
|
+
fs5.copyFileSync(tempDiffPath, savedDiffPath);
|
|
506
|
+
trace7("saved-diff:copy:done", savedDiffPath);
|
|
310
507
|
const savedReportPath = getNextFilePath(REPORT_DIR, nowStr, ".md");
|
|
508
|
+
trace7("saved-report:path", savedReportPath);
|
|
311
509
|
const promises = fileList.map(async (file) => {
|
|
312
510
|
try {
|
|
511
|
+
trace7("file-review:start", file);
|
|
313
512
|
console.log(`\u{1F50D} Reviewing: ${file}...`);
|
|
513
|
+
trace7("file-diff:run", file);
|
|
314
514
|
const fileDiff = execSync(`git diff ${diffArgs} -- "${file}"`).toString();
|
|
515
|
+
trace7("file-diff:done", `${file} | length=${fileDiff.length}`);
|
|
315
516
|
const tempOneFileDiffPath = `temp_diff_${file.replace(/\//g, "_")}.txt`;
|
|
316
|
-
|
|
517
|
+
trace7("file-temp-diff:write:start", tempOneFileDiffPath);
|
|
518
|
+
fs5.writeFileSync(tempOneFileDiffPath, fileDiff);
|
|
519
|
+
trace7("file-temp-diff:write:done", tempOneFileDiffPath);
|
|
317
520
|
let command = "";
|
|
521
|
+
trace7("file-command:create:start", file);
|
|
318
522
|
switch (service) {
|
|
319
523
|
case "gemini":
|
|
320
524
|
command = createGeminiCommand(tempOneFileDiffPath, reviewFormOneByOnePath);
|
|
@@ -323,25 +527,37 @@ async function main() {
|
|
|
323
527
|
command = createClaudeCommand(tempOneFileDiffPath, reviewFormOneByOnePath);
|
|
324
528
|
break;
|
|
325
529
|
case "codex":
|
|
530
|
+
command = createCodexCommand(tempOneFileDiffPath, reviewFormOneByOnePath);
|
|
326
531
|
break;
|
|
327
532
|
}
|
|
533
|
+
trace7("file-command:create:done", file);
|
|
534
|
+
trace7("file-command:exec:start", file);
|
|
328
535
|
const { stdout } = await execAsync(command, { maxBuffer: 1024 * 1024 * 20 });
|
|
329
536
|
const result = stdout.toString();
|
|
537
|
+
trace7("file-command:exec:done", `${file} | resultLength=${result.length}`);
|
|
538
|
+
trace7("file-temp-diff:delete:start", tempOneFileDiffPath);
|
|
330
539
|
deleteFile(tempOneFileDiffPath);
|
|
540
|
+
trace7("file-temp-diff:delete:done", tempOneFileDiffPath);
|
|
331
541
|
const tempReport = `### File: ${file}
|
|
332
542
|
${result}
|
|
333
543
|
|
|
334
544
|
`;
|
|
335
545
|
console.log(tempReport);
|
|
336
|
-
|
|
546
|
+
trace7("file-report:append:start", file);
|
|
547
|
+
fs5.appendFileSync(savedReportPath, tempReport);
|
|
548
|
+
trace7("file-report:append:done", file);
|
|
337
549
|
if (isTest) {
|
|
338
|
-
|
|
550
|
+
trace7("file-test-command:append:start", file);
|
|
551
|
+
fs5.appendFileSync(savedReportPath, `
|
|
339
552
|
|
|
340
553
|
## \uC0AC\uC6A9\uB41C \uBA85\uB839\uC5B4
|
|
341
554
|
|
|
342
555
|
${command}`);
|
|
556
|
+
trace7("file-test-command:append:done", file);
|
|
343
557
|
}
|
|
558
|
+
trace7("file-review:end", file);
|
|
344
559
|
} catch (err) {
|
|
560
|
+
trace7("file-review:catch", file);
|
|
345
561
|
console.error(`\u274C Error reviewing file ${file}:`, err);
|
|
346
562
|
const errorReport = `### File: ${file}
|
|
347
563
|
\u274C Review Failed
|
|
@@ -350,28 +566,41 @@ ${err}
|
|
|
350
566
|
\`\`\`
|
|
351
567
|
|
|
352
568
|
`;
|
|
353
|
-
|
|
569
|
+
fs5.appendFileSync(savedReportPath, errorReport);
|
|
354
570
|
try {
|
|
355
571
|
const tempOneFileDiffPath = `temp_diff_${file.replace(/\//g, "_")}.txt`;
|
|
356
|
-
if (
|
|
572
|
+
if (fs5.existsSync(tempOneFileDiffPath)) {
|
|
573
|
+
trace7("file-temp-diff:delete:start(catch)", tempOneFileDiffPath);
|
|
357
574
|
deleteFile(tempOneFileDiffPath);
|
|
575
|
+
trace7("file-temp-diff:delete:done(catch)", tempOneFileDiffPath);
|
|
358
576
|
}
|
|
359
577
|
} catch (e) {
|
|
578
|
+
trace7("file-temp-diff:delete:failed(catch)", file);
|
|
360
579
|
console.error(`\u274C Error deleting temp file for ${file}:`, e);
|
|
361
580
|
}
|
|
362
581
|
}
|
|
363
582
|
});
|
|
583
|
+
trace7("parallel-review:await-start");
|
|
364
584
|
await Promise.all(promises);
|
|
585
|
+
trace7("parallel-review:await-done");
|
|
365
586
|
console.log(`
|
|
366
587
|
\u2705 \uB9AC\uBDF0\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`);
|
|
367
588
|
console.log(`\u{1F4C4} \uB9AC\uD3EC\uD2B8 \uC800\uC7A5 \uC704\uCE58: ${savedReportPath}`);
|
|
368
589
|
console.log(`diff \uC800\uC7A5 \uC704\uCE58: ${savedDiffPath}`);
|
|
590
|
+
trace7("open-report:start");
|
|
369
591
|
openReport(savedReportPath);
|
|
592
|
+
trace7("open-report:done");
|
|
593
|
+
trace7("cleanup-temp-diff:start");
|
|
370
594
|
deleteTempDiff();
|
|
595
|
+
trace7("cleanup-temp-diff:done");
|
|
596
|
+
trace7("review-flow:end");
|
|
371
597
|
} catch (error) {
|
|
598
|
+
trace7("review-flow:catch");
|
|
372
599
|
console.error("\u274C \uB9AC\uBDF0 \uB3C4\uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
|
|
373
600
|
console.error(error);
|
|
601
|
+
trace7("cleanup-temp-diff:start(catch)");
|
|
374
602
|
deleteTempDiff();
|
|
603
|
+
trace7("cleanup-temp-diff:done(catch)");
|
|
375
604
|
process.exit(1);
|
|
376
605
|
}
|
|
377
606
|
}
|