sales-frontend-gemini-cli 0.4.3 → 0.4.4

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 (41) hide show
  1. package/dist/common/helper.cjs +119 -3
  2. package/dist/common/helper.cjs.map +1 -1
  3. package/dist/common/helper.d.cts +30 -1
  4. package/dist/common/helper.d.ts +30 -1
  5. package/dist/common/helper.js +118 -4
  6. package/dist/common/helper.js.map +1 -1
  7. package/dist/pr-review/claude/claude-commander.cjs +10 -3
  8. package/dist/pr-review/claude/claude-commander.cjs.map +1 -1
  9. package/dist/pr-review/claude/claude-commander.js +10 -3
  10. package/dist/pr-review/claude/claude-commander.js.map +1 -1
  11. package/dist/pr-review/claude/installation-claude.cjs +1 -1
  12. package/dist/pr-review/claude/installation-claude.cjs.map +1 -1
  13. package/dist/pr-review/claude/installation-claude.js +1 -1
  14. package/dist/pr-review/claude/installation-claude.js.map +1 -1
  15. package/dist/pr-review/codex/codex-commander.cjs +14 -4
  16. package/dist/pr-review/codex/codex-commander.cjs.map +1 -1
  17. package/dist/pr-review/codex/codex-commander.d.cts +1 -1
  18. package/dist/pr-review/codex/codex-commander.d.ts +1 -1
  19. package/dist/pr-review/codex/codex-commander.js +14 -4
  20. package/dist/pr-review/codex/codex-commander.js.map +1 -1
  21. package/dist/pr-review/codex/installation-codex.cjs +1 -1
  22. package/dist/pr-review/codex/installation-codex.cjs.map +1 -1
  23. package/dist/pr-review/codex/installation-codex.js +1 -1
  24. package/dist/pr-review/codex/installation-codex.js.map +1 -1
  25. package/dist/pr-review/gemini/gemini-commander.cjs +12 -12
  26. package/dist/pr-review/gemini/gemini-commander.cjs.map +1 -1
  27. package/dist/pr-review/gemini/gemini-commander.js +12 -12
  28. package/dist/pr-review/gemini/gemini-commander.js.map +1 -1
  29. package/dist/pr-review/gemini/installation-gemini.cjs +1 -1
  30. package/dist/pr-review/gemini/installation-gemini.cjs.map +1 -1
  31. package/dist/pr-review/gemini/installation-gemini.js +1 -1
  32. package/dist/pr-review/gemini/installation-gemini.js.map +1 -1
  33. package/dist/pr-review/review-one-by-one.cjs +223 -24
  34. package/dist/pr-review/review-one-by-one.cjs.map +1 -1
  35. package/dist/pr-review/review-one-by-one.js +223 -24
  36. package/dist/pr-review/review-one-by-one.js.map +1 -1
  37. package/dist/pr-review/review.cjs +220 -26
  38. package/dist/pr-review/review.cjs.map +1 -1
  39. package/dist/pr-review/review.js +220 -26
  40. package/dist/pr-review/review.js.map +1 -1
  41. package/package.json +1 -1
@@ -80,6 +80,9 @@ var ignoreList = [
80
80
  function isTestMode(args4 = process.argv.slice(2)) {
81
81
  return args4.includes("--test");
82
82
  }
83
+ function shouldStreamAIOutput(args4 = process.argv.slice(2)) {
84
+ return args4.includes("--stream-output");
85
+ }
83
86
  function clearTraceMessages() {
84
87
  traceMessages.length = 0;
85
88
  }
@@ -249,11 +252,41 @@ async function executeShellCommandWithProgress(command, options = {}) {
249
252
  return;
250
253
  }
251
254
  const exitSummary = signal ? `signal=${signal}` : `code=${String(code ?? "unknown")}`;
252
- reject(new Error(`\uC258 \uBA85\uB839 \uC2E4\uD589 \uC2E4\uD328 (${exitSummary})${stderr.trim() ? `
253
- ${stderr.trim()}` : ""}`));
255
+ const failureDetails = {
256
+ code,
257
+ command,
258
+ signal,
259
+ stderr,
260
+ stdout
261
+ };
262
+ reject(createShellCommandExecutionError(failureDetails, exitSummary));
254
263
  });
255
264
  });
256
265
  }
266
+ function getShellCommandFailurePreview(failureDetails) {
267
+ const stderrText = failureDetails.stderr.trim();
268
+ const stdoutText = failureDetails.stdout.trim();
269
+ const combinedOutput = stderrText || stdoutText;
270
+ if (!combinedOutput) {
271
+ return "";
272
+ }
273
+ const MAX_PREVIEW_LENGTH = 4e3;
274
+ if (combinedOutput.length <= MAX_PREVIEW_LENGTH) {
275
+ return combinedOutput;
276
+ }
277
+ return combinedOutput.slice(-4e3);
278
+ }
279
+ function createShellCommandExecutionError(failureDetails, exitSummary) {
280
+ const failurePreview = getShellCommandFailurePreview(failureDetails);
281
+ const error = new Error(`\uC258 \uBA85\uB839 \uC2E4\uD589 \uC2E4\uD328 (${exitSummary})${failurePreview ? `
282
+ ${failurePreview}` : ""}`);
283
+ error.code = failureDetails.code;
284
+ error.signal = failureDetails.signal;
285
+ error.stdout = failureDetails.stdout;
286
+ error.stderr = failureDetails.stderr;
287
+ error.command = failureDetails.command;
288
+ return error;
289
+ }
257
290
  function formatReviewTargetFiles(files, visibleCount = 5) {
258
291
  if (files.length === 0) {
259
292
  return "(\uC5C6\uC74C)";
@@ -326,7 +359,7 @@ function serializeError(error) {
326
359
  }
327
360
  if (error && typeof error === "object") {
328
361
  const errorLike = error;
329
- const extraKeys = ["code", "errno", "syscall", "path", "cmd", "status", "signal", "spawnargs"];
362
+ const extraKeys = ["code", "errno", "syscall", "path", "cmd", "status", "signal", "spawnargs", "command"];
330
363
  extraKeys.forEach((key) => {
331
364
  if (errorLike[key] !== void 0) {
332
365
  serialized[key] = errorLike[key];
@@ -432,6 +465,87 @@ ${section.markdown}`).join("\n")}
432
465
  return "";
433
466
  }
434
467
  }
468
+ function getExecutionLogSummary(status, title) {
469
+ if (title) {
470
+ return title;
471
+ }
472
+ switch (status) {
473
+ case "success":
474
+ return "\uB9AC\uBDF0 \uC2E4\uD589\uC774 \uC131\uACF5\uC801\uC73C\uB85C \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.";
475
+ case "failed":
476
+ return "\uB9AC\uBDF0 \uC2E4\uD589 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.";
477
+ case "partial_failure":
478
+ return "\uB9AC\uBDF0 \uC2E4\uD589\uC740 \uC644\uB8CC\uB418\uC5C8\uC9C0\uB9CC \uC77C\uBD80 \uB2E8\uACC4\uC5D0\uC11C \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.";
479
+ default:
480
+ return "\uB9AC\uBDF0 \uC2E4\uD589\uC774 \uCDE8\uC18C\uB418\uC5C8\uAC70\uB098 \uB9AC\uBDF0 \uB300\uC0C1\uC774 \uC5C6\uC5B4 \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.";
481
+ }
482
+ }
483
+ function formatExecutionDuration(startedAt, finishedAt) {
484
+ const durationMs = Math.max(0, finishedAt.getTime() - startedAt.getTime());
485
+ if (durationMs < 1e3) {
486
+ return `${durationMs}ms`;
487
+ }
488
+ const durationSeconds = durationMs / 1e3;
489
+ if (durationSeconds < 60) {
490
+ return `${durationSeconds.toFixed(1)}s`;
491
+ }
492
+ const minutes = Math.floor(durationSeconds / 60);
493
+ const seconds = Math.round(durationSeconds % 60);
494
+ return `${minutes}m ${seconds}s`;
495
+ }
496
+ function writeExecutionLog(options = {}) {
497
+ try {
498
+ const startedAt = options.startedAt ?? /* @__PURE__ */ new Date();
499
+ const finishedAt = options.finishedAt ?? /* @__PURE__ */ new Date();
500
+ const status = options.status ?? "success";
501
+ helperTrace("execution-log:write:start", options.scope || "unknown");
502
+ createReportDirectory();
503
+ const reportPath = getAvailableFilePath(REPORT_DIR, `${getNowString(finishedAt)}-execution-log`, ".md");
504
+ const traceSnapshot = options.traceMessages ?? getTraceMessages();
505
+ const extraSections = options.extraSections || [];
506
+ const serializedError = options.error ? serializeError(options.error) : null;
507
+ const report = `# Execution Log
508
+
509
+ - \uC2DC\uC791 \uC2DC\uAC01: ${getHumanReadableNowString(startedAt)}
510
+ - \uC885\uB8CC \uC2DC\uAC01: ${getHumanReadableNowString(finishedAt)}
511
+ - \uC2E4\uD589 \uC2DC\uAC04: ${formatExecutionDuration(startedAt, finishedAt)}
512
+ - \uC0C1\uD0DC: \`${status}\`
513
+ - Scope: \`${options.scope || "unknown"}\`
514
+ - \uC791\uC5C5 \uACBD\uB85C: \`${process.cwd()}\`
515
+ - \uC2E4\uD589 \uC778\uC790: \`${JSON.stringify(options.args ?? process.argv.slice(2))}\`
516
+ - \uC2E4\uD589 \uD658\uACBD: \`${process.platform} ${process.arch} / Node ${process.version}\`
517
+
518
+ ## Summary
519
+
520
+ ${getExecutionLogSummary(status, options.title)}
521
+ ${serializedError ? `
522
+
523
+ ## Error
524
+
525
+ \`\`\`json
526
+ ${JSON.stringify(serializedError, null, 2)}
527
+ \`\`\`` : ""}
528
+
529
+ ## Trace
530
+
531
+ \`\`\`json
532
+ ${JSON.stringify(traceSnapshot, null, 2)}
533
+ \`\`\`${extraSections.length ? `
534
+ ${extraSections.map((section) => `
535
+ ## ${section.heading}
536
+
537
+ ${section.markdown}`).join("\n")}
538
+ ` : "\n"}
539
+ `;
540
+ fs__default.default.writeFileSync(reportPath, report);
541
+ helperTrace("execution-log:write:done", reportPath);
542
+ return reportPath;
543
+ } catch (writeError) {
544
+ console.error("\u26A0\uFE0F \uC2E4\uD589 \uB85C\uADF8 \uD30C\uC77C \uC0DD\uC131\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
545
+ console.error(writeError);
546
+ return "";
547
+ }
548
+ }
435
549
  function exitWithError(message, options = {}) {
436
550
  const reportPath = writeErrorReport(options.error || new Error(message), {
437
551
  ...options,
@@ -819,6 +933,13 @@ var ALLOWED_REASONING_EFFORTS = ["minimal", "low", "medium", "high"];
819
933
  function shellQuote(value) {
820
934
  return `'${value.replace(/'/g, `'\\''`)}'`;
821
935
  }
936
+ function toShellOptionToken(value) {
937
+ const SIMPLE_SHELL_TOKEN_PATTERN = /^[A-Za-z0-9._:/=-]+$/;
938
+ if (SIMPLE_SHELL_TOKEN_PATTERN.test(value)) {
939
+ return value;
940
+ }
941
+ return shellQuote(value);
942
+ }
822
943
  function getArgValue(flag) {
823
944
  const index = args.indexOf(flag);
824
945
  if (index === -1 || !args[index + 1]) {
@@ -898,9 +1019,9 @@ function getAliasFallbacks(primaryAlias) {
898
1019
  }
899
1020
  function buildClaudeExecCommand(options) {
900
1021
  const { tempDiffPath: tempDiffPath2, prompt, systemPromptFiles, effort, model, fallbackModel } = options;
901
- const modelOption = model ? `--model ${shellQuote(model)}` : "";
902
- const fallbackOption = model && fallbackModel ? `--fallback-model ${shellQuote(fallbackModel)}` : "";
903
- const effortOption = `--effort ${shellQuote(effort)}`;
1022
+ const modelOption = model ? `--model ${toShellOptionToken(model)}` : "";
1023
+ const fallbackOption = model && fallbackModel ? `--fallback-model ${toShellOptionToken(fallbackModel)}` : "";
1024
+ const effortOption = `--effort ${toShellOptionToken(effort)}`;
904
1025
  const appendedPromptFiles = systemPromptFiles.map((path3) => `--append-system-prompt-file ${shellQuote(path3)}`).join(" ");
905
1026
  return `cat ${shellQuote(tempDiffPath2)} | claude ${[
906
1027
  modelOption,
@@ -1025,12 +1146,22 @@ function printNotice2(message) {
1025
1146
  console.warn(message);
1026
1147
  }
1027
1148
  }
1149
+ function normalizeEffort2(level) {
1150
+ if (level === "minimal") {
1151
+ return "low";
1152
+ }
1153
+ return level;
1154
+ }
1028
1155
  function resolveReasoningEffort2() {
1029
1156
  const customReasoningEffort = getArgValue2("--reasoning-effort");
1030
1157
  if (customReasoningEffort) {
1031
1158
  if (ALLOWED_REASONING_EFFORTS2.includes(customReasoningEffort)) {
1032
- trace3("reasoning:custom", customReasoningEffort);
1033
- return customReasoningEffort;
1159
+ const normalized = normalizeEffort2(customReasoningEffort);
1160
+ trace3("reasoning:custom", `${customReasoningEffort} -> ${normalized}`);
1161
+ if (customReasoningEffort === "minimal") {
1162
+ printNotice2("\u26A0\uFE0F Codex\uB294 minimal\uC774 web_search \uB3C4\uAD6C\uC640 \uCDA9\uB3CC\uD560 \uC218 \uC788\uC5B4 low\uB85C \uB9E4\uD551\uD569\uB2C8\uB2E4.");
1163
+ }
1164
+ return normalized;
1034
1165
  }
1035
1166
  printNotice2(
1036
1167
  `\u26A0\uFE0F \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 reasoning effort(${customReasoningEffort})\uC785\uB2C8\uB2E4. allowed: ${ALLOWED_REASONING_EFFORTS2.join(
@@ -1039,8 +1170,8 @@ function resolveReasoningEffort2() {
1039
1170
  );
1040
1171
  }
1041
1172
  if (args2.includes("--flash")) {
1042
- trace3("reasoning:flash-default", "minimal");
1043
- return "minimal";
1173
+ trace3("reasoning:flash-default", "low");
1174
+ return "low";
1044
1175
  }
1045
1176
  if (args2.includes("--review")) {
1046
1177
  trace3("reasoning:review-default", "high");
@@ -1235,7 +1366,7 @@ function buildGeminiFileReferenceSection(files) {
1235
1366
  const existingFiles = files.filter((file) => fs__default.default.existsSync(file.path));
1236
1367
  return {
1237
1368
  count: existingFiles.length,
1238
- lines: existingFiles.map((file) => `- ${file.display}: ${toGeminiFileReference(file.path)}`)
1369
+ items: existingFiles.map((file) => `${file.display} ${toGeminiFileReference(file.path)}`)
1239
1370
  };
1240
1371
  }
1241
1372
  var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
@@ -1254,19 +1385,19 @@ var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
1254
1385
  const ruleSection = buildGeminiFileReferenceSection(rules);
1255
1386
  trace5("rules:loaded", `count=${ruleSection.count}`);
1256
1387
  const reviewFormExists = fs__default.default.existsSync(resolvedReviewFormPath);
1257
- const reviewFormLine = reviewFormExists ? `- \uB9AC\uBDF0 \uC591\uC2DD: ${toGeminiFileReference(resolvedReviewFormPath)}` : "- \uB9AC\uBDF0 \uC591\uC2DD: (\uC5C6\uC74C)";
1388
+ const reviewFormText = reviewFormExists ? `\uB9AC\uBDF0 \uC591\uC2DD ${toGeminiFileReference(resolvedReviewFormPath)}` : "\uB9AC\uBDF0 \uC591\uC2DD (\uC5C6\uC74C)";
1258
1389
  trace5("reviewForm:status", reviewFormExists ? "exists" : "missing");
1259
1390
  const reasoningInstruction = getReasoningInstruction(reasoningEffort);
1260
- const prompt = `\uC544\uB798 \uD30C\uC77C\uB4E4\uC744 \uC21C\uC11C\uB300\uB85C \uC77D\uACE0 \uCF54\uB4DC \uB9AC\uBDF0\uB97C \uC9C4\uD589\uD574\uC918.
1261
- \uADDC\uCE59 \uD30C\uC77C:
1262
- ${ruleSection.lines.join("\n") || "- (\uC5C6\uC74C)"}
1263
- \uB9AC\uBDF0 \uC591\uC2DD \uD30C\uC77C:
1264
- ${reviewFormLine}
1265
- \uB9AC\uBDF0 \uB300\uC0C1 diff \uD30C\uC77C:
1266
- - \uB9AC\uBDF0 \uB300\uC0C1 diff: ${toGeminiFileReference(resolvedTempDiffPath)}
1267
-
1268
- \uBC18\uB4DC\uC2DC \uB9AC\uBDF0 \uC591\uC2DD\uC5D0 \uB9DE\uCDB0 \uC791\uC131\uD574\uC918.
1269
- \uCD94\uB860 \uAC15\uB3C4 \uC9C0\uCE68: ${reasoningInstruction}`;
1391
+ const ruleText = ruleSection.items.join(" ") || "(\uC5C6\uC74C)";
1392
+ const diffText = `\uB9AC\uBDF0 \uB300\uC0C1 diff ${toGeminiFileReference(resolvedTempDiffPath)}`;
1393
+ const prompt = [
1394
+ "\uC544\uB798 \uD30C\uC77C\uB4E4\uC744 \uC21C\uC11C\uB300\uB85C \uC77D\uACE0 \uCF54\uB4DC \uB9AC\uBDF0\uB97C \uC9C4\uD589\uD574\uC918.",
1395
+ `\uADDC\uCE59 \uD30C\uC77C: ${ruleText}`,
1396
+ `\uB9AC\uBDF0 \uC591\uC2DD \uD30C\uC77C: ${reviewFormText}`,
1397
+ `\uB9AC\uBDF0 \uB300\uC0C1 diff \uD30C\uC77C: ${diffText}`,
1398
+ "\uBC18\uB4DC\uC2DC \uB9AC\uBDF0 \uC591\uC2DD\uC5D0 \uB9DE\uCDB0 \uC791\uC131\uD574\uC918.",
1399
+ `\uCD94\uB860 \uAC15\uB3C4 \uC9C0\uCE68: ${reasoningInstruction}`
1400
+ ].join(" ");
1270
1401
  trace5("prompt:prepared", `length=${prompt.length}`);
1271
1402
  const modelCandidates = toUnique2(customModel ? [customModel, ...aliasFallbacks] : aliasFallbacks);
1272
1403
  trace5("model:candidates", modelCandidates.join(", "));
@@ -1329,8 +1460,10 @@ function checkGeminiCliInstalled() {
1329
1460
  // src/pr-review/review.ts
1330
1461
  async function main() {
1331
1462
  const args4 = process.argv.slice(2);
1463
+ const startedAt = /* @__PURE__ */ new Date();
1332
1464
  clearTraceMessages();
1333
1465
  const isTest = isTestMode(args4);
1466
+ const shouldStreamOutput = shouldStreamAIOutput(args4);
1334
1467
  const trace7 = createTraceLogger("review", args4);
1335
1468
  trace7("main:start", `args=${JSON.stringify(args4)}`);
1336
1469
  let command = "";
@@ -1339,6 +1472,12 @@ async function main() {
1339
1472
  let service = "";
1340
1473
  let selectedCommitSummary = "";
1341
1474
  let reviewTargetFiles = [];
1475
+ let executionLogPath = "";
1476
+ let executionStatus = "cancelled";
1477
+ let executionTitle = "\uB9AC\uBDF0 \uC2E4\uD589\uC774 \uCDE8\uC18C\uB418\uC5C8\uAC70\uB098 \uB9AC\uBDF0 \uB300\uC0C1\uC774 \uC5C6\uC5B4 \uC885\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.";
1478
+ let executionError = null;
1479
+ let resultLength = 0;
1480
+ let exitCode = 0;
1342
1481
  try {
1343
1482
  trace7("service-selection:start");
1344
1483
  service = await showSelectionAIService();
@@ -1362,14 +1501,18 @@ async function main() {
1362
1501
  }
1363
1502
  trace7("review-flow:start");
1364
1503
  console.log("\u{1F680} AI Code Review\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4...");
1504
+ if (shouldStreamOutput) {
1505
+ console.log("\u2139\uFE0F AI \uC2E4\uC2DC\uAC04 \uC751\uB2F5 \uD45C\uC2DC \uBAA8\uB4DC\uAC00 \uD65C\uC131\uD654\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
1506
+ }
1365
1507
  trace7("commit-selection:start");
1366
1508
  const selectedCommits = await selectReviewCommits();
1367
1509
  trace7("commit-selection:done", `count=${selectedCommits.length}`);
1368
1510
  if (selectedCommits.length === 0) {
1369
1511
  trace7("commit-selection:empty");
1512
+ executionTitle = "\uC120\uD0DD\uB41C \uCEE4\uBC0B\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.";
1370
1513
  console.log("\u2139\uFE0F \uC120\uD0DD\uB41C \uCEE4\uBC0B\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
1371
1514
  deleteTempDiff();
1372
- process.exit(0);
1515
+ return;
1373
1516
  }
1374
1517
  selectedCommitSummary = buildSelectedCommitSummary(selectedCommits);
1375
1518
  trace7("commit-summary:prepared", selectedCommitSummary);
@@ -1381,9 +1524,10 @@ async function main() {
1381
1524
  trace7("git-diff:build:done", `length=${diff.length}`);
1382
1525
  if (!diff.trim() && !isTest) {
1383
1526
  trace7("empty-diff:exit");
1527
+ executionTitle = "\uC120\uD0DD\uD55C \uCEE4\uBC0B\uC5D0\uC11C \uB9AC\uBDF0 \uB300\uC0C1 \uD30C\uC77C \uBCC0\uACBD\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.";
1384
1528
  console.log("\u2139\uFE0F \uC120\uD0DD\uD55C \uCEE4\uBC0B\uC5D0\uC11C \uB9AC\uBDF0 \uB300\uC0C1 \uD30C\uC77C \uBCC0\uACBD\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
1385
1529
  deleteTempDiff();
1386
- process.exit(0);
1530
+ return;
1387
1531
  }
1388
1532
  const nowStr = getNowString();
1389
1533
  trace7("timestamp:created", nowStr);
@@ -1413,8 +1557,9 @@ async function main() {
1413
1557
  trace7("command:exec:start");
1414
1558
  const result = (await executeShellCommandWithProgress(command, {
1415
1559
  progressMessage: `\u23F3 [\uB9AC\uBDF0 \uC9C4\uD589] ${service} | \uB300\uC0C1 ${reviewTargetFiles.length}\uAC1C \uD30C\uC77C`,
1416
- streamOutput: isTest
1560
+ streamOutput: isTest || shouldStreamOutput
1417
1561
  })).stdout;
1562
+ resultLength = result.length;
1418
1563
  trace7("command:exec:done", `resultLength=${result.length}`);
1419
1564
  trace7("report:write:start");
1420
1565
  savedReportPath = getNextFilePath(REPORT_DIR, nowStr, ".md");
@@ -1440,9 +1585,15 @@ ${command}`);
1440
1585
  deleteTempDiff();
1441
1586
  trace7("cleanup-temp-diff:done");
1442
1587
  trace7("review-flow:end");
1588
+ executionStatus = "success";
1589
+ executionTitle = "\uB9AC\uBDF0\uAC00 \uC131\uACF5\uC801\uC73C\uB85C \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.";
1443
1590
  } catch (error) {
1444
1591
  trace7("review-flow:catch", getErrorSummary(error));
1445
1592
  let errorReportPath = "";
1593
+ executionStatus = "failed";
1594
+ executionTitle = "\uB9AC\uBDF0 \uC2E4\uD589 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.";
1595
+ executionError = error;
1596
+ exitCode = 1;
1446
1597
  trace7("cleanup-temp-diff:start(catch)");
1447
1598
  try {
1448
1599
  deleteTempDiff();
@@ -1482,7 +1633,50 @@ ${JSON.stringify(
1482
1633
  if (errorReportPath) {
1483
1634
  console.error(`\u{1F4C4} \uC5D0\uB7EC \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${errorReportPath}`);
1484
1635
  }
1485
- process.exit(1);
1636
+ } finally {
1637
+ executionLogPath = writeExecutionLog({
1638
+ scope: "review",
1639
+ status: executionStatus,
1640
+ title: executionTitle,
1641
+ args: args4,
1642
+ startedAt,
1643
+ error: executionError,
1644
+ extraSections: [
1645
+ {
1646
+ heading: "Execution Context",
1647
+ markdown: `\`\`\`json
1648
+ ${JSON.stringify(
1649
+ {
1650
+ service: service || null,
1651
+ selectedCommitSummary: selectedCommitSummary || null,
1652
+ reviewTargetFiles,
1653
+ command: command || null,
1654
+ tempDiffPath,
1655
+ savedDiffPath: savedDiffPath || null,
1656
+ savedReportPath: savedReportPath || null,
1657
+ shouldStreamOutput,
1658
+ resultLength
1659
+ },
1660
+ null,
1661
+ 2
1662
+ )}
1663
+ \`\`\``
1664
+ },
1665
+ {
1666
+ heading: "Generated Command",
1667
+ markdown: command ? `\`\`\`sh
1668
+ ${command}
1669
+ \`\`\`` : "(\uC5C6\uC74C)"
1670
+ }
1671
+ ]
1672
+ });
1673
+ if (executionLogPath) {
1674
+ const writeLog = executionStatus === "failed" ? console.error : console.log;
1675
+ writeLog(`\u{1F4DD} \uC2E4\uD589 \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${executionLogPath}`);
1676
+ }
1677
+ }
1678
+ if (exitCode !== 0) {
1679
+ process.exit(exitCode);
1486
1680
  }
1487
1681
  }
1488
1682
  main();