sales-frontend-gemini-cli 0.4.3 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/common/helper.cjs +227 -20
  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 +226 -21
  6. package/dist/common/helper.js.map +1 -1
  7. package/dist/common/types.d.cts +3 -1
  8. package/dist/common/types.d.ts +3 -1
  9. package/dist/pr-review/claude/claude-commander.cjs +10 -3
  10. package/dist/pr-review/claude/claude-commander.cjs.map +1 -1
  11. package/dist/pr-review/claude/claude-commander.js +10 -3
  12. package/dist/pr-review/claude/claude-commander.js.map +1 -1
  13. package/dist/pr-review/claude/installation-claude.cjs +1 -1
  14. package/dist/pr-review/claude/installation-claude.cjs.map +1 -1
  15. package/dist/pr-review/claude/installation-claude.js +1 -1
  16. package/dist/pr-review/claude/installation-claude.js.map +1 -1
  17. package/dist/pr-review/codex/codex-commander.cjs +14 -4
  18. package/dist/pr-review/codex/codex-commander.cjs.map +1 -1
  19. package/dist/pr-review/codex/codex-commander.d.cts +1 -1
  20. package/dist/pr-review/codex/codex-commander.d.ts +1 -1
  21. package/dist/pr-review/codex/codex-commander.js +14 -4
  22. package/dist/pr-review/codex/codex-commander.js.map +1 -1
  23. package/dist/pr-review/codex/installation-codex.cjs +1 -1
  24. package/dist/pr-review/codex/installation-codex.cjs.map +1 -1
  25. package/dist/pr-review/codex/installation-codex.js +1 -1
  26. package/dist/pr-review/codex/installation-codex.js.map +1 -1
  27. package/dist/pr-review/gemini/gemini-commander.cjs +12 -12
  28. package/dist/pr-review/gemini/gemini-commander.cjs.map +1 -1
  29. package/dist/pr-review/gemini/gemini-commander.js +12 -12
  30. package/dist/pr-review/gemini/gemini-commander.js.map +1 -1
  31. package/dist/pr-review/gemini/installation-gemini.cjs +1 -1
  32. package/dist/pr-review/gemini/installation-gemini.cjs.map +1 -1
  33. package/dist/pr-review/gemini/installation-gemini.js +1 -1
  34. package/dist/pr-review/gemini/installation-gemini.js.map +1 -1
  35. package/dist/pr-review/review-one-by-one.cjs +296 -42
  36. package/dist/pr-review/review-one-by-one.cjs.map +1 -1
  37. package/dist/pr-review/review-one-by-one.js +296 -42
  38. package/dist/pr-review/review-one-by-one.js.map +1 -1
  39. package/dist/pr-review/review.cjs +327 -42
  40. package/dist/pr-review/review.cjs.map +1 -1
  41. package/dist/pr-review/review.js +327 -42
  42. package/dist/pr-review/review.js.map +1 -1
  43. 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,
@@ -425,6 +506,62 @@ function truncateCommitSubject(subject) {
425
506
  }
426
507
  return `${subject.slice(0, 69)}...`;
427
508
  }
509
+ function formatReviewTargetFileCount(fileCount) {
510
+ return fileCount === 0 ? "\uBCC0\uACBD \uC5C6\uC74C" : `${fileCount}\uAC1C \uD30C\uC77C`;
511
+ }
512
+ function buildReviewTargetSectionTitle(target) {
513
+ return target.kind === "commit" ? `${target.hash} ${target.subject}` : `${target.hash} | ${target.subject}`;
514
+ }
515
+ function buildReviewTargetSummaryLine(target) {
516
+ if (target.kind === "commit") {
517
+ return `- ${target.hash} | ${target.subject} | ${target.author} | ${target.relativeDate}`;
518
+ }
519
+ return `- ${target.hash} | ${target.subject}`;
520
+ }
521
+ function buildReviewTargetDiffArgs(target, filePath) {
522
+ const reviewPathspecArgs = getReviewPathspecArgs();
523
+ if (target.kind === "commit") {
524
+ return filePath ? ["show", "--stat", "--patch", "--format=", target.hash, "--", filePath] : ["show", "--stat", "--patch", "--format=", target.hash, "--", ...reviewPathspecArgs];
525
+ }
526
+ const diffArgs = ["diff"];
527
+ if (target.kind === "staged") {
528
+ diffArgs.push("--cached");
529
+ }
530
+ diffArgs.push("--stat", "--patch", "--");
531
+ return filePath ? [...diffArgs, filePath] : [...diffArgs, ...reviewPathspecArgs];
532
+ }
533
+ function buildReviewTargetFileArgs(target) {
534
+ const reviewPathspecArgs = getReviewPathspecArgs();
535
+ if (target.kind === "commit") {
536
+ return ["show", "--pretty=format:", "--name-only", target.hash, "--", ...reviewPathspecArgs];
537
+ }
538
+ const diffArgs = ["diff"];
539
+ if (target.kind === "staged") {
540
+ diffArgs.push("--cached");
541
+ }
542
+ return [...diffArgs, "--name-only", "--", ...reviewPathspecArgs];
543
+ }
544
+ function getReviewTargetFiles(target) {
545
+ const output = runGitCommand(buildReviewTargetFileArgs(target), {
546
+ allowFailure: true
547
+ });
548
+ return output.split("\n").map((line) => line.trim()).filter(Boolean);
549
+ }
550
+ function createWorkingTreeReviewOption(kind) {
551
+ const files = getReviewTargetFiles({
552
+ hash: kind,
553
+ kind});
554
+ const subject = kind === "unstaged" ? "\uC544\uC9C1 git add \uD558\uC9C0 \uC54A\uC740 \uBCC0\uACBD\uC0AC\uD56D" : "git add \uB41C \uBCC0\uACBD\uC0AC\uD56D";
555
+ return {
556
+ author: "",
557
+ description: `${subject} | ${formatReviewTargetFileCount(files.length)}`,
558
+ hash: kind,
559
+ kind,
560
+ label: kind,
561
+ relativeDate: "",
562
+ subject
563
+ };
564
+ }
428
565
  function getRecentCommitOptions() {
429
566
  const output = runGitCommand(
430
567
  ["log", `-${COMMIT_FETCH_LIMIT}`, "--date=relative", "--pretty=format:%h%x09%an%x09%ar%x09%s"],
@@ -440,62 +577,61 @@ function getRecentCommitOptions() {
440
577
  author,
441
578
  description: `${author} | ${relativeDate}`,
442
579
  hash,
580
+ kind: "commit",
443
581
  label: `${hash} | ${truncateCommitSubject(subject)}`,
444
582
  relativeDate,
445
583
  subject
446
584
  };
447
585
  });
448
586
  }
587
+ function getReviewTargetOptions() {
588
+ return [createWorkingTreeReviewOption("unstaged"), createWorkingTreeReviewOption("staged"), ...getRecentCommitOptions()];
589
+ }
449
590
  function buildSelectedCommitSummary(commits) {
450
- return commits.map((commit) => `- ${commit.hash} | ${commit.subject} | ${commit.author} | ${commit.relativeDate}`).join("\n");
591
+ return commits.map((commit) => buildReviewTargetSummaryLine(commit)).join("\n");
451
592
  }
452
593
  function getReviewPathspecArgs() {
453
594
  const { includePatterns, excludePatterns } = getGitDiffPathspecs();
454
595
  return [...includePatterns, ...excludePatterns];
455
596
  }
456
597
  function buildSelectedCommitDiff(commits) {
457
- const reviewPathspecArgs = getReviewPathspecArgs();
458
598
  const sections = commits.map((commit) => {
459
- const diff = runGitCommand(["show", "--stat", "--patch", "--format=", commit.hash, "--", ...reviewPathspecArgs], {
599
+ const diff = runGitCommand(buildReviewTargetDiffArgs(commit), {
460
600
  allowFailure: true,
461
601
  trimOutput: false
462
602
  }).trim();
463
603
  if (!diff) {
464
604
  return "";
465
605
  }
466
- return [`## ${commit.hash} ${commit.subject}`, diff].join("\n\n");
606
+ return [`## ${buildReviewTargetSectionTitle(commit)}`, diff].join("\n\n");
467
607
  }).filter(Boolean).join("\n\n");
468
608
  if (!sections) {
469
609
  return "";
470
610
  }
471
- return ["# \uC120\uD0DD\uD55C \uCEE4\uBC0B", buildSelectedCommitSummary(commits), "", "# \uB9AC\uBDF0 \uB300\uC0C1 diff", sections].join("\n");
611
+ return ["# \uC120\uD0DD\uD55C \uB9AC\uBDF0 \uB300\uC0C1", buildSelectedCommitSummary(commits), "", "# \uB9AC\uBDF0 \uB300\uC0C1 diff", sections].join("\n");
472
612
  }
473
613
  function getSelectedCommitFiles(commits) {
474
- const reviewPathspecArgs = getReviewPathspecArgs();
475
614
  const files = /* @__PURE__ */ new Set();
476
615
  commits.forEach((commit) => {
477
- const output = runGitCommand(["show", "--pretty=format:", "--name-only", commit.hash, "--", ...reviewPathspecArgs], {
478
- allowFailure: true
479
- });
480
- output.split("\n").map((line) => line.trim()).filter(Boolean).forEach((filePath) => files.add(filePath));
616
+ getReviewTargetFiles(commit).forEach((filePath) => files.add(filePath));
481
617
  });
482
618
  return [...files];
483
619
  }
484
620
  function buildSelectedFileDiff(commits, filePath) {
485
621
  const sections = commits.map((commit) => {
486
- const diff = runGitCommand(["show", "--stat", "--patch", "--format=", commit.hash, "--", filePath], {
622
+ const diff = runGitCommand(buildReviewTargetDiffArgs(commit, filePath), {
487
623
  allowFailure: true,
488
624
  trimOutput: false
489
625
  }).trim();
490
626
  if (!diff) {
491
627
  return "";
492
628
  }
493
- return [`## ${commit.hash} ${commit.subject}`, diff].join("\n\n");
629
+ return [`## ${buildReviewTargetSectionTitle(commit)}`, diff].join("\n\n");
494
630
  }).filter(Boolean).join("\n\n");
495
631
  if (!sections) {
496
632
  return "";
497
633
  }
498
- return ["# \uC120\uD0DD\uD55C \uCEE4\uBC0B", buildSelectedCommitSummary(commits), "", `# \uD30C\uC77C: ${filePath}`, sections].join("\n\n");
634
+ return ["# \uC120\uD0DD\uD55C \uB9AC\uBDF0 \uB300\uC0C1", buildSelectedCommitSummary(commits), "", `# \uD30C\uC77C: ${filePath}`, sections].join("\n\n");
499
635
  }
500
636
  function openReport(reportPath) {
501
637
  const resolvedPath = path.resolve(reportPath);
@@ -681,13 +817,13 @@ async function showMultiSelect(question, options, windowSize = COMMIT_SELECTION_
681
817
  });
682
818
  }
683
819
  async function selectReviewCommits() {
684
- const commits = getRecentCommitOptions();
820
+ const commits = getReviewTargetOptions();
685
821
  if (commits.length === 0) {
686
- console.log("\u2139\uFE0F \uB9AC\uBDF0\uD560 \uCD5C\uADFC \uCEE4\uBC0B\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
822
+ console.log("\u2139\uFE0F \uB9AC\uBDF0\uD560 \uB300\uC0C1\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
687
823
  return [];
688
824
  }
689
825
  return showMultiSelect(
690
- "\uB9AC\uBDF0\uD560 \uCEE4\uBC0B\uC744 \uC120\uD0DD\uD574\uC8FC\uC138\uC694.",
826
+ "\uB9AC\uBDF0\uD560 \uB300\uC0C1\uC744 \uC120\uD0DD\uD574\uC8FC\uC138\uC694.",
691
827
  commits.map((commit) => ({
692
828
  description: commit.description,
693
829
  label: commit.label,
@@ -778,6 +914,13 @@ var ALLOWED_REASONING_EFFORTS = ["minimal", "low", "medium", "high"];
778
914
  function shellQuote(value) {
779
915
  return `'${value.replace(/'/g, `'\\''`)}'`;
780
916
  }
917
+ function toShellOptionToken(value) {
918
+ const SIMPLE_SHELL_TOKEN_PATTERN = /^[A-Za-z0-9._:/=-]+$/;
919
+ if (SIMPLE_SHELL_TOKEN_PATTERN.test(value)) {
920
+ return value;
921
+ }
922
+ return shellQuote(value);
923
+ }
781
924
  function getArgValue(flag) {
782
925
  const index = args.indexOf(flag);
783
926
  if (index === -1 || !args[index + 1]) {
@@ -857,9 +1000,9 @@ function getAliasFallbacks(primaryAlias) {
857
1000
  }
858
1001
  function buildClaudeExecCommand(options) {
859
1002
  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)}`;
1003
+ const modelOption = model ? `--model ${toShellOptionToken(model)}` : "";
1004
+ const fallbackOption = model && fallbackModel ? `--fallback-model ${toShellOptionToken(fallbackModel)}` : "";
1005
+ const effortOption = `--effort ${toShellOptionToken(effort)}`;
863
1006
  const appendedPromptFiles = systemPromptFiles.map((path3) => `--append-system-prompt-file ${shellQuote(path3)}`).join(" ");
864
1007
  return `cat ${shellQuote(tempDiffPath2)} | claude ${[
865
1008
  modelOption,
@@ -984,12 +1127,22 @@ function printNotice2(message) {
984
1127
  console.warn(message);
985
1128
  }
986
1129
  }
1130
+ function normalizeEffort2(level) {
1131
+ if (level === "minimal") {
1132
+ return "low";
1133
+ }
1134
+ return level;
1135
+ }
987
1136
  function resolveReasoningEffort2() {
988
1137
  const customReasoningEffort = getArgValue2("--reasoning-effort");
989
1138
  if (customReasoningEffort) {
990
1139
  if (ALLOWED_REASONING_EFFORTS2.includes(customReasoningEffort)) {
991
- trace3("reasoning:custom", customReasoningEffort);
992
- return customReasoningEffort;
1140
+ const normalized = normalizeEffort2(customReasoningEffort);
1141
+ trace3("reasoning:custom", `${customReasoningEffort} -> ${normalized}`);
1142
+ if (customReasoningEffort === "minimal") {
1143
+ 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.");
1144
+ }
1145
+ return normalized;
993
1146
  }
994
1147
  printNotice2(
995
1148
  `\u26A0\uFE0F \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 reasoning effort(${customReasoningEffort})\uC785\uB2C8\uB2E4. allowed: ${ALLOWED_REASONING_EFFORTS2.join(
@@ -998,8 +1151,8 @@ function resolveReasoningEffort2() {
998
1151
  );
999
1152
  }
1000
1153
  if (args2.includes("--flash")) {
1001
- trace3("reasoning:flash-default", "minimal");
1002
- return "minimal";
1154
+ trace3("reasoning:flash-default", "low");
1155
+ return "low";
1003
1156
  }
1004
1157
  if (args2.includes("--review")) {
1005
1158
  trace3("reasoning:review-default", "high");
@@ -1194,7 +1347,7 @@ function buildGeminiFileReferenceSection(files) {
1194
1347
  const existingFiles = files.filter((file) => fs.existsSync(file.path));
1195
1348
  return {
1196
1349
  count: existingFiles.length,
1197
- lines: existingFiles.map((file) => `- ${file.display}: ${toGeminiFileReference(file.path)}`)
1350
+ items: existingFiles.map((file) => `${file.display} ${toGeminiFileReference(file.path)}`)
1198
1351
  };
1199
1352
  }
1200
1353
  var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
@@ -1213,19 +1366,19 @@ var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
1213
1366
  const ruleSection = buildGeminiFileReferenceSection(rules);
1214
1367
  trace5("rules:loaded", `count=${ruleSection.count}`);
1215
1368
  const reviewFormExists = fs.existsSync(resolvedReviewFormPath);
1216
- const reviewFormLine = reviewFormExists ? `- \uB9AC\uBDF0 \uC591\uC2DD: ${toGeminiFileReference(resolvedReviewFormPath)}` : "- \uB9AC\uBDF0 \uC591\uC2DD: (\uC5C6\uC74C)";
1369
+ const reviewFormText = reviewFormExists ? `\uB9AC\uBDF0 \uC591\uC2DD ${toGeminiFileReference(resolvedReviewFormPath)}` : "\uB9AC\uBDF0 \uC591\uC2DD (\uC5C6\uC74C)";
1217
1370
  trace5("reviewForm:status", reviewFormExists ? "exists" : "missing");
1218
1371
  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}`;
1372
+ const ruleText = ruleSection.items.join(" ") || "(\uC5C6\uC74C)";
1373
+ const diffText = `\uB9AC\uBDF0 \uB300\uC0C1 diff ${toGeminiFileReference(resolvedTempDiffPath)}`;
1374
+ const prompt = [
1375
+ "\uC544\uB798 \uD30C\uC77C\uB4E4\uC744 \uC21C\uC11C\uB300\uB85C \uC77D\uACE0 \uCF54\uB4DC \uB9AC\uBDF0\uB97C \uC9C4\uD589\uD574\uC918.",
1376
+ `\uADDC\uCE59 \uD30C\uC77C: ${ruleText}`,
1377
+ `\uB9AC\uBDF0 \uC591\uC2DD \uD30C\uC77C: ${reviewFormText}`,
1378
+ `\uB9AC\uBDF0 \uB300\uC0C1 diff \uD30C\uC77C: ${diffText}`,
1379
+ "\uBC18\uB4DC\uC2DC \uB9AC\uBDF0 \uC591\uC2DD\uC5D0 \uB9DE\uCDB0 \uC791\uC131\uD574\uC918.",
1380
+ `\uCD94\uB860 \uAC15\uB3C4 \uC9C0\uCE68: ${reasoningInstruction}`
1381
+ ].join(" ");
1229
1382
  trace5("prompt:prepared", `length=${prompt.length}`);
1230
1383
  const modelCandidates = toUnique2(customModel ? [customModel, ...aliasFallbacks] : aliasFallbacks);
1231
1384
  trace5("model:candidates", modelCandidates.join(", "));
@@ -1289,6 +1442,7 @@ function checkGeminiCliInstalled() {
1289
1442
  var execAsync = util.promisify(exec);
1290
1443
  async function main() {
1291
1444
  const args4 = process.argv.slice(2);
1445
+ const startedAt = /* @__PURE__ */ new Date();
1292
1446
  clearTraceMessages();
1293
1447
  const isTest = isTestMode(args4);
1294
1448
  const trace7 = createTraceLogger("review-one-by-one", args4);
@@ -1297,6 +1451,13 @@ async function main() {
1297
1451
  let savedDiffPath = "";
1298
1452
  let savedReportPath = "";
1299
1453
  let selectedCommitSummary = "";
1454
+ let fileList = [];
1455
+ let executionLogPath = "";
1456
+ let executionStatus = "cancelled";
1457
+ 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.";
1458
+ let executionError = null;
1459
+ let exitCode = 0;
1460
+ const fileExecutionLogs = [];
1300
1461
  try {
1301
1462
  trace7("service-selection:start");
1302
1463
  service = await showSelectionAIService();
@@ -1325,22 +1486,24 @@ async function main() {
1325
1486
  trace7("commit-selection:done", `count=${selectedCommits.length}`);
1326
1487
  if (selectedCommits.length === 0) {
1327
1488
  trace7("commit-selection:empty");
1328
- console.log("\u2139\uFE0F \uC120\uD0DD\uB41C \uCEE4\uBC0B\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
1489
+ executionTitle = "\uC120\uD0DD\uB41C \uB9AC\uBDF0 \uB300\uC0C1\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.";
1490
+ console.log("\u2139\uFE0F \uC120\uD0DD\uB41C \uB9AC\uBDF0 \uB300\uC0C1\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
1329
1491
  deleteTempDiff();
1330
- process.exit(0);
1492
+ return;
1331
1493
  }
1332
1494
  selectedCommitSummary = buildSelectedCommitSummary(selectedCommits);
1333
1495
  trace7("commit-summary:prepared", selectedCommitSummary);
1334
1496
  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
1497
  trace7("files-command:run");
1336
- const fileList = getSelectedCommitFiles(selectedCommits);
1498
+ fileList = getSelectedCommitFiles(selectedCommits);
1337
1499
  trace7("files-command:done", `fileCount=${fileList.length}`);
1338
1500
  console.log(`\u{1F4C2} \uB9AC\uBDF0 \uB300\uC0C1 \uD30C\uC77C(${fileList.length}\uAC1C): ${formatReviewTargetFiles(fileList)}`);
1339
1501
  if (fileList.length === 0) {
1340
1502
  trace7("empty-file-list:exit");
1341
- 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.");
1503
+ executionTitle = "\uC120\uD0DD\uD55C \uB9AC\uBDF0 \uB300\uC0C1\uC5D0\uC11C \uB9AC\uBDF0\uD560 \uBCC0\uACBD\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.";
1504
+ console.log("\u2139\uFE0F \uC120\uD0DD\uD55C \uB9AC\uBDF0 \uB300\uC0C1\uC5D0\uC11C \uB9AC\uBDF0\uD560 \uBCC0\uACBD\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.");
1342
1505
  deleteTempDiff();
1343
- process.exit(0);
1506
+ return;
1344
1507
  }
1345
1508
  trace7("report-dir:create:start");
1346
1509
  createReportDirectory();
@@ -1370,6 +1533,15 @@ async function main() {
1370
1533
  trace7("file-diff:build:done", `${file} | length=${fileDiff.length}`);
1371
1534
  if (!fileDiff.trim()) {
1372
1535
  trace7("file-diff:empty", file);
1536
+ fileExecutionLogs.push({
1537
+ command: null,
1538
+ errorSummary: null,
1539
+ file,
1540
+ index,
1541
+ resultLength: 0,
1542
+ status: "skipped",
1543
+ tempOneFileDiffPath
1544
+ });
1373
1545
  return;
1374
1546
  }
1375
1547
  trace7("file-temp-diff:write:start", tempOneFileDiffPath);
@@ -1412,9 +1584,27 @@ ${result}
1412
1584
  ${command}`);
1413
1585
  trace7("file-test-command:append:done", file);
1414
1586
  }
1587
+ fileExecutionLogs.push({
1588
+ command,
1589
+ errorSummary: null,
1590
+ file,
1591
+ index,
1592
+ resultLength: result.length,
1593
+ status: "success",
1594
+ tempOneFileDiffPath
1595
+ });
1415
1596
  trace7("file-review:end", file);
1416
1597
  } catch (err) {
1417
1598
  trace7("file-review:catch", `${file} | ${getErrorSummary(err)}`);
1599
+ fileExecutionLogs.push({
1600
+ command: command || null,
1601
+ errorSummary: getErrorSummary(err),
1602
+ file,
1603
+ index,
1604
+ resultLength: 0,
1605
+ status: "failed",
1606
+ tempOneFileDiffPath
1607
+ });
1418
1608
  const errorLogPath = writeErrorReport(err, {
1419
1609
  scope: "review-one-by-one:file",
1420
1610
  args: args4,
@@ -1466,6 +1656,15 @@ ${getErrorSummary(err)}
1466
1656
  trace7("parallel-review:await-start");
1467
1657
  await Promise.all(promises);
1468
1658
  trace7("parallel-review:await-done");
1659
+ const failedFileCount = fileExecutionLogs.filter((log) => log.status === "failed").length;
1660
+ const successfulFileCount = fileExecutionLogs.filter((log) => log.status === "success").length;
1661
+ if (failedFileCount > 0) {
1662
+ executionStatus = "partial_failure";
1663
+ executionTitle = `\uD30C\uC77C\uBCC4 \uB9AC\uBDF0 \uC911 \uC77C\uBD80\uAC00 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. (\uC131\uACF5 ${successfulFileCount}\uAC74 / \uC2E4\uD328 ${failedFileCount}\uAC74)`;
1664
+ } else {
1665
+ executionStatus = "success";
1666
+ executionTitle = "\uD30C\uC77C\uBCC4 \uB9AC\uBDF0\uAC00 \uC131\uACF5\uC801\uC73C\uB85C \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.";
1667
+ }
1469
1668
  console.log(`
1470
1669
  \u2705 \uB9AC\uBDF0\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`);
1471
1670
  console.log(`\u{1F4C4} \uB9AC\uD3EC\uD2B8 \uC800\uC7A5 \uC704\uCE58: ${savedReportPath}`);
@@ -1480,6 +1679,10 @@ ${getErrorSummary(err)}
1480
1679
  } catch (error) {
1481
1680
  trace7("review-flow:catch", getErrorSummary(error));
1482
1681
  let errorReportPath = "";
1682
+ executionStatus = "failed";
1683
+ executionTitle = "\uD30C\uC77C\uBCC4 \uB9AC\uBDF0 \uC2E4\uD589 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.";
1684
+ executionError = error;
1685
+ exitCode = 1;
1483
1686
  trace7("cleanup-temp-diff:start(catch)");
1484
1687
  try {
1485
1688
  deleteTempDiff();
@@ -1517,7 +1720,58 @@ ${JSON.stringify(
1517
1720
  if (errorReportPath) {
1518
1721
  console.error(`\u{1F4C4} \uC5D0\uB7EC \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${errorReportPath}`);
1519
1722
  }
1520
- process.exit(1);
1723
+ } finally {
1724
+ executionLogPath = writeExecutionLog({
1725
+ scope: "review-one-by-one",
1726
+ status: executionStatus,
1727
+ title: executionTitle,
1728
+ args: args4,
1729
+ startedAt,
1730
+ error: executionError,
1731
+ extraSections: [
1732
+ {
1733
+ heading: "Execution Context",
1734
+ markdown: `\`\`\`json
1735
+ ${JSON.stringify(
1736
+ {
1737
+ service: service || null,
1738
+ selectedCommitSummary: selectedCommitSummary || null,
1739
+ fileList,
1740
+ tempDiffPath,
1741
+ savedDiffPath: savedDiffPath || null,
1742
+ savedReportPath: savedReportPath || null
1743
+ },
1744
+ null,
1745
+ 2
1746
+ )}
1747
+ \`\`\``
1748
+ },
1749
+ {
1750
+ heading: "Generated Commands",
1751
+ markdown: `\`\`\`json
1752
+ ${JSON.stringify(
1753
+ fileExecutionLogs.slice().sort((left, right) => left.index - right.index).map((log) => ({
1754
+ file: log.file,
1755
+ status: log.status,
1756
+ resultLength: log.resultLength,
1757
+ errorSummary: log.errorSummary,
1758
+ tempOneFileDiffPath: log.tempOneFileDiffPath,
1759
+ command: log.command
1760
+ })),
1761
+ null,
1762
+ 2
1763
+ )}
1764
+ \`\`\``
1765
+ }
1766
+ ]
1767
+ });
1768
+ if (executionLogPath) {
1769
+ const writeLog = executionStatus === "failed" ? console.error : console.log;
1770
+ writeLog(`\u{1F4DD} \uC2E4\uD589 \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${executionLogPath}`);
1771
+ }
1772
+ }
1773
+ if (exitCode !== 0) {
1774
+ process.exit(exitCode);
1521
1775
  }
1522
1776
  }
1523
1777
  main();