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
@@ -269,7 +269,7 @@ function serializeError(error) {
269
269
  }
270
270
  if (error && typeof error === "object") {
271
271
  const errorLike = error;
272
- const extraKeys = ["code", "errno", "syscall", "path", "cmd", "status", "signal", "spawnargs"];
272
+ const extraKeys = ["code", "errno", "syscall", "path", "cmd", "status", "signal", "spawnargs", "command"];
273
273
  extraKeys.forEach((key) => {
274
274
  if (errorLike[key] !== void 0) {
275
275
  serialized[key] = errorLike[key];
@@ -375,6 +375,87 @@ ${section.markdown}`).join("\n")}
375
375
  return "";
376
376
  }
377
377
  }
378
+ function getExecutionLogSummary(status, title) {
379
+ if (title) {
380
+ return title;
381
+ }
382
+ switch (status) {
383
+ case "success":
384
+ return "\uB9AC\uBDF0 \uC2E4\uD589\uC774 \uC131\uACF5\uC801\uC73C\uB85C \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.";
385
+ case "failed":
386
+ return "\uB9AC\uBDF0 \uC2E4\uD589 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.";
387
+ case "partial_failure":
388
+ 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.";
389
+ default:
390
+ 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.";
391
+ }
392
+ }
393
+ function formatExecutionDuration(startedAt, finishedAt) {
394
+ const durationMs = Math.max(0, finishedAt.getTime() - startedAt.getTime());
395
+ if (durationMs < 1e3) {
396
+ return `${durationMs}ms`;
397
+ }
398
+ const durationSeconds = durationMs / 1e3;
399
+ if (durationSeconds < 60) {
400
+ return `${durationSeconds.toFixed(1)}s`;
401
+ }
402
+ const minutes = Math.floor(durationSeconds / 60);
403
+ const seconds = Math.round(durationSeconds % 60);
404
+ return `${minutes}m ${seconds}s`;
405
+ }
406
+ function writeExecutionLog(options = {}) {
407
+ try {
408
+ const startedAt = options.startedAt ?? /* @__PURE__ */ new Date();
409
+ const finishedAt = options.finishedAt ?? /* @__PURE__ */ new Date();
410
+ const status = options.status ?? "success";
411
+ helperTrace("execution-log:write:start", options.scope || "unknown");
412
+ createReportDirectory();
413
+ const reportPath = getAvailableFilePath(REPORT_DIR, `${getNowString(finishedAt)}-execution-log`, ".md");
414
+ const traceSnapshot = options.traceMessages ?? getTraceMessages();
415
+ const extraSections = options.extraSections || [];
416
+ const serializedError = options.error ? serializeError(options.error) : null;
417
+ const report = `# Execution Log
418
+
419
+ - \uC2DC\uC791 \uC2DC\uAC01: ${getHumanReadableNowString(startedAt)}
420
+ - \uC885\uB8CC \uC2DC\uAC01: ${getHumanReadableNowString(finishedAt)}
421
+ - \uC2E4\uD589 \uC2DC\uAC04: ${formatExecutionDuration(startedAt, finishedAt)}
422
+ - \uC0C1\uD0DC: \`${status}\`
423
+ - Scope: \`${options.scope || "unknown"}\`
424
+ - \uC791\uC5C5 \uACBD\uB85C: \`${process.cwd()}\`
425
+ - \uC2E4\uD589 \uC778\uC790: \`${JSON.stringify(options.args ?? process.argv.slice(2))}\`
426
+ - \uC2E4\uD589 \uD658\uACBD: \`${process.platform} ${process.arch} / Node ${process.version}\`
427
+
428
+ ## Summary
429
+
430
+ ${getExecutionLogSummary(status, options.title)}
431
+ ${serializedError ? `
432
+
433
+ ## Error
434
+
435
+ \`\`\`json
436
+ ${JSON.stringify(serializedError, null, 2)}
437
+ \`\`\`` : ""}
438
+
439
+ ## Trace
440
+
441
+ \`\`\`json
442
+ ${JSON.stringify(traceSnapshot, null, 2)}
443
+ \`\`\`${extraSections.length ? `
444
+ ${extraSections.map((section) => `
445
+ ## ${section.heading}
446
+
447
+ ${section.markdown}`).join("\n")}
448
+ ` : "\n"}
449
+ `;
450
+ fs.writeFileSync(reportPath, report);
451
+ helperTrace("execution-log:write:done", reportPath);
452
+ return reportPath;
453
+ } catch (writeError) {
454
+ console.error("\u26A0\uFE0F \uC2E4\uD589 \uB85C\uADF8 \uD30C\uC77C \uC0DD\uC131\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
455
+ console.error(writeError);
456
+ return "";
457
+ }
458
+ }
378
459
  function exitWithError(message, options = {}) {
379
460
  const reportPath = writeErrorReport(options.error || new Error(message), {
380
461
  ...options,
@@ -778,6 +859,13 @@ var ALLOWED_REASONING_EFFORTS = ["minimal", "low", "medium", "high"];
778
859
  function shellQuote(value) {
779
860
  return `'${value.replace(/'/g, `'\\''`)}'`;
780
861
  }
862
+ function toShellOptionToken(value) {
863
+ const SIMPLE_SHELL_TOKEN_PATTERN = /^[A-Za-z0-9._:/=-]+$/;
864
+ if (SIMPLE_SHELL_TOKEN_PATTERN.test(value)) {
865
+ return value;
866
+ }
867
+ return shellQuote(value);
868
+ }
781
869
  function getArgValue(flag) {
782
870
  const index = args.indexOf(flag);
783
871
  if (index === -1 || !args[index + 1]) {
@@ -857,9 +945,9 @@ function getAliasFallbacks(primaryAlias) {
857
945
  }
858
946
  function buildClaudeExecCommand(options) {
859
947
  const { tempDiffPath: tempDiffPath2, prompt, systemPromptFiles, effort, model, fallbackModel } = options;
860
- const modelOption = model ? `--model ${shellQuote(model)}` : "";
861
- const fallbackOption = model && fallbackModel ? `--fallback-model ${shellQuote(fallbackModel)}` : "";
862
- const effortOption = `--effort ${shellQuote(effort)}`;
948
+ const modelOption = model ? `--model ${toShellOptionToken(model)}` : "";
949
+ const fallbackOption = model && fallbackModel ? `--fallback-model ${toShellOptionToken(fallbackModel)}` : "";
950
+ const effortOption = `--effort ${toShellOptionToken(effort)}`;
863
951
  const appendedPromptFiles = systemPromptFiles.map((path3) => `--append-system-prompt-file ${shellQuote(path3)}`).join(" ");
864
952
  return `cat ${shellQuote(tempDiffPath2)} | claude ${[
865
953
  modelOption,
@@ -984,12 +1072,22 @@ function printNotice2(message) {
984
1072
  console.warn(message);
985
1073
  }
986
1074
  }
1075
+ function normalizeEffort2(level) {
1076
+ if (level === "minimal") {
1077
+ return "low";
1078
+ }
1079
+ return level;
1080
+ }
987
1081
  function resolveReasoningEffort2() {
988
1082
  const customReasoningEffort = getArgValue2("--reasoning-effort");
989
1083
  if (customReasoningEffort) {
990
1084
  if (ALLOWED_REASONING_EFFORTS2.includes(customReasoningEffort)) {
991
- trace3("reasoning:custom", customReasoningEffort);
992
- return customReasoningEffort;
1085
+ const normalized = normalizeEffort2(customReasoningEffort);
1086
+ trace3("reasoning:custom", `${customReasoningEffort} -> ${normalized}`);
1087
+ if (customReasoningEffort === "minimal") {
1088
+ 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.");
1089
+ }
1090
+ return normalized;
993
1091
  }
994
1092
  printNotice2(
995
1093
  `\u26A0\uFE0F \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 reasoning effort(${customReasoningEffort})\uC785\uB2C8\uB2E4. allowed: ${ALLOWED_REASONING_EFFORTS2.join(
@@ -998,8 +1096,8 @@ function resolveReasoningEffort2() {
998
1096
  );
999
1097
  }
1000
1098
  if (args2.includes("--flash")) {
1001
- trace3("reasoning:flash-default", "minimal");
1002
- return "minimal";
1099
+ trace3("reasoning:flash-default", "low");
1100
+ return "low";
1003
1101
  }
1004
1102
  if (args2.includes("--review")) {
1005
1103
  trace3("reasoning:review-default", "high");
@@ -1194,7 +1292,7 @@ function buildGeminiFileReferenceSection(files) {
1194
1292
  const existingFiles = files.filter((file) => fs.existsSync(file.path));
1195
1293
  return {
1196
1294
  count: existingFiles.length,
1197
- lines: existingFiles.map((file) => `- ${file.display}: ${toGeminiFileReference(file.path)}`)
1295
+ items: existingFiles.map((file) => `${file.display} ${toGeminiFileReference(file.path)}`)
1198
1296
  };
1199
1297
  }
1200
1298
  var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
@@ -1213,19 +1311,19 @@ var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
1213
1311
  const ruleSection = buildGeminiFileReferenceSection(rules);
1214
1312
  trace5("rules:loaded", `count=${ruleSection.count}`);
1215
1313
  const reviewFormExists = fs.existsSync(resolvedReviewFormPath);
1216
- const reviewFormLine = reviewFormExists ? `- \uB9AC\uBDF0 \uC591\uC2DD: ${toGeminiFileReference(resolvedReviewFormPath)}` : "- \uB9AC\uBDF0 \uC591\uC2DD: (\uC5C6\uC74C)";
1314
+ const reviewFormText = reviewFormExists ? `\uB9AC\uBDF0 \uC591\uC2DD ${toGeminiFileReference(resolvedReviewFormPath)}` : "\uB9AC\uBDF0 \uC591\uC2DD (\uC5C6\uC74C)";
1217
1315
  trace5("reviewForm:status", reviewFormExists ? "exists" : "missing");
1218
1316
  const reasoningInstruction = getReasoningInstruction(reasoningEffort);
1219
- const prompt = `\uC544\uB798 \uD30C\uC77C\uB4E4\uC744 \uC21C\uC11C\uB300\uB85C \uC77D\uACE0 \uCF54\uB4DC \uB9AC\uBDF0\uB97C \uC9C4\uD589\uD574\uC918.
1220
- \uADDC\uCE59 \uD30C\uC77C:
1221
- ${ruleSection.lines.join("\n") || "- (\uC5C6\uC74C)"}
1222
- \uB9AC\uBDF0 \uC591\uC2DD \uD30C\uC77C:
1223
- ${reviewFormLine}
1224
- \uB9AC\uBDF0 \uB300\uC0C1 diff \uD30C\uC77C:
1225
- - \uB9AC\uBDF0 \uB300\uC0C1 diff: ${toGeminiFileReference(resolvedTempDiffPath)}
1226
-
1227
- \uBC18\uB4DC\uC2DC \uB9AC\uBDF0 \uC591\uC2DD\uC5D0 \uB9DE\uCDB0 \uC791\uC131\uD574\uC918.
1228
- \uCD94\uB860 \uAC15\uB3C4 \uC9C0\uCE68: ${reasoningInstruction}`;
1317
+ const ruleText = ruleSection.items.join(" ") || "(\uC5C6\uC74C)";
1318
+ const diffText = `\uB9AC\uBDF0 \uB300\uC0C1 diff ${toGeminiFileReference(resolvedTempDiffPath)}`;
1319
+ const prompt = [
1320
+ "\uC544\uB798 \uD30C\uC77C\uB4E4\uC744 \uC21C\uC11C\uB300\uB85C \uC77D\uACE0 \uCF54\uB4DC \uB9AC\uBDF0\uB97C \uC9C4\uD589\uD574\uC918.",
1321
+ `\uADDC\uCE59 \uD30C\uC77C: ${ruleText}`,
1322
+ `\uB9AC\uBDF0 \uC591\uC2DD \uD30C\uC77C: ${reviewFormText}`,
1323
+ `\uB9AC\uBDF0 \uB300\uC0C1 diff \uD30C\uC77C: ${diffText}`,
1324
+ "\uBC18\uB4DC\uC2DC \uB9AC\uBDF0 \uC591\uC2DD\uC5D0 \uB9DE\uCDB0 \uC791\uC131\uD574\uC918.",
1325
+ `\uCD94\uB860 \uAC15\uB3C4 \uC9C0\uCE68: ${reasoningInstruction}`
1326
+ ].join(" ");
1229
1327
  trace5("prompt:prepared", `length=${prompt.length}`);
1230
1328
  const modelCandidates = toUnique2(customModel ? [customModel, ...aliasFallbacks] : aliasFallbacks);
1231
1329
  trace5("model:candidates", modelCandidates.join(", "));
@@ -1289,6 +1387,7 @@ function checkGeminiCliInstalled() {
1289
1387
  var execAsync = util.promisify(exec);
1290
1388
  async function main() {
1291
1389
  const args4 = process.argv.slice(2);
1390
+ const startedAt = /* @__PURE__ */ new Date();
1292
1391
  clearTraceMessages();
1293
1392
  const isTest = isTestMode(args4);
1294
1393
  const trace7 = createTraceLogger("review-one-by-one", args4);
@@ -1297,6 +1396,13 @@ async function main() {
1297
1396
  let savedDiffPath = "";
1298
1397
  let savedReportPath = "";
1299
1398
  let selectedCommitSummary = "";
1399
+ let fileList = [];
1400
+ let executionLogPath = "";
1401
+ let executionStatus = "cancelled";
1402
+ 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.";
1403
+ let executionError = null;
1404
+ let exitCode = 0;
1405
+ const fileExecutionLogs = [];
1300
1406
  try {
1301
1407
  trace7("service-selection:start");
1302
1408
  service = await showSelectionAIService();
@@ -1325,22 +1431,24 @@ async function main() {
1325
1431
  trace7("commit-selection:done", `count=${selectedCommits.length}`);
1326
1432
  if (selectedCommits.length === 0) {
1327
1433
  trace7("commit-selection:empty");
1434
+ executionTitle = "\uC120\uD0DD\uB41C \uCEE4\uBC0B\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.";
1328
1435
  console.log("\u2139\uFE0F \uC120\uD0DD\uB41C \uCEE4\uBC0B\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
1329
1436
  deleteTempDiff();
1330
- process.exit(0);
1437
+ return;
1331
1438
  }
1332
1439
  selectedCommitSummary = buildSelectedCommitSummary(selectedCommits);
1333
1440
  trace7("commit-summary:prepared", selectedCommitSummary);
1334
1441
  console.log("\u23F3 \uC120\uD0DD\uD55C \uCEE4\uBC0B\uC758 \uD30C\uC77C \uBAA9\uB85D\uACFC diff\uB97C \uC815\uB9AC\uD558\uB294 \uC911\uC785\uB2C8\uB2E4...");
1335
1442
  trace7("files-command:run");
1336
- const fileList = getSelectedCommitFiles(selectedCommits);
1443
+ fileList = getSelectedCommitFiles(selectedCommits);
1337
1444
  trace7("files-command:done", `fileCount=${fileList.length}`);
1338
1445
  console.log(`\u{1F4C2} \uB9AC\uBDF0 \uB300\uC0C1 \uD30C\uC77C(${fileList.length}\uAC1C): ${formatReviewTargetFiles(fileList)}`);
1339
1446
  if (fileList.length === 0) {
1340
1447
  trace7("empty-file-list:exit");
1448
+ executionTitle = "\uC120\uD0DD\uD55C \uCEE4\uBC0B\uC5D0\uC11C \uB9AC\uBDF0 \uB300\uC0C1 \uD30C\uC77C \uBCC0\uACBD\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.";
1341
1449
  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.");
1342
1450
  deleteTempDiff();
1343
- process.exit(0);
1451
+ return;
1344
1452
  }
1345
1453
  trace7("report-dir:create:start");
1346
1454
  createReportDirectory();
@@ -1370,6 +1478,15 @@ async function main() {
1370
1478
  trace7("file-diff:build:done", `${file} | length=${fileDiff.length}`);
1371
1479
  if (!fileDiff.trim()) {
1372
1480
  trace7("file-diff:empty", file);
1481
+ fileExecutionLogs.push({
1482
+ command: null,
1483
+ errorSummary: null,
1484
+ file,
1485
+ index,
1486
+ resultLength: 0,
1487
+ status: "skipped",
1488
+ tempOneFileDiffPath
1489
+ });
1373
1490
  return;
1374
1491
  }
1375
1492
  trace7("file-temp-diff:write:start", tempOneFileDiffPath);
@@ -1412,9 +1529,27 @@ ${result}
1412
1529
  ${command}`);
1413
1530
  trace7("file-test-command:append:done", file);
1414
1531
  }
1532
+ fileExecutionLogs.push({
1533
+ command,
1534
+ errorSummary: null,
1535
+ file,
1536
+ index,
1537
+ resultLength: result.length,
1538
+ status: "success",
1539
+ tempOneFileDiffPath
1540
+ });
1415
1541
  trace7("file-review:end", file);
1416
1542
  } catch (err) {
1417
1543
  trace7("file-review:catch", `${file} | ${getErrorSummary(err)}`);
1544
+ fileExecutionLogs.push({
1545
+ command: command || null,
1546
+ errorSummary: getErrorSummary(err),
1547
+ file,
1548
+ index,
1549
+ resultLength: 0,
1550
+ status: "failed",
1551
+ tempOneFileDiffPath
1552
+ });
1418
1553
  const errorLogPath = writeErrorReport(err, {
1419
1554
  scope: "review-one-by-one:file",
1420
1555
  args: args4,
@@ -1466,6 +1601,15 @@ ${getErrorSummary(err)}
1466
1601
  trace7("parallel-review:await-start");
1467
1602
  await Promise.all(promises);
1468
1603
  trace7("parallel-review:await-done");
1604
+ const failedFileCount = fileExecutionLogs.filter((log) => log.status === "failed").length;
1605
+ const successfulFileCount = fileExecutionLogs.filter((log) => log.status === "success").length;
1606
+ if (failedFileCount > 0) {
1607
+ executionStatus = "partial_failure";
1608
+ executionTitle = `\uD30C\uC77C\uBCC4 \uB9AC\uBDF0 \uC911 \uC77C\uBD80\uAC00 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. (\uC131\uACF5 ${successfulFileCount}\uAC74 / \uC2E4\uD328 ${failedFileCount}\uAC74)`;
1609
+ } else {
1610
+ executionStatus = "success";
1611
+ executionTitle = "\uD30C\uC77C\uBCC4 \uB9AC\uBDF0\uAC00 \uC131\uACF5\uC801\uC73C\uB85C \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.";
1612
+ }
1469
1613
  console.log(`
1470
1614
  \u2705 \uB9AC\uBDF0\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`);
1471
1615
  console.log(`\u{1F4C4} \uB9AC\uD3EC\uD2B8 \uC800\uC7A5 \uC704\uCE58: ${savedReportPath}`);
@@ -1480,6 +1624,10 @@ ${getErrorSummary(err)}
1480
1624
  } catch (error) {
1481
1625
  trace7("review-flow:catch", getErrorSummary(error));
1482
1626
  let errorReportPath = "";
1627
+ executionStatus = "failed";
1628
+ executionTitle = "\uD30C\uC77C\uBCC4 \uB9AC\uBDF0 \uC2E4\uD589 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.";
1629
+ executionError = error;
1630
+ exitCode = 1;
1483
1631
  trace7("cleanup-temp-diff:start(catch)");
1484
1632
  try {
1485
1633
  deleteTempDiff();
@@ -1517,7 +1665,58 @@ ${JSON.stringify(
1517
1665
  if (errorReportPath) {
1518
1666
  console.error(`\u{1F4C4} \uC5D0\uB7EC \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${errorReportPath}`);
1519
1667
  }
1520
- process.exit(1);
1668
+ } finally {
1669
+ executionLogPath = writeExecutionLog({
1670
+ scope: "review-one-by-one",
1671
+ status: executionStatus,
1672
+ title: executionTitle,
1673
+ args: args4,
1674
+ startedAt,
1675
+ error: executionError,
1676
+ extraSections: [
1677
+ {
1678
+ heading: "Execution Context",
1679
+ markdown: `\`\`\`json
1680
+ ${JSON.stringify(
1681
+ {
1682
+ service: service || null,
1683
+ selectedCommitSummary: selectedCommitSummary || null,
1684
+ fileList,
1685
+ tempDiffPath,
1686
+ savedDiffPath: savedDiffPath || null,
1687
+ savedReportPath: savedReportPath || null
1688
+ },
1689
+ null,
1690
+ 2
1691
+ )}
1692
+ \`\`\``
1693
+ },
1694
+ {
1695
+ heading: "Generated Commands",
1696
+ markdown: `\`\`\`json
1697
+ ${JSON.stringify(
1698
+ fileExecutionLogs.slice().sort((left, right) => left.index - right.index).map((log) => ({
1699
+ file: log.file,
1700
+ status: log.status,
1701
+ resultLength: log.resultLength,
1702
+ errorSummary: log.errorSummary,
1703
+ tempOneFileDiffPath: log.tempOneFileDiffPath,
1704
+ command: log.command
1705
+ })),
1706
+ null,
1707
+ 2
1708
+ )}
1709
+ \`\`\``
1710
+ }
1711
+ ]
1712
+ });
1713
+ if (executionLogPath) {
1714
+ const writeLog = executionStatus === "failed" ? console.error : console.log;
1715
+ writeLog(`\u{1F4DD} \uC2E4\uD589 \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${executionLogPath}`);
1716
+ }
1717
+ }
1718
+ if (exitCode !== 0) {
1719
+ process.exit(exitCode);
1521
1720
  }
1522
1721
  }
1523
1722
  main();