sales-frontend-gemini-cli 0.4.0 → 0.4.2

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 (45) hide show
  1. package/dist/common/helper.cjs +234 -20
  2. package/dist/common/helper.cjs.map +1 -1
  3. package/dist/common/helper.d.cts +23 -3
  4. package/dist/common/helper.d.ts +23 -3
  5. package/dist/common/helper.js +228 -21
  6. package/dist/common/helper.js.map +1 -1
  7. package/dist/pr-review/claude/claude-commander.cjs +142 -28
  8. package/dist/pr-review/claude/claude-commander.cjs.map +1 -1
  9. package/dist/pr-review/claude/claude-commander.d.cts +7 -8
  10. package/dist/pr-review/claude/claude-commander.d.ts +7 -8
  11. package/dist/pr-review/claude/claude-commander.js +142 -28
  12. package/dist/pr-review/claude/claude-commander.js.map +1 -1
  13. package/dist/pr-review/claude/installation-claude.cjs +178 -8
  14. package/dist/pr-review/claude/installation-claude.cjs.map +1 -1
  15. package/dist/pr-review/claude/installation-claude.js +177 -8
  16. package/dist/pr-review/claude/installation-claude.js.map +1 -1
  17. package/dist/pr-review/codex/codex-commander.cjs +64 -21
  18. package/dist/pr-review/codex/codex-commander.cjs.map +1 -1
  19. package/dist/pr-review/codex/codex-commander.d.cts +8 -3
  20. package/dist/pr-review/codex/codex-commander.d.ts +8 -3
  21. package/dist/pr-review/codex/codex-commander.js +64 -21
  22. package/dist/pr-review/codex/codex-commander.js.map +1 -1
  23. package/dist/pr-review/codex/installation-codex.cjs +178 -8
  24. package/dist/pr-review/codex/installation-codex.cjs.map +1 -1
  25. package/dist/pr-review/codex/installation-codex.js +177 -8
  26. package/dist/pr-review/codex/installation-codex.js.map +1 -1
  27. package/dist/pr-review/gemini/gemini-commander.cjs +122 -21
  28. package/dist/pr-review/gemini/gemini-commander.cjs.map +1 -1
  29. package/dist/pr-review/gemini/gemini-commander.d.cts +10 -13
  30. package/dist/pr-review/gemini/gemini-commander.d.ts +10 -13
  31. package/dist/pr-review/gemini/gemini-commander.js +122 -21
  32. package/dist/pr-review/gemini/gemini-commander.js.map +1 -1
  33. package/dist/pr-review/gemini/installation-gemini.cjs +178 -8
  34. package/dist/pr-review/gemini/installation-gemini.cjs.map +1 -1
  35. package/dist/pr-review/gemini/installation-gemini.js +177 -8
  36. package/dist/pr-review/gemini/installation-gemini.js.map +1 -1
  37. package/dist/pr-review/review-one-by-one.cjs +679 -157
  38. package/dist/pr-review/review-one-by-one.cjs.map +1 -1
  39. package/dist/pr-review/review-one-by-one.js +679 -157
  40. package/dist/pr-review/review-one-by-one.js.map +1 -1
  41. package/dist/pr-review/review.cjs +630 -132
  42. package/dist/pr-review/review.cjs.map +1 -1
  43. package/dist/pr-review/review.js +630 -132
  44. package/dist/pr-review/review.js.map +1 -1
  45. package/package.json +1 -1
@@ -6,6 +6,7 @@ var fs = require('fs');
6
6
  var path = require('path');
7
7
  var readline = require('readline');
8
8
  var url = require('url');
9
+ var util = require('util');
9
10
 
10
11
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
11
12
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -15,6 +16,7 @@ var path__default = /*#__PURE__*/_interopDefault(path);
15
16
  var readline__default = /*#__PURE__*/_interopDefault(readline);
16
17
 
17
18
  var __dirname$1 = path__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('review.cjs', document.baseURI).href))));
19
+ var traceMessages = [];
18
20
  var rulesPath = path__default.default.resolve(__dirname$1, "../../src/common/rules/review-rules.md");
19
21
  var namingRulesPath = path__default.default.resolve(__dirname$1, "../../src/common/rules/naming-rule.md");
20
22
  var codingConventionRulesPath = path__default.default.resolve(__dirname$1, "../../src/common/rules/coding-convention.md");
@@ -40,15 +42,94 @@ var ignoreList = [
40
42
  function isTestMode(args4 = process.argv.slice(2)) {
41
43
  return args4.includes("--test");
42
44
  }
45
+ function clearTraceMessages() {
46
+ traceMessages.length = 0;
47
+ }
48
+ function getTraceMessages() {
49
+ return [...traceMessages];
50
+ }
43
51
  function createTraceLogger(scope, args4 = process.argv.slice(2)) {
44
52
  const enabled = isTestMode(args4);
45
53
  return (step, detail) => {
54
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
55
+ const message = `[${timestamp}][TRACE][${scope}] ${step}${detail ? ` | ${detail}` : ""}`;
56
+ traceMessages.push(message);
46
57
  if (!enabled) {
47
58
  return;
48
59
  }
49
- console.log(`[TRACE][${scope}] ${step}${detail ? ` | ${detail}` : ""}`);
60
+ console.log(message);
61
+ };
62
+ }
63
+ var helperTrace = createTraceLogger("helper");
64
+ function getTimestampParts(now = /* @__PURE__ */ new Date()) {
65
+ return {
66
+ YYYY: now.getFullYear(),
67
+ MM: String(now.getMonth() + 1).padStart(2, "0"),
68
+ DD: String(now.getDate()).padStart(2, "0"),
69
+ HH: String(now.getHours()).padStart(2, "0"),
70
+ mm: String(now.getMinutes()).padStart(2, "0"),
71
+ ss: String(now.getSeconds()).padStart(2, "0")
50
72
  };
51
73
  }
74
+ function getHumanReadableNowString(now = /* @__PURE__ */ new Date()) {
75
+ const { YYYY, MM, DD, HH, mm, ss } = getTimestampParts(now);
76
+ return `${YYYY}-${MM}-${DD} ${HH}:${mm}:${ss}`;
77
+ }
78
+ function stringifyUnknown(value) {
79
+ if (value === void 0 || value === null) {
80
+ return "";
81
+ }
82
+ if (typeof value === "string") {
83
+ return value;
84
+ }
85
+ if (Buffer.isBuffer(value)) {
86
+ return value.toString();
87
+ }
88
+ if (value instanceof Error) {
89
+ return value.stack || value.message;
90
+ }
91
+ return util.inspect(value, { depth: 5, breakLength: 120 });
92
+ }
93
+ function getErrorSummary(error) {
94
+ if (error instanceof Error) {
95
+ return `${error.name}: ${error.message}`;
96
+ }
97
+ return stringifyUnknown(error) || "Unknown error";
98
+ }
99
+ function serializeError(error) {
100
+ const serialized = {
101
+ summary: getErrorSummary(error)
102
+ };
103
+ if (error instanceof Error) {
104
+ serialized.name = error.name;
105
+ serialized.message = error.message;
106
+ serialized.stack = error.stack;
107
+ } else {
108
+ serialized.value = stringifyUnknown(error);
109
+ }
110
+ if (error && typeof error === "object") {
111
+ const errorLike = error;
112
+ const extraKeys = ["code", "errno", "syscall", "path", "cmd", "status", "signal", "spawnargs"];
113
+ extraKeys.forEach((key) => {
114
+ if (errorLike[key] !== void 0) {
115
+ serialized[key] = errorLike[key];
116
+ }
117
+ });
118
+ const stdout = stringifyUnknown(errorLike.stdout);
119
+ if (stdout) {
120
+ serialized.stdout = stdout;
121
+ }
122
+ const stderr = stringifyUnknown(errorLike.stderr);
123
+ if (stderr) {
124
+ serialized.stderr = stderr;
125
+ }
126
+ const cause = stringifyUnknown(errorLike.cause);
127
+ if (cause) {
128
+ serialized.cause = cause;
129
+ }
130
+ }
131
+ return serialized;
132
+ }
52
133
  function getNextFilePath(dir, baseName, extension) {
53
134
  let counter = 1;
54
135
  while (true) {
@@ -59,6 +140,13 @@ function getNextFilePath(dir, baseName, extension) {
59
140
  counter++;
60
141
  }
61
142
  }
143
+ function getAvailableFilePath(dir, baseName, extension) {
144
+ const firstFilePath = path__default.default.join(dir, `${baseName}${extension}`);
145
+ if (!fs__default.default.existsSync(firstFilePath)) {
146
+ return firstFilePath;
147
+ }
148
+ return getNextFilePath(dir, baseName, extension);
149
+ }
62
150
  function deleteFile(filePath) {
63
151
  if (fs__default.default.existsSync(filePath)) {
64
152
  fs__default.default.unlinkSync(filePath);
@@ -72,16 +160,105 @@ function createReportDirectory() {
72
160
  fs__default.default.mkdirSync(REPORT_DIR, { recursive: true });
73
161
  }
74
162
  }
75
- function getNowString() {
76
- const now = /* @__PURE__ */ new Date();
77
- const YYYY = now.getFullYear();
78
- const MM = String(now.getMonth() + 1).padStart(2, "0");
79
- const DD = String(now.getDate()).padStart(2, "0");
80
- const HH = String(now.getHours()).padStart(2, "0");
81
- const mm = String(now.getMinutes()).padStart(2, "0");
82
- const ss = String(now.getSeconds()).padStart(2, "0");
163
+ function getNowString(now = /* @__PURE__ */ new Date()) {
164
+ const { YYYY, MM, DD, HH, mm, ss } = getTimestampParts(now);
83
165
  return `${YYYY}-${MM}-${DD}_${HH}-${mm}-${ss}`;
84
166
  }
167
+ function getErrorLogTimestamp(now = /* @__PURE__ */ new Date()) {
168
+ const { YYYY, MM, DD, HH, mm, ss } = getTimestampParts(now);
169
+ return `${YYYY}-${MM}-${DD}-${HH}\uC2DC-${mm}\uBD84-${ss}\uCD08`;
170
+ }
171
+ function writeErrorReport(error, options = {}) {
172
+ try {
173
+ const now = /* @__PURE__ */ new Date();
174
+ helperTrace("error-report:write:start", options.scope || "unknown");
175
+ createReportDirectory();
176
+ const reportPath = getAvailableFilePath(REPORT_DIR, `error-log-${getErrorLogTimestamp(now)}`, ".md");
177
+ const serializedError = serializeError(error);
178
+ const traceSnapshot = options.traceMessages ?? getTraceMessages();
179
+ const extraSections = options.extraSections || [];
180
+ const report = `# Error Log
181
+
182
+ - \uBC1C\uC0DD \uC2DC\uAC01: ${getHumanReadableNowString(now)}
183
+ - Scope: \`${options.scope || "unknown"}\`
184
+ - \uC791\uC5C5 \uACBD\uB85C: \`${process.cwd()}\`
185
+ - \uC2E4\uD589 \uC778\uC790: \`${JSON.stringify(options.args ?? process.argv.slice(2))}\`
186
+ - \uC2E4\uD589 \uD658\uACBD: \`${process.platform} ${process.arch} / Node ${process.version}\`
187
+
188
+ ## Summary
189
+
190
+ ${options.title || serializedError.summary || "Unknown error"}
191
+
192
+ ## Error
193
+
194
+ \`\`\`json
195
+ ${JSON.stringify(serializedError, null, 2)}
196
+ \`\`\`
197
+
198
+ ## Trace
199
+
200
+ \`\`\`json
201
+ ${JSON.stringify(traceSnapshot, null, 2)}
202
+ \`\`\`${extraSections.length ? `
203
+ ${extraSections.map((section) => `
204
+ ## ${section.heading}
205
+
206
+ ${section.markdown}`).join("\n")}
207
+ ` : "\n"}
208
+ `;
209
+ fs__default.default.writeFileSync(reportPath, report);
210
+ helperTrace("error-report:write:done", reportPath);
211
+ return reportPath;
212
+ } catch (writeError) {
213
+ console.error("\u26A0\uFE0F \uC5D0\uB7EC \uB85C\uADF8 \uD30C\uC77C \uC0DD\uC131\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
214
+ console.error(writeError);
215
+ return "";
216
+ }
217
+ }
218
+ function exitWithError(message, options = {}) {
219
+ const reportPath = writeErrorReport(options.error || new Error(message), {
220
+ ...options,
221
+ title: message
222
+ });
223
+ console.error(message);
224
+ if (options.error) {
225
+ console.error(options.error);
226
+ }
227
+ if (reportPath) {
228
+ console.error(`\u{1F4C4} \uC5D0\uB7EC \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${reportPath}`);
229
+ }
230
+ process.exit(1);
231
+ }
232
+ function parseServiceFromArgs(args4 = process.argv.slice(2)) {
233
+ helperTrace("parse-service:start", `args=${JSON.stringify(args4)}`);
234
+ const serviceIndex = args4.indexOf("--service");
235
+ const rawService = serviceIndex !== -1 ? args4[serviceIndex + 1] : "";
236
+ if (!rawService) {
237
+ helperTrace("parse-service:empty");
238
+ return "";
239
+ }
240
+ const normalizedService = rawService.toLowerCase();
241
+ if (AIServices.includes(normalizedService)) {
242
+ helperTrace("parse-service:resolved", normalizedService);
243
+ return normalizedService;
244
+ }
245
+ helperTrace("parse-service:invalid", rawService);
246
+ exitWithError(
247
+ `\u274C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uC11C\uBE44\uC2A4\uC785\uB2C8\uB2E4: ${rawService}. \uC0AC\uC6A9 \uAC00\uB2A5 \uAC12: ${AIServices.join(", ")} (\uC608: --service codex)`,
248
+ {
249
+ scope: "helper:parseServiceFromArgs",
250
+ args: args4,
251
+ extraSections: [
252
+ {
253
+ heading: "Allowed Services",
254
+ markdown: `\`\`\`json
255
+ ${JSON.stringify(AIServices, null, 2)}
256
+ \`\`\``
257
+ }
258
+ ]
259
+ }
260
+ );
261
+ }
85
262
  function getGitDiffFilter() {
86
263
  const includeExtensions = ["*.ts", "*.tsx", "*.js", "*.jsx"];
87
264
  const excludePatterns = ignoreList.map((item) => `:(exclude)${item}`);
@@ -93,6 +270,7 @@ function getGitDiffFilter() {
93
270
  function openReport(reportPath) {
94
271
  const resolvedPath = path__default.default.resolve(reportPath);
95
272
  const { platform } = process;
273
+ helperTrace("open-report:start", resolvedPath);
96
274
  const openWithChrome = () => {
97
275
  if (platform === "darwin") {
98
276
  child_process.execSync(`open -a "Google Chrome" "${resolvedPath}"`, { stdio: "ignore" });
@@ -117,32 +295,41 @@ function openReport(reportPath) {
117
295
  };
118
296
  try {
119
297
  if (openWithChrome()) {
298
+ helperTrace("open-report:chrome:success", platform);
120
299
  console.log("\u{1F680} Google Chrome\uC5D0\uC11C \uB9AC\uD3EC\uD2B8\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4.");
121
300
  return;
122
301
  }
123
- } catch {
302
+ } catch (error) {
303
+ helperTrace("open-report:chrome:failed", getErrorSummary(error));
124
304
  }
125
305
  try {
126
306
  if (openWithDefaultBrowser()) {
307
+ helperTrace("open-report:default-browser:success", platform);
127
308
  console.log("\u{1F680} \uAE30\uBCF8 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB9AC\uD3EC\uD2B8\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4.");
128
309
  return;
129
310
  }
130
- } catch (e) {
131
- console.error("\u26A0\uFE0F \uBE0C\uB77C\uC6B0\uC800 \uC5F4\uAE30 \uC2E4\uD328:", e);
311
+ } catch (error) {
312
+ helperTrace("open-report:default-browser:failed", getErrorSummary(error));
313
+ console.error("\u26A0\uFE0F \uBE0C\uB77C\uC6B0\uC800 \uC5F4\uAE30 \uC2E4\uD328:", error);
132
314
  return;
133
315
  }
316
+ helperTrace("open-report:unsupported-platform", platform);
134
317
  console.error(`\u26A0\uFE0F \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD50C\uB7AB\uD3FC\uC785\uB2C8\uB2E4: ${platform}`);
135
318
  }
136
319
  function getDiffArgs() {
137
320
  const args4 = process.argv.slice(2);
138
321
  const commitIndex = args4.indexOf("--commit");
139
322
  const { includeParams, excludeParams } = getGitDiffFilter();
323
+ helperTrace("diff-args:resolve:start", `args=${JSON.stringify(args4)}`);
140
324
  let diffArgs = "";
141
325
  if (commitIndex !== -1) {
142
326
  const commitHash = args4[commitIndex + 1];
143
327
  if (!commitHash) {
144
- console.error("\u274C \uCEE4\uBC0B \uD574\uC2DC\uAC00 \uC81C\uACF5\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.");
145
- process.exit(1);
328
+ helperTrace("diff-args:commit-hash-missing");
329
+ exitWithError("\u274C \uCEE4\uBC0B \uD574\uC2DC\uAC00 \uC81C\uACF5\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.", {
330
+ scope: "helper:getDiffArgs",
331
+ args: args4
332
+ });
146
333
  }
147
334
  const nextArg = args4[commitIndex + 2];
148
335
  let n = 0;
@@ -152,21 +339,37 @@ function getDiffArgs() {
152
339
  n = 0;
153
340
  }
154
341
  }
342
+ helperTrace("diff-args:commit-mode", `${commitHash}~${n + 1} ${commitHash}`);
155
343
  console.log(`\u2139\uFE0F \uCEE4\uBC0B '${commitHash}' ${n > 0 ? ` \uD3EC\uD568 \uCD1D ${n + 1}\uAC1C\uC758 \uCEE4\uBC0B` : ""}\uC744 \uB9AC\uBDF0\uD569\uB2C8\uB2E4...`);
156
344
  diffArgs = `${commitHash}~${n + 1} ${commitHash}`;
157
345
  } else {
158
346
  try {
347
+ helperTrace("diff-args:unstaged-check:start");
159
348
  const check = child_process.execSync(`git diff --name-only -- ${includeParams} ${excludeParams}`).toString();
160
349
  if (!check.trim()) {
350
+ helperTrace("diff-args:unstaged-check:empty", "use HEAD~1 HEAD");
161
351
  console.log("\u2139\uFE0F Unstaged \uBCC0\uACBD\uC0AC\uD56D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uB9C8\uC9C0\uB9C9 \uCEE4\uBC0B(HEAD)\uC744 \uB9AC\uBDF0\uD569\uB2C8\uB2E4...");
162
352
  diffArgs = "HEAD~1 HEAD";
353
+ } else {
354
+ helperTrace("diff-args:unstaged-check:has-changes", `length=${check.length}`);
163
355
  }
164
- } catch {
356
+ } catch (error) {
357
+ helperTrace("diff-args:unstaged-check:failed", getErrorSummary(error));
165
358
  }
166
359
  }
360
+ helperTrace("diff-args:resolve:done", diffArgs || "(default)");
167
361
  return diffArgs;
168
362
  }
169
363
  async function showSelectionAIService() {
364
+ const selectedServiceFromArgs = parseServiceFromArgs();
365
+ if (selectedServiceFromArgs) {
366
+ helperTrace("show-selection:from-args", selectedServiceFromArgs);
367
+ console.log(`
368
+ \u2705 \x1B[32m${selectedServiceFromArgs}\x1B[0m \uC11C\uBE44\uC2A4\uAC00 \uC120\uD0DD\uB418\uC5C8\uC2B5\uB2C8\uB2E4. (--service)
369
+ `);
370
+ return selectedServiceFromArgs;
371
+ }
372
+ helperTrace("show-selection:interactive:start");
170
373
  let selectedIndex = 0;
171
374
  const rl = readline__default.default.createInterface({
172
375
  input: process.stdin,
@@ -180,6 +383,7 @@ async function showSelectionAIService() {
180
383
  readline__default.default.moveCursor(process.stdout, 0, -(AIServices.length + 1));
181
384
  }
182
385
  firstRender = false;
386
+ helperTrace("show-selection:interactive:render", AIServices[selectedIndex] || "unknown");
183
387
  readline__default.default.clearScreenDown(process.stdout);
184
388
  process.stdout.write(
185
389
  "\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,6 +403,7 @@ async function showSelectionAIService() {
199
403
  const onData = (data) => {
200
404
  const key = data.toString();
201
405
  if (key === "") {
406
+ helperTrace("show-selection:interactive:ctrl-c");
202
407
  process.stdout.write("\x1B[?25h");
203
408
  process.exit(0);
204
409
  }
@@ -219,6 +424,7 @@ async function showSelectionAIService() {
219
424
  `);
220
425
  const result = AIServices[selectedIndex];
221
426
  if (result) {
427
+ helperTrace("show-selection:interactive:confirmed", result);
222
428
  resolve(result);
223
429
  }
224
430
  }
@@ -230,40 +436,150 @@ async function showSelectionAIService() {
230
436
  }
231
437
  var args = process.argv.slice(2);
232
438
  var trace = createTraceLogger("claude-commander", args);
233
- var createClaudeCommand = (tempDiffPath2, reviewFormPath2) => {
234
- trace("createClaudeCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
235
- let modelOption = "";
236
- if (args.includes("--review")) {
237
- modelOption = "--model opus";
238
- trace("model:review", modelOption);
239
- } else if (args.includes("--flash")) {
240
- modelOption = "--model haiku";
241
- trace("model:flash", modelOption);
242
- } else {
243
- const modelIndex = args.indexOf("--model");
244
- if (modelIndex !== -1 && args[modelIndex + 1]) {
245
- 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.");
246
- modelOption = `--model ${args[modelIndex + 1]}`;
247
- trace("model:custom", modelOption);
248
- } else {
249
- 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.");
250
- modelOption = "--model sonnet";
251
- trace("model:default", modelOption);
439
+ var ALLOWED_REASONING_EFFORTS = ["minimal", "low", "medium", "high"];
440
+ function shellQuote(value) {
441
+ return `'${value.replace(/'/g, `'\\''`)}'`;
442
+ }
443
+ function getArgValue(flag) {
444
+ const index = args.indexOf(flag);
445
+ if (index === -1 || !args[index + 1]) {
446
+ return "";
447
+ }
448
+ return args[index + 1];
449
+ }
450
+ function toUnique(values) {
451
+ const seen = /* @__PURE__ */ new Set();
452
+ return values.filter((value) => {
453
+ if (!value || seen.has(value)) {
454
+ return false;
252
455
  }
456
+ seen.add(value);
457
+ return true;
458
+ });
459
+ }
460
+ function normalizeEffort(level) {
461
+ if (level === "minimal") {
462
+ return "low";
253
463
  }
464
+ return level;
465
+ }
466
+ function resolveReasoningEffort() {
467
+ const customReasoningEffort = getArgValue("--reasoning-effort") || getArgValue("--effort");
468
+ if (customReasoningEffort) {
469
+ if (ALLOWED_REASONING_EFFORTS.includes(customReasoningEffort)) {
470
+ const normalized = normalizeEffort(customReasoningEffort);
471
+ trace("reasoning:custom", `${customReasoningEffort} -> ${normalized}`);
472
+ if (customReasoningEffort === "minimal") {
473
+ console.warn("\u26A0\uFE0F Claude\uB294 minimal\uC744 \uC9C1\uC811 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC544 low\uB85C \uB9E4\uD551\uD569\uB2C8\uB2E4.");
474
+ }
475
+ return normalized;
476
+ }
477
+ console.warn(
478
+ `\u26A0\uFE0F \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 reasoning effort(${customReasoningEffort})\uC785\uB2C8\uB2E4. allowed: ${ALLOWED_REASONING_EFFORTS.join(
479
+ ", "
480
+ )}`
481
+ );
482
+ }
483
+ if (args.includes("--flash")) {
484
+ trace("reasoning:flash-default", "low");
485
+ return "low";
486
+ }
487
+ if (args.includes("--review")) {
488
+ trace("reasoning:review-default", "high");
489
+ return "high";
490
+ }
491
+ trace("reasoning:default", "medium");
492
+ return "medium";
493
+ }
494
+ function resolvePrimaryAlias() {
495
+ if (args.includes("--review")) {
496
+ trace("model:mode-alias", "opus");
497
+ return "opus";
498
+ }
499
+ if (args.includes("--flash")) {
500
+ trace("model:mode-alias", "haiku");
501
+ return "haiku";
502
+ }
503
+ trace("model:default-alias", "sonnet");
504
+ return "sonnet";
505
+ }
506
+ function getAliasFallbacks(primaryAlias) {
507
+ if (primaryAlias === "opus") {
508
+ return ["opus", "sonnet", "haiku"];
509
+ }
510
+ if (primaryAlias === "haiku") {
511
+ return ["haiku", "sonnet"];
512
+ }
513
+ return [primaryAlias, "sonnet", "haiku"];
514
+ }
515
+ function buildClaudeExecCommand(options) {
516
+ const { tempDiffPath: tempDiffPath2, prompt, systemPromptFiles, effort, model, fallbackModel } = options;
517
+ const modelOption = model ? `--model ${shellQuote(model)}` : "";
518
+ const fallbackOption = model && fallbackModel ? `--fallback-model ${shellQuote(fallbackModel)}` : "";
519
+ const effortOption = `--effort ${shellQuote(effort)}`;
520
+ const appendedPromptFiles = systemPromptFiles.map((path2) => `--append-system-prompt-file ${shellQuote(path2)}`).join(" ");
521
+ return `cat ${shellQuote(tempDiffPath2)} | claude ${[
522
+ modelOption,
523
+ fallbackOption,
524
+ effortOption,
525
+ appendedPromptFiles,
526
+ "-p",
527
+ shellQuote(prompt)
528
+ ].filter(Boolean).join(" ")}`;
529
+ }
530
+ var createClaudeCommand = (tempDiffPath2, reviewFormPath2) => {
531
+ trace("createClaudeCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
532
+ const customModel = getArgValue("--model");
533
+ const effort = resolveReasoningEffort();
534
+ const primaryAlias = resolvePrimaryAlias();
535
+ const aliasFallbacks = toUnique(getAliasFallbacks(primaryAlias));
254
536
  const rules = [
255
537
  { path: rulesPath, display: "\uB8F0\uC14B" },
256
538
  { path: namingRulesPath, display: "\uB124\uC774\uBC0D \uADDC\uCE59" },
257
539
  { path: codingConventionRulesPath, display: "\uCF54\uB529 \uCEE8\uBCA4\uC158" }
258
540
  ];
259
- const systemPromptFiles = rules.filter((rule) => fs__default.default.existsSync(rule.path)).map((rule) => `--append-system-prompt-file ${rule.path}`).join(" ");
260
- trace(
261
- "rules:loaded",
262
- `count=${systemPromptFiles ? systemPromptFiles.split("--append-system-prompt-file").length - 1 : 0}`
263
- );
264
- const reviewFormOption = fs__default.default.existsSync(reviewFormPath2) ? `--append-system-prompt-file ${reviewFormPath2}` : "";
265
- trace("reviewForm:status", reviewFormOption ? "exists" : "missing");
266
- 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."`;
541
+ const existingRuleFiles = rules.filter((rule) => fs__default.default.existsSync(rule.path)).map((rule) => rule.path);
542
+ trace("rules:loaded", `count=${existingRuleFiles.length}`);
543
+ const reviewFormExists = fs__default.default.existsSync(reviewFormPath2);
544
+ trace("reviewForm:status", reviewFormExists ? "exists" : "missing");
545
+ const systemPromptFiles = reviewFormExists ? [...existingRuleFiles, reviewFormPath2] : existingRuleFiles;
546
+ 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.";
547
+ trace("prompt:prepared", `length=${prompt.length}`);
548
+ trace("system-prompt-files", `count=${systemPromptFiles.length}`);
549
+ const modelCandidates = toUnique(customModel ? [customModel, ...aliasFallbacks] : aliasFallbacks);
550
+ trace("model:candidates", modelCandidates.join(", "));
551
+ trace("command:candidates:count", String(modelCandidates.length + 1));
552
+ if (customModel) {
553
+ console.warn(
554
+ `\u26A0\uFE0F \uCEE4\uC2A4\uD140 \uBAA8\uB378(${customModel})\uC744 \uC6B0\uC120 \uC2DC\uB3C4\uD558\uACE0 \uC2E4\uD328\uD558\uBA74 alias(${aliasFallbacks.join(
555
+ " -> "
556
+ )}) \uBC0F \uAE30\uBCF8 \uBAA8\uB378 \uC21C\uC73C\uB85C \uD3F4\uBC31\uD569\uB2C8\uB2E4.`
557
+ );
558
+ } else {
559
+ console.warn(
560
+ `\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.`
561
+ );
562
+ }
563
+ const commandCandidates = modelCandidates.map((model, index) => {
564
+ const fallbackModel = modelCandidates[index + 1];
565
+ return buildClaudeExecCommand({
566
+ tempDiffPath: tempDiffPath2,
567
+ prompt,
568
+ systemPromptFiles,
569
+ effort,
570
+ model,
571
+ fallbackModel
572
+ });
573
+ });
574
+ const command = [
575
+ ...commandCandidates,
576
+ buildClaudeExecCommand({
577
+ tempDiffPath: tempDiffPath2,
578
+ prompt,
579
+ systemPromptFiles,
580
+ effort
581
+ })
582
+ ].join(" || ");
267
583
  trace("command:created");
268
584
  if (args.includes("--test")) {
269
585
  const safeCommand = command.replace(/"/g, '\\"');
@@ -273,6 +589,7 @@ var createClaudeCommand = (tempDiffPath2, reviewFormPath2) => {
273
589
  \uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
274
590
  ${safeCommand}"`;
275
591
  }
592
+ trace("command:mode", "execute");
276
593
  trace("createClaudeCommand:end");
277
594
  return command;
278
595
  };
@@ -283,50 +600,75 @@ function checkClaudeCliInstalled() {
283
600
  trace2("version-check:run", "claude --version");
284
601
  child_process.execSync("claude --version", { stdio: "ignore" });
285
602
  trace2("version-check:ok");
286
- } catch {
287
- trace2("version-check:failed", "install-start");
603
+ } catch (error) {
604
+ trace2("version-check:failed", getErrorSummary(error));
605
+ trace2("install:start", "@anthropic-ai/claude-code");
288
606
  console.log(
289
607
  "\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"
290
608
  );
291
609
  try {
292
610
  child_process.execSync("npm install -g @anthropic-ai/claude-code", { stdio: "inherit" });
293
- trace2("install:ok", "exit(1) for login");
611
+ trace2("install:ok", "login-required");
294
612
  console.log("\u2705 claude-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
295
613
  console.log("\u26A0\uFE0F claude-cli \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
296
614
  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.');
297
615
  process.exit(1);
298
616
  } catch (installError) {
299
- trace2("install:failed");
300
- 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).");
301
- console.error(installError);
302
- process.exit(1);
617
+ trace2("install:failed", getErrorSummary(installError));
618
+ exitWithError("\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).", {
619
+ scope: "installation-claude",
620
+ error: installError
621
+ });
303
622
  }
304
623
  }
305
624
  trace2("checkClaudeCliInstalled:end");
306
625
  }
307
626
  var args2 = process.argv.slice(2);
308
627
  var trace3 = createTraceLogger("codex-commander", args2);
309
- var createCodexCommand = (tempDiffPath2, reviewFormPath2) => {
310
- trace3("createCodexCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
311
- let modelOption = "";
312
- if (args2.includes("--review")) {
313
- modelOption = "--model gpt-5";
314
- trace3("model:review", modelOption);
315
- } else if (args2.includes("--flash")) {
316
- modelOption = "--model gpt-5-mini";
317
- trace3("model:flash", modelOption);
318
- } else {
319
- const modelIndex = args2.indexOf("--model");
320
- if (modelIndex !== -1 && args2[modelIndex + 1]) {
321
- 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.");
322
- modelOption = `--model ${args2[modelIndex + 1]}`;
323
- trace3("model:custom", modelOption);
324
- } else {
325
- 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.");
326
- modelOption = "--model gpt-5-mini";
327
- trace3("model:default", modelOption);
628
+ var ALLOWED_REASONING_EFFORTS2 = ["minimal", "low", "medium", "high"];
629
+ function shellQuote2(value) {
630
+ return `'${value.replace(/'/g, `'\\''`)}'`;
631
+ }
632
+ function getArgValue2(flag) {
633
+ const index = args2.indexOf(flag);
634
+ if (index === -1 || !args2[index + 1]) {
635
+ return "";
636
+ }
637
+ return args2[index + 1];
638
+ }
639
+ function resolveReasoningEffort2() {
640
+ const customReasoningEffort = getArgValue2("--reasoning-effort");
641
+ if (customReasoningEffort) {
642
+ if (ALLOWED_REASONING_EFFORTS2.includes(customReasoningEffort)) {
643
+ trace3("reasoning:custom", customReasoningEffort);
644
+ return customReasoningEffort;
328
645
  }
646
+ console.warn(
647
+ `\u26A0\uFE0F \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 reasoning effort(${customReasoningEffort})\uC785\uB2C8\uB2E4. allowed: ${ALLOWED_REASONING_EFFORTS2.join(
648
+ ", "
649
+ )}`
650
+ );
329
651
  }
652
+ if (args2.includes("--flash")) {
653
+ trace3("reasoning:flash-default", "minimal");
654
+ return "minimal";
655
+ }
656
+ if (args2.includes("--review")) {
657
+ trace3("reasoning:review-default", "high");
658
+ return "high";
659
+ }
660
+ trace3("reasoning:default", "medium");
661
+ return "medium";
662
+ }
663
+ function buildCodexExecCommand(prompt, reasoningEffort, model) {
664
+ const modelOption = model ? `--model ${shellQuote2(model)}` : "";
665
+ const reasoningOption = `-c ${shellQuote2(`model_reasoning_effort="${reasoningEffort}"`)}`;
666
+ return `codex exec ${[modelOption, reasoningOption, shellQuote2(prompt)].filter(Boolean).join(" ")}`;
667
+ }
668
+ var createCodexCommand = (tempDiffPath2, reviewFormPath2) => {
669
+ trace3("createCodexCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
670
+ const customModel = getArgValue2("--model");
671
+ const reasoningEffort = resolveReasoningEffort2();
330
672
  const rules = [rulesPath, namingRulesPath, codingConventionRulesPath].filter((filePath) => fs__default.default.existsSync(filePath)).map((filePath) => `- ${filePath}`).join("\n");
331
673
  const rulesCount = rules ? rules.split("\n").length : 0;
332
674
  trace3("rules:loaded", `count=${rulesCount}`);
@@ -342,7 +684,23 @@ ${reviewFormLine || "- (\uC5C6\uC74C)"}
342
684
  - ${tempDiffPath2}
343
685
 
344
686
  \uBC18\uB4DC\uC2DC \uB9AC\uBDF0 \uC591\uC2DD\uC5D0 \uB9DE\uCDB0 \uC791\uC131\uD574\uC918.`;
345
- const command = `codex exec ${modelOption} "${prompt.replace(/"/g, '\\"')}"`;
687
+ trace3("prompt:prepared", `length=${prompt.length}`);
688
+ let command = "";
689
+ if (customModel) {
690
+ 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.");
691
+ trace3("model:custom", customModel);
692
+ command = buildCodexExecCommand(prompt, reasoningEffort, customModel);
693
+ } else {
694
+ const preferredModelAlias = "gpt-5";
695
+ const aliasCommand = buildCodexExecCommand(prompt, reasoningEffort, preferredModelAlias);
696
+ const fallbackCommand = buildCodexExecCommand(prompt, reasoningEffort);
697
+ console.warn(
698
+ `\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.`
699
+ );
700
+ trace3("model:alias-first", preferredModelAlias);
701
+ trace3("model:fallback", "account-default");
702
+ command = `${aliasCommand} || ${fallbackCommand}`;
703
+ }
346
704
  trace3("command:created");
347
705
  if (args2.includes("--test")) {
348
706
  const safeCommand = command.replace(/"/g, '\\"');
@@ -352,6 +710,7 @@ ${reviewFormLine || "- (\uC5C6\uC74C)"}
352
710
  \uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
353
711
  ${safeCommand}"`;
354
712
  }
713
+ trace3("command:mode", "execute");
355
714
  trace3("createCodexCommand:end");
356
715
  return command;
357
716
  };
@@ -362,48 +721,125 @@ function checkCodexCliInstalled() {
362
721
  trace4("version-check:run", "codex --version");
363
722
  child_process.execSync("codex --version", { stdio: "ignore" });
364
723
  trace4("version-check:ok");
365
- } catch {
366
- trace4("version-check:failed", "install-start");
724
+ } catch (error) {
725
+ trace4("version-check:failed", getErrorSummary(error));
726
+ trace4("install:start", "@openai/codex");
367
727
  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");
368
728
  try {
369
729
  child_process.execSync("npm install -g @openai/codex", { stdio: "inherit" });
370
- trace4("install:ok", "exit(1) for login");
730
+ trace4("install:ok", "login-required");
371
731
  console.log("\u2705 codex-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
372
732
  console.log("\u26A0\uFE0F codex-cli \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
373
733
  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.');
374
734
  process.exit(1);
375
735
  } catch (installError) {
376
- trace4("install:failed");
377
- 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).");
378
- console.error(installError);
379
- process.exit(1);
736
+ trace4("install:failed", getErrorSummary(installError));
737
+ exitWithError("\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).", {
738
+ scope: "installation-codex",
739
+ error: installError
740
+ });
380
741
  }
381
742
  }
382
743
  trace4("checkCodexCliInstalled:end");
383
744
  }
384
745
  var args3 = process.argv.slice(2);
385
746
  var trace5 = createTraceLogger("gemini-commander", args3);
386
- var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
387
- trace5("createGeminiCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
388
- let modelOption = "";
389
- if (args3.includes("--review")) {
390
- modelOption = "--model pro";
391
- trace5("model:review", modelOption);
392
- } else if (args3.includes("--flash")) {
393
- modelOption = "--model flash";
394
- trace5("model:flash", modelOption);
395
- } else {
396
- const modelIndex = args3.indexOf("--model");
397
- if (modelIndex !== -1 && args3[modelIndex + 1]) {
398
- 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.");
399
- modelOption = `--model ${args3[modelIndex + 1]}`;
400
- trace5("model:custom", modelOption);
401
- } else {
402
- 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.");
403
- modelOption = "--model flash";
404
- trace5("model:default", modelOption);
747
+ var ALLOWED_REASONING_EFFORTS3 = ["minimal", "low", "medium", "high"];
748
+ function shellQuote3(value) {
749
+ return `'${value.replace(/'/g, `'\\''`)}'`;
750
+ }
751
+ function getArgValue3(flag) {
752
+ const index = args3.indexOf(flag);
753
+ if (index === -1 || !args3[index + 1]) {
754
+ return "";
755
+ }
756
+ return args3[index + 1];
757
+ }
758
+ function toUnique2(values) {
759
+ const seen = /* @__PURE__ */ new Set();
760
+ return values.filter((value) => {
761
+ if (!value || seen.has(value)) {
762
+ return false;
763
+ }
764
+ seen.add(value);
765
+ return true;
766
+ });
767
+ }
768
+ function resolveReasoningEffort3() {
769
+ const customReasoningEffort = getArgValue3("--reasoning-effort");
770
+ if (customReasoningEffort) {
771
+ if (ALLOWED_REASONING_EFFORTS3.includes(customReasoningEffort)) {
772
+ trace5("reasoning:custom", customReasoningEffort);
773
+ return customReasoningEffort;
405
774
  }
775
+ console.warn(
776
+ `\u26A0\uFE0F \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 reasoning effort(${customReasoningEffort})\uC785\uB2C8\uB2E4. allowed: ${ALLOWED_REASONING_EFFORTS3.join(
777
+ ", "
778
+ )}`
779
+ );
780
+ }
781
+ if (args3.includes("--flash")) {
782
+ trace5("reasoning:flash-default", "minimal");
783
+ return "minimal";
784
+ }
785
+ if (args3.includes("--review")) {
786
+ trace5("reasoning:review-default", "high");
787
+ return "high";
406
788
  }
789
+ trace5("reasoning:default", "medium");
790
+ return "medium";
791
+ }
792
+ function resolvePrimaryAlias2(reasoningEffort) {
793
+ if (args3.includes("--review")) {
794
+ trace5("model:mode-alias", "pro");
795
+ return "pro";
796
+ }
797
+ if (args3.includes("--flash")) {
798
+ trace5("model:mode-alias", "flash");
799
+ return "flash";
800
+ }
801
+ if (reasoningEffort === "high") {
802
+ trace5("model:reasoning-alias", "pro");
803
+ return "pro";
804
+ }
805
+ if (reasoningEffort === "minimal" || reasoningEffort === "low") {
806
+ trace5("model:reasoning-alias", "flash");
807
+ return "flash";
808
+ }
809
+ trace5("model:default-alias", "auto");
810
+ return "auto";
811
+ }
812
+ function getAliasFallbacks2(primaryAlias) {
813
+ if (primaryAlias === "pro") {
814
+ return ["pro", "flash", "auto"];
815
+ }
816
+ if (primaryAlias === "flash") {
817
+ return ["flash", "auto", "pro"];
818
+ }
819
+ return [primaryAlias, "auto", "flash", "pro"];
820
+ }
821
+ function getReasoningInstruction(reasoningEffort) {
822
+ if (reasoningEffort === "high") {
823
+ return "high (\uAE4A\uC774 \uC788\uB294 \uBD84\uC11D, \uC7A0\uC7AC\uC801 \uB9AC\uC2A4\uD06C\uAE4C\uC9C0 \uC810\uAC80)";
824
+ }
825
+ if (reasoningEffort === "medium") {
826
+ return "medium (\uADE0\uD615 \uC7A1\uD78C \uBD84\uC11D\uACFC \uD575\uC2EC \uC774\uC288 \uC911\uC2EC)";
827
+ }
828
+ if (reasoningEffort === "low") {
829
+ return "low (\uD575\uC2EC \uACB0\uD568 \uC704\uC8FC\uB85C \uAC04\uACB0\uD558\uAC8C \uBD84\uC11D)";
830
+ }
831
+ return "minimal (\uCE58\uBA85\uB3C4 \uB192\uC740 \uC774\uC288\uB9CC \uB9E4\uC6B0 \uAC04\uACB0\uD558\uAC8C \uBD84\uC11D)";
832
+ }
833
+ function buildGeminiExecCommand(prompt, model) {
834
+ const modelOption = model ? `--model ${shellQuote3(model)}` : "";
835
+ return `gemini ${[modelOption, "-p", shellQuote3(prompt)].filter(Boolean).join(" ")}`;
836
+ }
837
+ var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
838
+ trace5("createGeminiCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
839
+ const customModel = getArgValue3("--model");
840
+ const reasoningEffort = resolveReasoningEffort3();
841
+ const primaryAlias = resolvePrimaryAlias2(reasoningEffort);
842
+ const aliasFallbacks = toUnique2(getAliasFallbacks2(primaryAlias));
407
843
  const rules = [
408
844
  { path: rulesPath, display: "\uB8F0\uC14B" },
409
845
  { path: namingRulesPath, display: "\uB124\uC774\uBC0D \uADDC\uCE59" },
@@ -412,7 +848,29 @@ var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
412
848
  const validRules = rules.filter((rule) => fs__default.default.existsSync(rule.path)).map((rule) => `@${rule.path}`).join(", ");
413
849
  const rulesCount = validRules ? validRules.split(",").length : 0;
414
850
  trace5("rules:loaded", `count=${rulesCount}`);
415
- 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. "`;
851
+ const reviewFormRef = fs__default.default.existsSync(reviewFormPath2) ? `@${reviewFormPath2}` : "(\uC5C6\uC74C)";
852
+ trace5("reviewForm:status", reviewFormRef === "(\uC5C6\uC74C)" ? "missing" : "exists");
853
+ const reasoningInstruction = getReasoningInstruction(reasoningEffort);
854
+ const prompt = `\uB2E4\uC74C \uADDC\uCE59\uB4E4\uC744 \uCC38\uACE0\uD574\uC11C(${validRules || "(\uC5C6\uC74C)"}) \uC774 diff(@${tempDiffPath2})\uB97C \uB9AC\uBDF0\uD574\uC918.
855
+ \uB9AC\uBDF0 \uC591\uC2DD\uC740 ${reviewFormRef} \uC5D0 \uB9DE\uCDB0\uC11C \uC791\uC131\uD574\uC918.
856
+ \uCD94\uB860 \uAC15\uB3C4 \uC9C0\uCE68: ${reasoningInstruction}`;
857
+ trace5("prompt:prepared", `length=${prompt.length}`);
858
+ const modelCandidates = toUnique2(customModel ? [customModel, ...aliasFallbacks] : aliasFallbacks);
859
+ trace5("model:candidates", modelCandidates.join(", "));
860
+ trace5("command:candidates:count", String(modelCandidates.length + 1));
861
+ if (customModel) {
862
+ console.warn(
863
+ `\u26A0\uFE0F \uCEE4\uC2A4\uD140 \uBAA8\uB378(${customModel})\uC744 \uC6B0\uC120 \uC2DC\uB3C4\uD558\uACE0 \uC2E4\uD328\uD558\uBA74 alias(${aliasFallbacks.join(
864
+ " -> "
865
+ )}) \uBC0F \uAE30\uBCF8 \uBAA8\uB378 \uC21C\uC73C\uB85C \uD3F4\uBC31\uD569\uB2C8\uB2E4.`
866
+ );
867
+ } else {
868
+ console.warn(
869
+ `\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.`
870
+ );
871
+ }
872
+ const commandCandidates = modelCandidates.map((model) => buildGeminiExecCommand(prompt, model));
873
+ const command = [...commandCandidates, buildGeminiExecCommand(prompt)].join(" || ");
416
874
  trace5("command:created");
417
875
  if (args3.includes("--test")) {
418
876
  const safeCommand = command.replace(/"/g, '\\"');
@@ -422,6 +880,7 @@ var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
422
880
  \uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
423
881
  ${safeCommand}"`;
424
882
  }
883
+ trace5("command:mode", "execute");
425
884
  trace5("createGeminiCommand:end");
426
885
  return command;
427
886
  };
@@ -432,21 +891,23 @@ function checkGeminiCliInstalled() {
432
891
  trace6("version-check:run", "gemini --version");
433
892
  child_process.execSync("gemini --version", { stdio: "ignore" });
434
893
  trace6("version-check:ok");
435
- } catch {
436
- trace6("version-check:failed", "install-start");
894
+ } catch (error) {
895
+ trace6("version-check:failed", getErrorSummary(error));
896
+ trace6("install:start", "@google/gemini-cli");
437
897
  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");
438
898
  try {
439
899
  child_process.execSync("npm install -g @google/gemini-cli", { stdio: "inherit" });
440
- trace6("install:ok", "exit(1) for login");
900
+ trace6("install:ok", "login-required");
441
901
  console.log("\u2705 gemini-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
442
902
  console.log("\u26A0\uFE0F Gemini API \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
443
903
  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.');
444
904
  process.exit(1);
445
905
  } catch (installError) {
446
- trace6("install:failed");
447
- 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).");
448
- console.error(installError);
449
- process.exit(1);
906
+ trace6("install:failed", getErrorSummary(installError));
907
+ exitWithError("\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).", {
908
+ scope: "installation-gemini",
909
+ error: installError
910
+ });
450
911
  }
451
912
  }
452
913
  trace6("checkGeminiCliInstalled:end");
@@ -455,30 +916,35 @@ function checkGeminiCliInstalled() {
455
916
  // src/pr-review/review.ts
456
917
  async function main() {
457
918
  const args4 = process.argv.slice(2);
919
+ clearTraceMessages();
458
920
  const isTest = isTestMode(args4);
459
921
  const trace7 = createTraceLogger("review", args4);
460
922
  trace7("main:start", `args=${JSON.stringify(args4)}`);
461
- trace7("service-selection:start");
462
- const service = await showSelectionAIService();
463
- trace7("service-selection:done", `service=${service}`);
464
- switch (service) {
465
- case "gemini":
466
- trace7("install-check:start", "service=gemini");
467
- checkGeminiCliInstalled();
468
- trace7("install-check:done", "service=gemini");
469
- break;
470
- case "claude":
471
- trace7("install-check:start", "service=claude");
472
- checkClaudeCliInstalled();
473
- trace7("install-check:done", "service=claude");
474
- break;
475
- case "codex":
476
- trace7("install-check:start", "service=codex");
477
- checkCodexCliInstalled();
478
- trace7("install-check:done", "service=codex");
479
- break;
480
- }
923
+ let command = "";
924
+ let savedDiffPath = "";
925
+ let savedReportPath = "";
926
+ let service = "";
481
927
  try {
928
+ trace7("service-selection:start");
929
+ service = await showSelectionAIService();
930
+ trace7("service-selection:done", `service=${service}`);
931
+ switch (service) {
932
+ case "gemini":
933
+ trace7("install-check:start", "service=gemini");
934
+ checkGeminiCliInstalled();
935
+ trace7("install-check:done", "service=gemini");
936
+ break;
937
+ case "claude":
938
+ trace7("install-check:start", "service=claude");
939
+ checkClaudeCliInstalled();
940
+ trace7("install-check:done", "service=claude");
941
+ break;
942
+ case "codex":
943
+ trace7("install-check:start", "service=codex");
944
+ checkCodexCliInstalled();
945
+ trace7("install-check:done", "service=codex");
946
+ break;
947
+ }
482
948
  trace7("review-flow:start");
483
949
  console.log("\u{1F680} AI Code Review\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4...");
484
950
  const nowStr = getNowString();
@@ -496,8 +962,8 @@ async function main() {
496
962
  trace7("git-diff:run");
497
963
  diff = child_process.execSync(`git diff ${diffArgs} -- ${includeParams} ${excludeParams}`).toString();
498
964
  trace7("git-diff:done", `length=${diff.length}`);
499
- } catch {
500
- trace7("git-diff:error", "fallback-empty-diff");
965
+ } catch (error) {
966
+ trace7("git-diff:error", getErrorSummary(error));
501
967
  }
502
968
  if (!diff.trim() && !isTest) {
503
969
  trace7("empty-diff:exit");
@@ -509,10 +975,9 @@ async function main() {
509
975
  fs__default.default.writeFileSync(tempDiffPath, diff);
510
976
  trace7("temp-diff:write:done");
511
977
  trace7("saved-diff:copy:start");
512
- const savedDiffPath = getNextFilePath(REPORT_DIR, `${nowStr}-diff`, ".txt");
978
+ savedDiffPath = getNextFilePath(REPORT_DIR, `${nowStr}-diff`, ".txt");
513
979
  fs__default.default.copyFileSync(tempDiffPath, savedDiffPath);
514
980
  trace7("saved-diff:copy:done", savedDiffPath);
515
- let command = "";
516
981
  trace7("command:create:start", `service=${service}`);
517
982
  switch (service) {
518
983
  case "gemini":
@@ -531,7 +996,7 @@ async function main() {
531
996
  trace7("command:exec:done", `resultLength=${result.length}`);
532
997
  console.log(result);
533
998
  trace7("report:write:start");
534
- const savedReportPath = getNextFilePath(REPORT_DIR, nowStr, ".md");
999
+ savedReportPath = getNextFilePath(REPORT_DIR, nowStr, ".md");
535
1000
  fs__default.default.writeFileSync(savedReportPath, result);
536
1001
  trace7("report:write:done", savedReportPath);
537
1002
  if (isTest) {
@@ -555,12 +1020,45 @@ ${command}`);
555
1020
  trace7("cleanup-temp-diff:done");
556
1021
  trace7("review-flow:end");
557
1022
  } catch (error) {
558
- trace7("review-flow:catch");
1023
+ trace7("review-flow:catch", getErrorSummary(error));
1024
+ let errorReportPath = "";
1025
+ trace7("cleanup-temp-diff:start(catch)");
1026
+ try {
1027
+ deleteTempDiff();
1028
+ trace7("cleanup-temp-diff:done(catch)");
1029
+ } catch (cleanupError) {
1030
+ trace7("cleanup-temp-diff:failed(catch)", getErrorSummary(cleanupError));
1031
+ console.error("\u26A0\uFE0F \uC784\uC2DC diff \uC815\uB9AC \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
1032
+ console.error(cleanupError);
1033
+ }
1034
+ trace7("error-report:prepare", `service=${service}`);
1035
+ errorReportPath = writeErrorReport(error, {
1036
+ scope: "review",
1037
+ args: args4,
1038
+ extraSections: [
1039
+ {
1040
+ heading: "Execution Context",
1041
+ markdown: `\`\`\`json
1042
+ ${JSON.stringify(
1043
+ {
1044
+ service,
1045
+ command: command || null,
1046
+ tempDiffPath,
1047
+ savedDiffPath: savedDiffPath || null,
1048
+ savedReportPath: savedReportPath || null
1049
+ },
1050
+ null,
1051
+ 2
1052
+ )}
1053
+ \`\`\``
1054
+ }
1055
+ ]
1056
+ });
559
1057
  console.error("\u274C \uB9AC\uBDF0 \uB3C4\uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
560
1058
  console.error(error);
561
- trace7("cleanup-temp-diff:start(catch)");
562
- deleteTempDiff();
563
- trace7("cleanup-temp-diff:done(catch)");
1059
+ if (errorReportPath) {
1060
+ console.error(`\u{1F4C4} \uC5D0\uB7EC \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${errorReportPath}`);
1061
+ }
564
1062
  process.exit(1);
565
1063
  }
566
1064
  }