sales-frontend-gemini-cli 0.3.1 → 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.
Files changed (77) hide show
  1. package/dist/common/helper.cjs +54 -3
  2. package/dist/common/helper.cjs.map +1 -1
  3. package/dist/common/helper.d.cts +15 -1
  4. package/dist/common/helper.d.ts +15 -1
  5. package/dist/common/helper.js +53 -4
  6. package/dist/common/helper.js.map +1 -1
  7. package/dist/{pr-review/gemini → etc}/installation-gcloud.cjs +1 -1
  8. package/dist/etc/installation-gcloud.cjs.map +1 -0
  9. package/dist/{pr-review/gemini → etc}/installation-gcloud.js +1 -1
  10. package/dist/etc/installation-gcloud.js.map +1 -0
  11. package/dist/{pr-review/gemini → etc}/interactive-version/index.cjs +2 -2
  12. package/dist/etc/interactive-version/index.cjs.map +1 -0
  13. package/dist/{pr-review/gemini → etc}/interactive-version/index.js +2 -2
  14. package/dist/etc/interactive-version/index.js.map +1 -0
  15. package/dist/{pr-review/gemini → etc}/login.cjs +1 -1
  16. package/dist/etc/login.cjs.map +1 -0
  17. package/dist/{pr-review/gemini → etc}/login.js +1 -1
  18. package/dist/etc/login.js.map +1 -0
  19. package/dist/{pr-review/gemini → etc}/vertex-version/index.cjs +1 -1
  20. package/dist/etc/vertex-version/index.cjs.map +1 -0
  21. package/dist/{pr-review/gemini → etc}/vertex-version/index.js +1 -1
  22. package/dist/etc/vertex-version/index.js.map +1 -0
  23. package/dist/pr-review/claude/claude-commander.cjs +26 -0
  24. package/dist/pr-review/claude/claude-commander.cjs.map +1 -1
  25. package/dist/pr-review/claude/claude-commander.js +26 -0
  26. package/dist/pr-review/claude/claude-commander.js.map +1 -1
  27. package/dist/pr-review/claude/installation-claude.cjs +38 -1
  28. package/dist/pr-review/claude/installation-claude.cjs.map +1 -1
  29. package/dist/pr-review/claude/installation-claude.js +33 -1
  30. package/dist/pr-review/claude/installation-claude.js.map +1 -1
  31. package/dist/pr-review/codex/codex-commander.cjs +88 -0
  32. package/dist/pr-review/codex/codex-commander.cjs.map +1 -0
  33. package/dist/pr-review/codex/codex-commander.d.cts +12 -0
  34. package/dist/pr-review/codex/codex-commander.d.ts +12 -0
  35. package/dist/pr-review/codex/codex-commander.js +80 -0
  36. package/dist/pr-review/codex/codex-commander.js.map +1 -0
  37. package/dist/pr-review/codex/installation-codex.cjs +62 -0
  38. package/dist/pr-review/codex/installation-codex.cjs.map +1 -0
  39. package/dist/pr-review/codex/installation-codex.d.cts +3 -0
  40. package/dist/pr-review/codex/installation-codex.d.ts +3 -0
  41. package/dist/pr-review/codex/installation-codex.js +55 -0
  42. package/dist/pr-review/codex/installation-codex.js.map +1 -0
  43. package/dist/pr-review/gemini/gemini-commander.cjs +23 -0
  44. package/dist/pr-review/gemini/gemini-commander.cjs.map +1 -1
  45. package/dist/pr-review/gemini/gemini-commander.js +23 -0
  46. package/dist/pr-review/gemini/gemini-commander.js.map +1 -1
  47. package/dist/pr-review/gemini/installation-gemini.cjs +35 -0
  48. package/dist/pr-review/gemini/installation-gemini.cjs.map +1 -1
  49. package/dist/pr-review/gemini/installation-gemini.js +30 -0
  50. package/dist/pr-review/gemini/installation-gemini.js.map +1 -1
  51. package/dist/pr-review/review-one-by-one.cjs +260 -31
  52. package/dist/pr-review/review-one-by-one.cjs.map +1 -1
  53. package/dist/pr-review/review-one-by-one.js +259 -30
  54. package/dist/pr-review/review-one-by-one.js.map +1 -1
  55. package/dist/pr-review/review.cjs +228 -14
  56. package/dist/pr-review/review.cjs.map +1 -1
  57. package/dist/pr-review/review.js +228 -14
  58. package/dist/pr-review/review.js.map +1 -1
  59. package/package.json +1 -1
  60. package/src/common/form/review-form.md +1 -1
  61. package/src/common/rules/review-rules.md +2 -0
  62. package/dist/pr-review/gemini/installation-gcloud.cjs.map +0 -1
  63. package/dist/pr-review/gemini/installation-gcloud.js.map +0 -1
  64. package/dist/pr-review/gemini/interactive-version/index.cjs.map +0 -1
  65. package/dist/pr-review/gemini/interactive-version/index.js.map +0 -1
  66. package/dist/pr-review/gemini/login.cjs.map +0 -1
  67. package/dist/pr-review/gemini/login.js.map +0 -1
  68. package/dist/pr-review/gemini/vertex-version/index.cjs.map +0 -1
  69. package/dist/pr-review/gemini/vertex-version/index.js.map +0 -1
  70. /package/dist/{pr-review/gemini → etc}/installation-gcloud.d.cts +0 -0
  71. /package/dist/{pr-review/gemini → etc}/installation-gcloud.d.ts +0 -0
  72. /package/dist/{pr-review/gemini → etc}/interactive-version/index.d.cts +0 -0
  73. /package/dist/{pr-review/gemini → etc}/interactive-version/index.d.ts +0 -0
  74. /package/dist/{pr-review/gemini → etc}/login.d.cts +0 -0
  75. /package/dist/{pr-review/gemini → etc}/login.d.ts +0 -0
  76. /package/dist/{pr-review/gemini → etc}/vertex-version/index.d.cts +0 -0
  77. /package/dist/{pr-review/gemini → etc}/vertex-version/index.d.ts +0 -0
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { exec, execSync } from 'child_process';
3
- import fs4 from 'fs';
3
+ import fs5 from 'fs';
4
4
  import util from 'util';
5
5
  import path from 'path';
6
6
  import readline from 'readline';
@@ -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 (!fs4.existsSync(filePath)) {
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 (fs4.existsSync(filePath)) {
44
- fs4.unlinkSync(filePath);
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 (!fs4.existsSync(REPORT_DIR)) {
52
- fs4.mkdirSync(REPORT_DIR, { recursive: true });
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
- execSync(`open -a "Google Chrome" "${path.resolve(reportPath)}"`);
76
- console.log(`\u{1F680} \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB9AC\uD3EC\uD2B8\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4.`);
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 args3 = process.argv.slice(2);
83
- const commitIndex = args3.indexOf("--commit");
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 = args3[commitIndex + 1];
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 = args3[commitIndex + 2];
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("\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");
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) => fs4.existsSync(rule.path)).map((rule) => `--append-system-prompt-file ${rule.path}`).join(" ");
197
- const reviewFormOption = fs4.existsSync(reviewFormPath2) ? `--append-system-prompt-file ${reviewFormPath2}` : "";
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
- console.log("\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");
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 createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
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 pro";
305
+ modelOption = "--model gpt-5";
306
+ trace3("model:review", modelOption);
231
307
  } else if (args2.includes("--flash")) {
232
- modelOption = "--model flash";
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) => fs4.existsSync(rule.path)).map((rule) => `@${rule.path}`).join(", ");
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
- if (args2.includes("--test")) {
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 args3 = process.argv.slice(2);
282
- const isTest = args3.includes("--test");
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
- fs4.writeFileSync(tempDiffPath, fullDiff);
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
- fs4.copyFileSync(tempDiffPath, savedDiffPath);
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
- fs4.writeFileSync(tempOneFileDiffPath, fileDiff);
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
- fs4.appendFileSync(savedReportPath, tempReport);
546
+ trace7("file-report:append:start", file);
547
+ fs5.appendFileSync(savedReportPath, tempReport);
548
+ trace7("file-report:append:done", file);
337
549
  if (isTest) {
338
- fs4.appendFileSync(savedReportPath, `
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
- fs4.appendFileSync(savedReportPath, errorReport);
569
+ fs5.appendFileSync(savedReportPath, errorReport);
354
570
  try {
355
571
  const tempOneFileDiffPath = `temp_diff_${file.replace(/\//g, "_")}.txt`;
356
- if (fs4.existsSync(tempOneFileDiffPath)) {
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
  }