sales-frontend-gemini-cli 0.3.1 → 0.4.1

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 (81) hide show
  1. package/dist/common/helper.cjs +77 -6
  2. package/dist/common/helper.cjs.map +1 -1
  3. package/dist/common/helper.d.cts +16 -2
  4. package/dist/common/helper.d.ts +16 -2
  5. package/dist/common/helper.js +76 -7
  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 +150 -17
  24. package/dist/pr-review/claude/claude-commander.cjs.map +1 -1
  25. package/dist/pr-review/claude/claude-commander.d.cts +7 -8
  26. package/dist/pr-review/claude/claude-commander.d.ts +7 -8
  27. package/dist/pr-review/claude/claude-commander.js +150 -17
  28. package/dist/pr-review/claude/claude-commander.js.map +1 -1
  29. package/dist/pr-review/claude/installation-claude.cjs +38 -1
  30. package/dist/pr-review/claude/installation-claude.cjs.map +1 -1
  31. package/dist/pr-review/claude/installation-claude.js +33 -1
  32. package/dist/pr-review/claude/installation-claude.js.map +1 -1
  33. package/dist/pr-review/codex/codex-commander.cjs +126 -0
  34. package/dist/pr-review/codex/codex-commander.cjs.map +1 -0
  35. package/dist/pr-review/codex/codex-commander.d.cts +17 -0
  36. package/dist/pr-review/codex/codex-commander.d.ts +17 -0
  37. package/dist/pr-review/codex/codex-commander.js +118 -0
  38. package/dist/pr-review/codex/codex-commander.js.map +1 -0
  39. package/dist/pr-review/codex/installation-codex.cjs +62 -0
  40. package/dist/pr-review/codex/installation-codex.cjs.map +1 -0
  41. package/dist/pr-review/codex/installation-codex.d.cts +3 -0
  42. package/dist/pr-review/codex/installation-codex.d.ts +3 -0
  43. package/dist/pr-review/codex/installation-codex.js +55 -0
  44. package/dist/pr-review/codex/installation-codex.js.map +1 -0
  45. package/dist/pr-review/gemini/gemini-commander.cjs +133 -15
  46. package/dist/pr-review/gemini/gemini-commander.cjs.map +1 -1
  47. package/dist/pr-review/gemini/gemini-commander.d.cts +10 -13
  48. package/dist/pr-review/gemini/gemini-commander.d.ts +10 -13
  49. package/dist/pr-review/gemini/gemini-commander.js +133 -15
  50. package/dist/pr-review/gemini/gemini-commander.js.map +1 -1
  51. package/dist/pr-review/gemini/installation-gemini.cjs +35 -0
  52. package/dist/pr-review/gemini/installation-gemini.cjs.map +1 -1
  53. package/dist/pr-review/gemini/installation-gemini.js +30 -0
  54. package/dist/pr-review/gemini/installation-gemini.js.map +1 -1
  55. package/dist/pr-review/review-one-by-one.cjs +547 -56
  56. package/dist/pr-review/review-one-by-one.cjs.map +1 -1
  57. package/dist/pr-review/review-one-by-one.js +546 -55
  58. package/dist/pr-review/review-one-by-one.js.map +1 -1
  59. package/dist/pr-review/review.cjs +517 -41
  60. package/dist/pr-review/review.cjs.map +1 -1
  61. package/dist/pr-review/review.js +517 -41
  62. package/dist/pr-review/review.js.map +1 -1
  63. package/package.json +1 -1
  64. package/src/common/form/review-form.md +1 -1
  65. package/src/common/rules/review-rules.md +2 -0
  66. package/dist/pr-review/gemini/installation-gcloud.cjs.map +0 -1
  67. package/dist/pr-review/gemini/installation-gcloud.js.map +0 -1
  68. package/dist/pr-review/gemini/interactive-version/index.cjs.map +0 -1
  69. package/dist/pr-review/gemini/interactive-version/index.js.map +0 -1
  70. package/dist/pr-review/gemini/login.cjs.map +0 -1
  71. package/dist/pr-review/gemini/login.js.map +0 -1
  72. package/dist/pr-review/gemini/vertex-version/index.cjs.map +0 -1
  73. package/dist/pr-review/gemini/vertex-version/index.js.map +0 -1
  74. /package/dist/{pr-review/gemini → etc}/installation-gcloud.d.cts +0 -0
  75. /package/dist/{pr-review/gemini → etc}/installation-gcloud.d.ts +0 -0
  76. /package/dist/{pr-review/gemini → etc}/interactive-version/index.d.cts +0 -0
  77. /package/dist/{pr-review/gemini → etc}/interactive-version/index.d.ts +0 -0
  78. /package/dist/{pr-review/gemini → etc}/login.d.cts +0 -0
  79. /package/dist/{pr-review/gemini → etc}/login.d.ts +0 -0
  80. /package/dist/{pr-review/gemini → etc}/vertex-version/index.d.cts +0 -0
  81. /package/dist/{pr-review/gemini → etc}/vertex-version/index.d.ts +0 -0
@@ -28,6 +28,33 @@ var ignoreList = [
28
28
  ".review-report/"
29
29
  // 생성되는 리포트 폴더도 제외
30
30
  ];
31
+ function parseServiceFromArgs(args4 = process.argv.slice(2)) {
32
+ const serviceIndex = args4.indexOf("--service");
33
+ const rawService = serviceIndex !== -1 ? args4[serviceIndex + 1] : "";
34
+ if (!rawService) {
35
+ return "";
36
+ }
37
+ const normalizedService = rawService.toLowerCase();
38
+ if (AIServices.includes(normalizedService)) {
39
+ return normalizedService;
40
+ }
41
+ console.error(
42
+ `\u274C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uC11C\uBE44\uC2A4\uC785\uB2C8\uB2E4: ${rawService}. \uC0AC\uC6A9 \uAC00\uB2A5 \uAC12: ${AIServices.join(", ")} (\uC608: --service codex)`
43
+ );
44
+ process.exit(1);
45
+ }
46
+ function isTestMode(args4 = process.argv.slice(2)) {
47
+ return args4.includes("--test");
48
+ }
49
+ function createTraceLogger(scope, args4 = process.argv.slice(2)) {
50
+ const enabled = isTestMode(args4);
51
+ return (step, detail) => {
52
+ if (!enabled) {
53
+ return;
54
+ }
55
+ console.log(`[TRACE][${scope}] ${step}${detail ? ` | ${detail}` : ""}`);
56
+ };
57
+ }
31
58
  function getNextFilePath(dir, baseName, extension) {
32
59
  let counter = 1;
33
60
  while (true) {
@@ -70,25 +97,60 @@ function getGitDiffFilter() {
70
97
  return { includeParams, excludeParams };
71
98
  }
72
99
  function openReport(reportPath) {
100
+ const resolvedPath = path.resolve(reportPath);
101
+ const { platform } = process;
102
+ const openWithChrome = () => {
103
+ if (platform === "darwin") {
104
+ execSync(`open -a "Google Chrome" "${resolvedPath}"`, { stdio: "ignore" });
105
+ return true;
106
+ }
107
+ if (platform === "linux") {
108
+ execSync(`google-chrome "${resolvedPath}"`, { stdio: "ignore" });
109
+ return true;
110
+ }
111
+ return false;
112
+ };
113
+ const openWithDefaultBrowser = () => {
114
+ if (platform === "darwin") {
115
+ execSync(`open "${resolvedPath}"`, { stdio: "ignore" });
116
+ return true;
117
+ }
118
+ if (platform === "linux") {
119
+ execSync(`xdg-open "${resolvedPath}"`, { stdio: "ignore" });
120
+ return true;
121
+ }
122
+ return false;
123
+ };
73
124
  try {
74
- execSync(`open -a "Google Chrome" "${path.resolve(reportPath)}"`);
75
- console.log(`\u{1F680} \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB9AC\uD3EC\uD2B8\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4.`);
125
+ if (openWithChrome()) {
126
+ console.log("\u{1F680} Google Chrome\uC5D0\uC11C \uB9AC\uD3EC\uD2B8\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4.");
127
+ return;
128
+ }
129
+ } catch {
130
+ }
131
+ try {
132
+ if (openWithDefaultBrowser()) {
133
+ console.log("\u{1F680} \uAE30\uBCF8 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB9AC\uD3EC\uD2B8\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4.");
134
+ return;
135
+ }
76
136
  } catch (e) {
77
137
  console.error("\u26A0\uFE0F \uBE0C\uB77C\uC6B0\uC800 \uC5F4\uAE30 \uC2E4\uD328:", e);
138
+ return;
78
139
  }
140
+ console.error(`\u26A0\uFE0F \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD50C\uB7AB\uD3FC\uC785\uB2C8\uB2E4: ${platform}`);
79
141
  }
80
142
  function getDiffArgs() {
81
- const args3 = process.argv.slice(2);
82
- const commitIndex = args3.indexOf("--commit");
143
+ const args4 = process.argv.slice(2);
144
+ const commitIndex = args4.indexOf("--commit");
83
145
  const { includeParams, excludeParams } = getGitDiffFilter();
84
146
  let diffArgs = "";
85
147
  if (commitIndex !== -1) {
86
- const commitHash = args3[commitIndex + 1];
148
+ const commitHash = args4[commitIndex + 1];
87
149
  if (!commitHash) {
88
150
  console.error("\u274C \uCEE4\uBC0B \uD574\uC2DC\uAC00 \uC81C\uACF5\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
89
151
  process.exit(1);
90
152
  }
91
- const nextArg = args3[commitIndex + 2];
153
+ const nextArg = args4[commitIndex + 2];
92
154
  let n = 0;
93
155
  if (nextArg && !nextArg.startsWith("--")) {
94
156
  n = parseInt(nextArg, 10);
@@ -111,6 +173,13 @@ function getDiffArgs() {
111
173
  return diffArgs;
112
174
  }
113
175
  async function showSelectionAIService() {
176
+ const selectedServiceFromArgs = parseServiceFromArgs();
177
+ if (selectedServiceFromArgs) {
178
+ console.log(`
179
+ \u2705 \x1B[32m${selectedServiceFromArgs}\x1B[0m \uC11C\uBE44\uC2A4\uAC00 \uC120\uD0DD\uB418\uC5C8\uC2B5\uB2C8\uB2E4. (--service)
180
+ `);
181
+ return selectedServiceFromArgs;
182
+ }
114
183
  let selectedIndex = 0;
115
184
  const rl = readline.createInterface({
116
185
  input: process.stdin,
@@ -125,7 +194,9 @@ async function showSelectionAIService() {
125
194
  }
126
195
  firstRender = false;
127
196
  readline.clearScreenDown(process.stdout);
128
- 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");
197
+ process.stdout.write(
198
+ "\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"
199
+ );
129
200
  AIServices.forEach((service, index) => {
130
201
  if (index === selectedIndex) {
131
202
  process.stdout.write(` \x1B[36m>\x1B[0m \x1B[36m\u25C9\x1B[0m \x1B[1m${service}\x1B[0m
@@ -171,142 +242,531 @@ async function showSelectionAIService() {
171
242
  });
172
243
  }
173
244
  var args = process.argv.slice(2);
174
- var createClaudeCommand = (tempDiffPath2, reviewFormPath2) => {
175
- let modelOption = "";
176
- if (args.includes("--review")) {
177
- modelOption = "--model opus";
178
- } else if (args.includes("--flash")) {
179
- modelOption = "--model haiku";
180
- } else {
181
- const modelIndex = args.indexOf("--model");
182
- if (modelIndex !== -1 && args[modelIndex + 1]) {
183
- 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.");
184
- modelOption = `--model ${args[modelIndex + 1]}`;
185
- } else {
186
- 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.");
187
- modelOption = "--model sonnet";
245
+ var trace = createTraceLogger("claude-commander", args);
246
+ var ALLOWED_REASONING_EFFORTS = ["minimal", "low", "medium", "high"];
247
+ function shellQuote(value) {
248
+ return `'${value.replace(/'/g, `'\\''`)}'`;
249
+ }
250
+ function getArgValue(flag) {
251
+ const index = args.indexOf(flag);
252
+ if (index === -1 || !args[index + 1]) {
253
+ return "";
254
+ }
255
+ return args[index + 1];
256
+ }
257
+ function toUnique(values) {
258
+ const seen = /* @__PURE__ */ new Set();
259
+ return values.filter((value) => {
260
+ if (!value || seen.has(value)) {
261
+ return false;
188
262
  }
263
+ seen.add(value);
264
+ return true;
265
+ });
266
+ }
267
+ function normalizeEffort(level) {
268
+ if (level === "minimal") {
269
+ return "low";
270
+ }
271
+ return level;
272
+ }
273
+ function resolveReasoningEffort() {
274
+ const customReasoningEffort = getArgValue("--reasoning-effort") || getArgValue("--effort");
275
+ if (customReasoningEffort) {
276
+ if (ALLOWED_REASONING_EFFORTS.includes(customReasoningEffort)) {
277
+ const normalized = normalizeEffort(customReasoningEffort);
278
+ trace("reasoning:custom", `${customReasoningEffort} -> ${normalized}`);
279
+ if (customReasoningEffort === "minimal") {
280
+ console.warn("\u26A0\uFE0F Claude\uB294 minimal\uC744 \uC9C1\uC811 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC544 low\uB85C \uB9E4\uD551\uD569\uB2C8\uB2E4.");
281
+ }
282
+ return normalized;
283
+ }
284
+ console.warn(
285
+ `\u26A0\uFE0F \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 reasoning effort(${customReasoningEffort})\uC785\uB2C8\uB2E4. allowed: ${ALLOWED_REASONING_EFFORTS.join(
286
+ ", "
287
+ )}`
288
+ );
289
+ }
290
+ if (args.includes("--flash")) {
291
+ trace("reasoning:flash-default", "low");
292
+ return "low";
189
293
  }
294
+ if (args.includes("--review")) {
295
+ trace("reasoning:review-default", "high");
296
+ return "high";
297
+ }
298
+ trace("reasoning:default", "medium");
299
+ return "medium";
300
+ }
301
+ function resolvePrimaryAlias() {
302
+ if (args.includes("--review")) {
303
+ trace("model:mode-alias", "opus");
304
+ return "opus";
305
+ }
306
+ if (args.includes("--flash")) {
307
+ trace("model:mode-alias", "haiku");
308
+ return "haiku";
309
+ }
310
+ trace("model:default-alias", "sonnet");
311
+ return "sonnet";
312
+ }
313
+ function getAliasFallbacks(primaryAlias) {
314
+ if (primaryAlias === "opus") {
315
+ return ["opus", "sonnet", "haiku"];
316
+ }
317
+ if (primaryAlias === "haiku") {
318
+ return ["haiku", "sonnet"];
319
+ }
320
+ return [primaryAlias, "sonnet", "haiku"];
321
+ }
322
+ function buildClaudeExecCommand(options) {
323
+ const { tempDiffPath: tempDiffPath2, prompt, systemPromptFiles, effort, model, fallbackModel } = options;
324
+ const modelOption = model ? `--model ${shellQuote(model)}` : "";
325
+ const fallbackOption = model && fallbackModel ? `--fallback-model ${shellQuote(fallbackModel)}` : "";
326
+ const effortOption = `--effort ${shellQuote(effort)}`;
327
+ const appendedPromptFiles = systemPromptFiles.map((path2) => `--append-system-prompt-file ${shellQuote(path2)}`).join(" ");
328
+ return `cat ${shellQuote(tempDiffPath2)} | claude ${[
329
+ modelOption,
330
+ fallbackOption,
331
+ effortOption,
332
+ appendedPromptFiles,
333
+ "-p",
334
+ shellQuote(prompt)
335
+ ].filter(Boolean).join(" ")}`;
336
+ }
337
+ var createClaudeCommand = (tempDiffPath2, reviewFormPath2) => {
338
+ trace("createClaudeCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
339
+ const customModel = getArgValue("--model");
340
+ const effort = resolveReasoningEffort();
341
+ const primaryAlias = resolvePrimaryAlias();
342
+ const aliasFallbacks = toUnique(getAliasFallbacks(primaryAlias));
190
343
  const rules = [
191
344
  { path: rulesPath, display: "\uB8F0\uC14B" },
192
345
  { path: namingRulesPath, display: "\uB124\uC774\uBC0D \uADDC\uCE59" },
193
346
  { path: codingConventionRulesPath, display: "\uCF54\uB529 \uCEE8\uBCA4\uC158" }
194
347
  ];
195
- const systemPromptFiles = rules.filter((rule) => fs.existsSync(rule.path)).map((rule) => `--append-system-prompt-file ${rule.path}`).join(" ");
196
- const reviewFormOption = fs.existsSync(reviewFormPath2) ? `--append-system-prompt-file ${reviewFormPath2}` : "";
197
- 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."`;
348
+ const existingRuleFiles = rules.filter((rule) => fs.existsSync(rule.path)).map((rule) => rule.path);
349
+ trace("rules:loaded", `count=${existingRuleFiles.length}`);
350
+ const reviewFormExists = fs.existsSync(reviewFormPath2);
351
+ trace("reviewForm:status", reviewFormExists ? "exists" : "missing");
352
+ const systemPromptFiles = reviewFormExists ? [...existingRuleFiles, reviewFormPath2] : existingRuleFiles;
353
+ const prompt = "\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.";
354
+ const modelCandidates = toUnique(customModel ? [customModel, ...aliasFallbacks] : aliasFallbacks);
355
+ trace("model:candidates", modelCandidates.join(", "));
356
+ if (customModel) {
357
+ console.warn(
358
+ `\u26A0\uFE0F \uCEE4\uC2A4\uD140 \uBAA8\uB378(${customModel})\uC744 \uC6B0\uC120 \uC2DC\uB3C4\uD558\uACE0 \uC2E4\uD328\uD558\uBA74 alias(${aliasFallbacks.join(
359
+ " -> "
360
+ )}) \uBC0F \uAE30\uBCF8 \uBAA8\uB378 \uC21C\uC73C\uB85C \uD3F4\uBC31\uD569\uB2C8\uB2E4.`
361
+ );
362
+ } else {
363
+ console.warn(
364
+ `\u26A0\uFE0F \uBAA8\uB378\uC774 \uC9C0\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. alias(${aliasFallbacks.join(" -> ")})\uB97C \uC21C\uCC28 \uC2DC\uB3C4\uD558\uACE0 \uB9C8\uC9C0\uB9C9\uC5D0 \uAE30\uBCF8 \uBAA8\uB378\uB85C \uD3F4\uBC31\uD569\uB2C8\uB2E4.`
365
+ );
366
+ }
367
+ const commandCandidates = modelCandidates.map((model, index) => {
368
+ const fallbackModel = modelCandidates[index + 1];
369
+ return buildClaudeExecCommand({
370
+ tempDiffPath: tempDiffPath2,
371
+ prompt,
372
+ systemPromptFiles,
373
+ effort,
374
+ model,
375
+ fallbackModel
376
+ });
377
+ });
378
+ const command = [
379
+ ...commandCandidates,
380
+ buildClaudeExecCommand({
381
+ tempDiffPath: tempDiffPath2,
382
+ prompt,
383
+ systemPromptFiles,
384
+ effort
385
+ })
386
+ ].join(" || ");
387
+ trace("command:created");
198
388
  if (args.includes("--test")) {
199
389
  const safeCommand = command.replace(/"/g, '\\"');
390
+ trace("test-mode:return-preview");
200
391
  return `echo "[TEST MODE] Claude \uBA85\uB839\uC5B4\uAC00 \uC2E4\uD589\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.
201
392
 
202
393
  \uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
203
394
  ${safeCommand}"`;
204
395
  }
396
+ trace("createClaudeCommand:end");
205
397
  return command;
206
398
  };
399
+ var trace2 = createTraceLogger("installation-claude");
207
400
  function checkClaudeCliInstalled() {
401
+ trace2("checkClaudeCliInstalled:start");
208
402
  try {
403
+ trace2("version-check:run", "claude --version");
209
404
  execSync("claude --version", { stdio: "ignore" });
405
+ trace2("version-check:ok");
210
406
  } catch {
211
- 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");
407
+ trace2("version-check:failed", "install-start");
408
+ console.log(
409
+ "\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"
410
+ );
212
411
  try {
213
412
  execSync("npm install -g @anthropic-ai/claude-code", { stdio: "inherit" });
413
+ trace2("install:ok", "exit(1) for login");
214
414
  console.log("\u2705 claude-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
215
415
  console.log("\u26A0\uFE0F claude-cli \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
216
416
  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.');
217
417
  process.exit(1);
218
418
  } catch (installError) {
419
+ trace2("install:failed");
219
420
  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).");
220
421
  console.error(installError);
221
422
  process.exit(1);
222
423
  }
223
424
  }
425
+ trace2("checkClaudeCliInstalled:end");
224
426
  }
225
427
  var args2 = process.argv.slice(2);
226
- var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
227
- let modelOption = "";
428
+ var trace3 = createTraceLogger("codex-commander", args2);
429
+ var ALLOWED_REASONING_EFFORTS2 = ["minimal", "low", "medium", "high"];
430
+ function shellQuote2(value) {
431
+ return `'${value.replace(/'/g, `'\\''`)}'`;
432
+ }
433
+ function getArgValue2(flag) {
434
+ const index = args2.indexOf(flag);
435
+ if (index === -1 || !args2[index + 1]) {
436
+ return "";
437
+ }
438
+ return args2[index + 1];
439
+ }
440
+ function resolveReasoningEffort2() {
441
+ const customReasoningEffort = getArgValue2("--reasoning-effort");
442
+ if (customReasoningEffort) {
443
+ if (ALLOWED_REASONING_EFFORTS2.includes(customReasoningEffort)) {
444
+ trace3("reasoning:custom", customReasoningEffort);
445
+ return customReasoningEffort;
446
+ }
447
+ console.warn(
448
+ `\u26A0\uFE0F \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 reasoning effort(${customReasoningEffort})\uC785\uB2C8\uB2E4. allowed: ${ALLOWED_REASONING_EFFORTS2.join(
449
+ ", "
450
+ )}`
451
+ );
452
+ }
453
+ if (args2.includes("--flash")) {
454
+ trace3("reasoning:flash-default", "minimal");
455
+ return "minimal";
456
+ }
228
457
  if (args2.includes("--review")) {
229
- modelOption = "--model pro";
230
- } else if (args2.includes("--flash")) {
231
- modelOption = "--model flash";
458
+ trace3("reasoning:review-default", "high");
459
+ return "high";
460
+ }
461
+ trace3("reasoning:default", "medium");
462
+ return "medium";
463
+ }
464
+ function buildCodexExecCommand(prompt, reasoningEffort, model) {
465
+ const modelOption = model ? `--model ${shellQuote2(model)}` : "";
466
+ const reasoningOption = `-c ${shellQuote2(`model_reasoning_effort="${reasoningEffort}"`)}`;
467
+ return `codex exec ${[modelOption, reasoningOption, shellQuote2(prompt)].filter(Boolean).join(" ")}`;
468
+ }
469
+ var createCodexCommand = (tempDiffPath2, reviewFormPath2) => {
470
+ trace3("createCodexCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
471
+ const customModel = getArgValue2("--model");
472
+ const reasoningEffort = resolveReasoningEffort2();
473
+ const rules = [rulesPath, namingRulesPath, codingConventionRulesPath].filter((filePath) => fs.existsSync(filePath)).map((filePath) => `- ${filePath}`).join("\n");
474
+ const rulesCount = rules ? rules.split("\n").length : 0;
475
+ trace3("rules:loaded", `count=${rulesCount}`);
476
+ const hasReviewForm = fs.existsSync(reviewFormPath2);
477
+ const reviewFormLine = hasReviewForm ? `- ${reviewFormPath2}` : "";
478
+ trace3("reviewForm:status", reviewFormLine ? "exists" : "missing");
479
+ const prompt = `\uC544\uB798 \uD30C\uC77C\uB4E4\uC744 \uCC38\uACE0\uD574\uC11C \uCF54\uB4DC \uB9AC\uBDF0\uB97C \uC9C4\uD589\uD574\uC918.
480
+ \uADDC\uCE59 \uD30C\uC77C:
481
+ ${rules || "- (\uC5C6\uC74C)"}
482
+ \uB9AC\uBDF0 \uC591\uC2DD \uD30C\uC77C:
483
+ ${reviewFormLine || "- (\uC5C6\uC74C)"}
484
+ \uB9AC\uBDF0 \uB300\uC0C1 diff \uD30C\uC77C:
485
+ - ${tempDiffPath2}
486
+
487
+ \uBC18\uB4DC\uC2DC \uB9AC\uBDF0 \uC591\uC2DD\uC5D0 \uB9DE\uCDB0 \uC791\uC131\uD574\uC918.`;
488
+ let command = "";
489
+ if (customModel) {
490
+ 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.");
491
+ trace3("model:custom", customModel);
492
+ command = buildCodexExecCommand(prompt, reasoningEffort, customModel);
232
493
  } else {
233
- const modelIndex = args2.indexOf("--model");
234
- if (modelIndex !== -1 && args2[modelIndex + 1]) {
235
- 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.");
236
- modelOption = `--model ${args2[modelIndex + 1]}`;
237
- } else {
238
- 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.");
239
- modelOption = "--model flash";
494
+ const preferredModelAlias = "gpt-5";
495
+ const aliasCommand = buildCodexExecCommand(prompt, reasoningEffort, preferredModelAlias);
496
+ const fallbackCommand = buildCodexExecCommand(prompt, reasoningEffort);
497
+ console.warn(
498
+ `\u26A0\uFE0F \uBAA8\uB378\uC774 \uC9C0\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. alias(${preferredModelAlias})\uB97C \uC6B0\uC120 \uC2DC\uB3C4\uD558\uACE0 \uC2E4\uD328\uD558\uBA74 \uACC4\uC815 \uAE30\uBCF8 \uBAA8\uB378\uB85C \uC790\uB3D9 \uD3F4\uBC31\uD569\uB2C8\uB2E4.`
499
+ );
500
+ trace3("model:alias-first", preferredModelAlias);
501
+ trace3("model:fallback", "account-default");
502
+ command = `${aliasCommand} || ${fallbackCommand}`;
503
+ }
504
+ trace3("command:created");
505
+ if (args2.includes("--test")) {
506
+ const safeCommand = command.replace(/"/g, '\\"');
507
+ trace3("test-mode:return-preview");
508
+ return `echo "[TEST MODE] Codex \uBA85\uB839\uC5B4\uAC00 \uC2E4\uD589\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.
509
+
510
+ \uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
511
+ ${safeCommand}"`;
512
+ }
513
+ trace3("createCodexCommand:end");
514
+ return command;
515
+ };
516
+ var trace4 = createTraceLogger("installation-codex");
517
+ function checkCodexCliInstalled() {
518
+ trace4("checkCodexCliInstalled:start");
519
+ try {
520
+ trace4("version-check:run", "codex --version");
521
+ execSync("codex --version", { stdio: "ignore" });
522
+ trace4("version-check:ok");
523
+ } catch {
524
+ trace4("version-check:failed", "install-start");
525
+ 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");
526
+ try {
527
+ execSync("npm install -g @openai/codex", { stdio: "inherit" });
528
+ trace4("install:ok", "exit(1) for login");
529
+ console.log("\u2705 codex-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
530
+ console.log("\u26A0\uFE0F codex-cli \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
531
+ 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.');
532
+ process.exit(1);
533
+ } catch (installError) {
534
+ trace4("install:failed");
535
+ 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).");
536
+ console.error(installError);
537
+ process.exit(1);
240
538
  }
241
539
  }
540
+ trace4("checkCodexCliInstalled:end");
541
+ }
542
+ var args3 = process.argv.slice(2);
543
+ var trace5 = createTraceLogger("gemini-commander", args3);
544
+ var ALLOWED_REASONING_EFFORTS3 = ["minimal", "low", "medium", "high"];
545
+ function shellQuote3(value) {
546
+ return `'${value.replace(/'/g, `'\\''`)}'`;
547
+ }
548
+ function getArgValue3(flag) {
549
+ const index = args3.indexOf(flag);
550
+ if (index === -1 || !args3[index + 1]) {
551
+ return "";
552
+ }
553
+ return args3[index + 1];
554
+ }
555
+ function toUnique2(values) {
556
+ const seen = /* @__PURE__ */ new Set();
557
+ return values.filter((value) => {
558
+ if (!value || seen.has(value)) {
559
+ return false;
560
+ }
561
+ seen.add(value);
562
+ return true;
563
+ });
564
+ }
565
+ function resolveReasoningEffort3() {
566
+ const customReasoningEffort = getArgValue3("--reasoning-effort");
567
+ if (customReasoningEffort) {
568
+ if (ALLOWED_REASONING_EFFORTS3.includes(customReasoningEffort)) {
569
+ trace5("reasoning:custom", customReasoningEffort);
570
+ return customReasoningEffort;
571
+ }
572
+ console.warn(
573
+ `\u26A0\uFE0F \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 reasoning effort(${customReasoningEffort})\uC785\uB2C8\uB2E4. allowed: ${ALLOWED_REASONING_EFFORTS3.join(
574
+ ", "
575
+ )}`
576
+ );
577
+ }
578
+ if (args3.includes("--flash")) {
579
+ trace5("reasoning:flash-default", "minimal");
580
+ return "minimal";
581
+ }
582
+ if (args3.includes("--review")) {
583
+ trace5("reasoning:review-default", "high");
584
+ return "high";
585
+ }
586
+ trace5("reasoning:default", "medium");
587
+ return "medium";
588
+ }
589
+ function resolvePrimaryAlias2(reasoningEffort) {
590
+ if (args3.includes("--review")) {
591
+ trace5("model:mode-alias", "pro");
592
+ return "pro";
593
+ }
594
+ if (args3.includes("--flash")) {
595
+ trace5("model:mode-alias", "flash");
596
+ return "flash";
597
+ }
598
+ if (reasoningEffort === "high") {
599
+ trace5("model:reasoning-alias", "pro");
600
+ return "pro";
601
+ }
602
+ if (reasoningEffort === "minimal" || reasoningEffort === "low") {
603
+ trace5("model:reasoning-alias", "flash");
604
+ return "flash";
605
+ }
606
+ trace5("model:default-alias", "auto");
607
+ return "auto";
608
+ }
609
+ function getAliasFallbacks2(primaryAlias) {
610
+ if (primaryAlias === "pro") {
611
+ return ["pro", "flash", "auto"];
612
+ }
613
+ if (primaryAlias === "flash") {
614
+ return ["flash", "auto", "pro"];
615
+ }
616
+ return [primaryAlias, "auto", "flash", "pro"];
617
+ }
618
+ function getReasoningInstruction(reasoningEffort) {
619
+ if (reasoningEffort === "high") {
620
+ return "high (\uAE4A\uC774 \uC788\uB294 \uBD84\uC11D, \uC7A0\uC7AC\uC801 \uB9AC\uC2A4\uD06C\uAE4C\uC9C0 \uC810\uAC80)";
621
+ }
622
+ if (reasoningEffort === "medium") {
623
+ return "medium (\uADE0\uD615 \uC7A1\uD78C \uBD84\uC11D\uACFC \uD575\uC2EC \uC774\uC288 \uC911\uC2EC)";
624
+ }
625
+ if (reasoningEffort === "low") {
626
+ return "low (\uD575\uC2EC \uACB0\uD568 \uC704\uC8FC\uB85C \uAC04\uACB0\uD558\uAC8C \uBD84\uC11D)";
627
+ }
628
+ return "minimal (\uCE58\uBA85\uB3C4 \uB192\uC740 \uC774\uC288\uB9CC \uB9E4\uC6B0 \uAC04\uACB0\uD558\uAC8C \uBD84\uC11D)";
629
+ }
630
+ function buildGeminiExecCommand(prompt, model) {
631
+ const modelOption = model ? `--model ${shellQuote3(model)}` : "";
632
+ return `gemini ${[modelOption, "-p", shellQuote3(prompt)].filter(Boolean).join(" ")}`;
633
+ }
634
+ var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
635
+ trace5("createGeminiCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
636
+ const customModel = getArgValue3("--model");
637
+ const reasoningEffort = resolveReasoningEffort3();
638
+ const primaryAlias = resolvePrimaryAlias2(reasoningEffort);
639
+ const aliasFallbacks = toUnique2(getAliasFallbacks2(primaryAlias));
242
640
  const rules = [
243
641
  { path: rulesPath, display: "\uB8F0\uC14B" },
244
642
  { path: namingRulesPath, display: "\uB124\uC774\uBC0D \uADDC\uCE59" },
245
643
  { path: codingConventionRulesPath, display: "\uCF54\uB529 \uCEE8\uBCA4\uC158" }
246
644
  ];
247
645
  const validRules = rules.filter((rule) => fs.existsSync(rule.path)).map((rule) => `@${rule.path}`).join(", ");
248
- 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. "`;
249
- if (args2.includes("--test")) {
646
+ const rulesCount = validRules ? validRules.split(",").length : 0;
647
+ trace5("rules:loaded", `count=${rulesCount}`);
648
+ const reviewFormRef = fs.existsSync(reviewFormPath2) ? `@${reviewFormPath2}` : "(\uC5C6\uC74C)";
649
+ trace5("reviewForm:status", reviewFormRef === "(\uC5C6\uC74C)" ? "missing" : "exists");
650
+ const reasoningInstruction = getReasoningInstruction(reasoningEffort);
651
+ const prompt = `\uB2E4\uC74C \uADDC\uCE59\uB4E4\uC744 \uCC38\uACE0\uD574\uC11C(${validRules || "(\uC5C6\uC74C)"}) \uC774 diff(@${tempDiffPath2})\uB97C \uB9AC\uBDF0\uD574\uC918.
652
+ \uB9AC\uBDF0 \uC591\uC2DD\uC740 ${reviewFormRef} \uC5D0 \uB9DE\uCDB0\uC11C \uC791\uC131\uD574\uC918.
653
+ \uCD94\uB860 \uAC15\uB3C4 \uC9C0\uCE68: ${reasoningInstruction}`;
654
+ const modelCandidates = toUnique2(customModel ? [customModel, ...aliasFallbacks] : aliasFallbacks);
655
+ trace5("model:candidates", modelCandidates.join(", "));
656
+ if (customModel) {
657
+ console.warn(
658
+ `\u26A0\uFE0F \uCEE4\uC2A4\uD140 \uBAA8\uB378(${customModel})\uC744 \uC6B0\uC120 \uC2DC\uB3C4\uD558\uACE0 \uC2E4\uD328\uD558\uBA74 alias(${aliasFallbacks.join(
659
+ " -> "
660
+ )}) \uBC0F \uAE30\uBCF8 \uBAA8\uB378 \uC21C\uC73C\uB85C \uD3F4\uBC31\uD569\uB2C8\uB2E4.`
661
+ );
662
+ } else {
663
+ console.warn(
664
+ `\u26A0\uFE0F \uBAA8\uB378\uC774 \uC9C0\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. alias(${aliasFallbacks.join(" -> ")})\uB97C \uC21C\uCC28 \uC2DC\uB3C4\uD558\uACE0 \uB9C8\uC9C0\uB9C9\uC5D0 \uAE30\uBCF8 \uBAA8\uB378\uB85C \uD3F4\uBC31\uD569\uB2C8\uB2E4.`
665
+ );
666
+ }
667
+ const commandCandidates = modelCandidates.map((model) => buildGeminiExecCommand(prompt, model));
668
+ const command = [...commandCandidates, buildGeminiExecCommand(prompt)].join(" || ");
669
+ trace5("command:created");
670
+ if (args3.includes("--test")) {
250
671
  const safeCommand = command.replace(/"/g, '\\"');
672
+ trace5("test-mode:return-preview");
251
673
  return `echo "[TEST MODE] Gemini \uBA85\uB839\uC5B4\uAC00 \uC2E4\uD589\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.
252
674
 
253
675
  \uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
254
676
  ${safeCommand}"`;
255
677
  }
678
+ trace5("createGeminiCommand:end");
256
679
  return command;
257
680
  };
681
+ var trace6 = createTraceLogger("installation-gemini");
258
682
  function checkGeminiCliInstalled() {
683
+ trace6("checkGeminiCliInstalled:start");
259
684
  try {
685
+ trace6("version-check:run", "gemini --version");
260
686
  execSync("gemini --version", { stdio: "ignore" });
687
+ trace6("version-check:ok");
261
688
  } catch {
689
+ trace6("version-check:failed", "install-start");
262
690
  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");
263
691
  try {
264
692
  execSync("npm install -g @google/gemini-cli", { stdio: "inherit" });
693
+ trace6("install:ok", "exit(1) for login");
265
694
  console.log("\u2705 gemini-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
266
695
  console.log("\u26A0\uFE0F Gemini API \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
267
696
  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.');
268
697
  process.exit(1);
269
698
  } catch (installError) {
699
+ trace6("install:failed");
270
700
  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).");
271
701
  console.error(installError);
272
702
  process.exit(1);
273
703
  }
274
704
  }
705
+ trace6("checkGeminiCliInstalled:end");
275
706
  }
276
707
 
277
708
  // src/pr-review/review.ts
278
709
  async function main() {
279
- const args3 = process.argv.slice(2);
280
- const isTest = args3.includes("--test");
710
+ const args4 = process.argv.slice(2);
711
+ const isTest = isTestMode(args4);
712
+ const trace7 = createTraceLogger("review", args4);
713
+ trace7("main:start", `args=${JSON.stringify(args4)}`);
714
+ trace7("service-selection:start");
281
715
  const service = await showSelectionAIService();
716
+ trace7("service-selection:done", `service=${service}`);
282
717
  switch (service) {
283
718
  case "gemini":
719
+ trace7("install-check:start", "service=gemini");
284
720
  checkGeminiCliInstalled();
721
+ trace7("install-check:done", "service=gemini");
285
722
  break;
286
723
  case "claude":
724
+ trace7("install-check:start", "service=claude");
287
725
  checkClaudeCliInstalled();
726
+ trace7("install-check:done", "service=claude");
727
+ break;
728
+ case "codex":
729
+ trace7("install-check:start", "service=codex");
730
+ checkCodexCliInstalled();
731
+ trace7("install-check:done", "service=codex");
288
732
  break;
289
733
  }
290
734
  try {
735
+ trace7("review-flow:start");
291
736
  console.log("\u{1F680} AI Code Review\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4...");
292
737
  const nowStr = getNowString();
738
+ trace7("timestamp:created", nowStr);
739
+ trace7("report-dir:create:start");
293
740
  createReportDirectory();
741
+ trace7("report-dir:create:done");
742
+ trace7("diff-args:build:start");
294
743
  const diffArgs = getDiffArgs();
744
+ trace7("diff-args:build:done", `diffArgs=${diffArgs || "(default)"}`);
295
745
  let diff = "";
296
746
  const { includeParams, excludeParams } = getGitDiffFilter();
747
+ trace7("diff-filter:loaded", `include=${includeParams} | exclude=${excludeParams}`);
297
748
  try {
749
+ trace7("git-diff:run");
298
750
  diff = execSync(`git diff ${diffArgs} -- ${includeParams} ${excludeParams}`).toString();
751
+ trace7("git-diff:done", `length=${diff.length}`);
299
752
  } catch {
753
+ trace7("git-diff:error", "fallback-empty-diff");
300
754
  }
301
755
  if (!diff.trim() && !isTest) {
756
+ trace7("empty-diff:exit");
302
757
  console.log("\u2139\uFE0F \uB9AC\uBDF0\uD560 \uBCC0\uACBD \uC0AC\uD56D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 (Unstaged Empty & HEAD Empty).");
303
758
  deleteTempDiff();
304
759
  process.exit(0);
305
760
  }
761
+ trace7("temp-diff:write:start", tempDiffPath);
306
762
  fs.writeFileSync(tempDiffPath, diff);
763
+ trace7("temp-diff:write:done");
764
+ trace7("saved-diff:copy:start");
307
765
  const savedDiffPath = getNextFilePath(REPORT_DIR, `${nowStr}-diff`, ".txt");
308
766
  fs.copyFileSync(tempDiffPath, savedDiffPath);
767
+ trace7("saved-diff:copy:done", savedDiffPath);
309
768
  let command = "";
769
+ trace7("command:create:start", `service=${service}`);
310
770
  switch (service) {
311
771
  case "gemini":
312
772
  command = createGeminiCommand(tempDiffPath, reviewFormPath);
@@ -315,29 +775,45 @@ async function main() {
315
775
  command = createClaudeCommand(tempDiffPath, reviewFormPath);
316
776
  break;
317
777
  case "codex":
778
+ command = createCodexCommand(tempDiffPath, reviewFormPath);
318
779
  break;
319
780
  }
781
+ trace7("command:create:done");
782
+ trace7("command:exec:start");
320
783
  const result = execSync(command).toString();
784
+ trace7("command:exec:done", `resultLength=${result.length}`);
321
785
  console.log(result);
786
+ trace7("report:write:start");
322
787
  const savedReportPath = getNextFilePath(REPORT_DIR, nowStr, ".md");
323
788
  fs.writeFileSync(savedReportPath, result);
789
+ trace7("report:write:done", savedReportPath);
324
790
  if (isTest) {
791
+ trace7("test-command:append:start");
325
792
  fs.appendFileSync(savedReportPath, `
326
793
 
327
794
  ## \uC0AC\uC6A9\uB41C \uBA85\uB839\uC5B4
328
795
 
329
796
  ${command}`);
797
+ trace7("test-command:append:done");
330
798
  }
331
799
  console.log(`
332
800
  \u2705 \uB9AC\uBDF0\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`);
333
801
  console.log(`\u{1F4C4} \uB9AC\uD3EC\uD2B8 \uC800\uC7A5 \uC704\uCE58: ${savedReportPath}`);
334
802
  console.log(`diff \uC800\uC7A5 \uC704\uCE58: ${savedDiffPath}`);
803
+ trace7("open-report:start");
335
804
  openReport(savedReportPath);
805
+ trace7("open-report:done");
806
+ trace7("cleanup-temp-diff:start");
336
807
  deleteTempDiff();
808
+ trace7("cleanup-temp-diff:done");
809
+ trace7("review-flow:end");
337
810
  } catch (error) {
811
+ trace7("review-flow:catch");
338
812
  console.error("\u274C \uB9AC\uBDF0 \uB3C4\uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
339
813
  console.error(error);
814
+ trace7("cleanup-temp-diff:start(catch)");
340
815
  deleteTempDiff();
816
+ trace7("cleanup-temp-diff:done(catch)");
341
817
  process.exit(1);
342
818
  }
343
819
  }