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.
- package/dist/common/helper.cjs +227 -20
- package/dist/common/helper.cjs.map +1 -1
- package/dist/common/helper.d.cts +30 -1
- package/dist/common/helper.d.ts +30 -1
- package/dist/common/helper.js +226 -21
- package/dist/common/helper.js.map +1 -1
- package/dist/common/types.d.cts +3 -1
- package/dist/common/types.d.ts +3 -1
- package/dist/pr-review/claude/claude-commander.cjs +10 -3
- package/dist/pr-review/claude/claude-commander.cjs.map +1 -1
- package/dist/pr-review/claude/claude-commander.js +10 -3
- package/dist/pr-review/claude/claude-commander.js.map +1 -1
- package/dist/pr-review/claude/installation-claude.cjs +1 -1
- package/dist/pr-review/claude/installation-claude.cjs.map +1 -1
- package/dist/pr-review/claude/installation-claude.js +1 -1
- package/dist/pr-review/claude/installation-claude.js.map +1 -1
- package/dist/pr-review/codex/codex-commander.cjs +14 -4
- package/dist/pr-review/codex/codex-commander.cjs.map +1 -1
- package/dist/pr-review/codex/codex-commander.d.cts +1 -1
- package/dist/pr-review/codex/codex-commander.d.ts +1 -1
- package/dist/pr-review/codex/codex-commander.js +14 -4
- package/dist/pr-review/codex/codex-commander.js.map +1 -1
- package/dist/pr-review/codex/installation-codex.cjs +1 -1
- package/dist/pr-review/codex/installation-codex.cjs.map +1 -1
- package/dist/pr-review/codex/installation-codex.js +1 -1
- package/dist/pr-review/codex/installation-codex.js.map +1 -1
- package/dist/pr-review/gemini/gemini-commander.cjs +12 -12
- package/dist/pr-review/gemini/gemini-commander.cjs.map +1 -1
- package/dist/pr-review/gemini/gemini-commander.js +12 -12
- package/dist/pr-review/gemini/gemini-commander.js.map +1 -1
- package/dist/pr-review/gemini/installation-gemini.cjs +1 -1
- package/dist/pr-review/gemini/installation-gemini.cjs.map +1 -1
- package/dist/pr-review/gemini/installation-gemini.js +1 -1
- package/dist/pr-review/gemini/installation-gemini.js.map +1 -1
- package/dist/pr-review/review-one-by-one.cjs +296 -42
- package/dist/pr-review/review-one-by-one.cjs.map +1 -1
- package/dist/pr-review/review-one-by-one.js +296 -42
- package/dist/pr-review/review-one-by-one.js.map +1 -1
- package/dist/pr-review/review.cjs +327 -42
- package/dist/pr-review/review.cjs.map +1 -1
- package/dist/pr-review/review.js +327 -42
- package/dist/pr-review/review.js.map +1 -1
- package/package.json +1 -1
package/dist/pr-review/review.js
CHANGED
|
@@ -71,6 +71,9 @@ var ignoreList = [
|
|
|
71
71
|
function isTestMode(args4 = process.argv.slice(2)) {
|
|
72
72
|
return args4.includes("--test");
|
|
73
73
|
}
|
|
74
|
+
function shouldStreamAIOutput(args4 = process.argv.slice(2)) {
|
|
75
|
+
return args4.includes("--stream-output");
|
|
76
|
+
}
|
|
74
77
|
function clearTraceMessages() {
|
|
75
78
|
traceMessages.length = 0;
|
|
76
79
|
}
|
|
@@ -197,15 +200,51 @@ function runGitCommand(args4, options = {}) {
|
|
|
197
200
|
throw error;
|
|
198
201
|
}
|
|
199
202
|
}
|
|
203
|
+
function resolveShellLaunchConfig() {
|
|
204
|
+
const candidates = [];
|
|
205
|
+
const seen = /* @__PURE__ */ new Set();
|
|
206
|
+
const appendCandidate = (executable, shellArgs) => {
|
|
207
|
+
const normalizedExecutable = executable?.trim();
|
|
208
|
+
if (!normalizedExecutable) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
if (path.isAbsolute(normalizedExecutable) && !fs.existsSync(normalizedExecutable)) {
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
const key = `${normalizedExecutable}::${shellArgs.join("\0")}`;
|
|
215
|
+
if (seen.has(key)) {
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
seen.add(key);
|
|
219
|
+
candidates.push({
|
|
220
|
+
executable: normalizedExecutable,
|
|
221
|
+
shellArgs
|
|
222
|
+
});
|
|
223
|
+
};
|
|
224
|
+
const shellFromEnv = process.env.SHELL?.trim();
|
|
225
|
+
const envShellName = shellFromEnv ? path.basename(shellFromEnv) : "";
|
|
226
|
+
if (["bash", "zsh", "ksh"].includes(envShellName)) {
|
|
227
|
+
appendCandidate(shellFromEnv, ["-lc"]);
|
|
228
|
+
}
|
|
229
|
+
["/bin/bash", "/usr/bin/bash", "bash", "/bin/zsh", "/usr/bin/zsh", "zsh"].forEach((shellPath) => {
|
|
230
|
+
appendCandidate(shellPath, ["-lc"]);
|
|
231
|
+
});
|
|
232
|
+
["/bin/sh", "/usr/bin/sh", "sh"].forEach((shellPath) => {
|
|
233
|
+
appendCandidate(shellPath, ["-c"]);
|
|
234
|
+
});
|
|
235
|
+
return candidates[0] || { executable: "sh", shellArgs: ["-c"] };
|
|
236
|
+
}
|
|
200
237
|
async function executeShellCommandWithProgress(command, options = {}) {
|
|
201
238
|
const { progressIntervalMs = 1e4, progressMessage = "\u23F3 \uBA85\uB839\uC744 \uC2E4\uD589\uD558\uB294 \uC911\uC785\uB2C8\uB2E4...", streamOutput = false } = options;
|
|
202
239
|
const { spawn } = await import('child_process');
|
|
240
|
+
const shellLaunchConfig = resolveShellLaunchConfig();
|
|
203
241
|
return new Promise((resolve, reject) => {
|
|
204
242
|
let stdout = "";
|
|
205
243
|
let stderr = "";
|
|
206
244
|
const startedAt = Date.now();
|
|
207
245
|
console.log(progressMessage);
|
|
208
|
-
|
|
246
|
+
helperTrace("shell-command:launcher", `${shellLaunchConfig.executable} ${shellLaunchConfig.shellArgs.join(" ")}`);
|
|
247
|
+
const child = spawn(shellLaunchConfig.executable, [...shellLaunchConfig.shellArgs, command], {
|
|
209
248
|
stdio: ["ignore", "pipe", "pipe"]
|
|
210
249
|
});
|
|
211
250
|
const progressTimer = setInterval(() => {
|
|
@@ -240,11 +279,41 @@ async function executeShellCommandWithProgress(command, options = {}) {
|
|
|
240
279
|
return;
|
|
241
280
|
}
|
|
242
281
|
const exitSummary = signal ? `signal=${signal}` : `code=${String(code ?? "unknown")}`;
|
|
243
|
-
|
|
244
|
-
|
|
282
|
+
const failureDetails = {
|
|
283
|
+
code,
|
|
284
|
+
command,
|
|
285
|
+
signal,
|
|
286
|
+
stderr,
|
|
287
|
+
stdout
|
|
288
|
+
};
|
|
289
|
+
reject(createShellCommandExecutionError(failureDetails, exitSummary));
|
|
245
290
|
});
|
|
246
291
|
});
|
|
247
292
|
}
|
|
293
|
+
function getShellCommandFailurePreview(failureDetails) {
|
|
294
|
+
const stderrText = failureDetails.stderr.trim();
|
|
295
|
+
const stdoutText = failureDetails.stdout.trim();
|
|
296
|
+
const combinedOutput = stderrText || stdoutText;
|
|
297
|
+
if (!combinedOutput) {
|
|
298
|
+
return "";
|
|
299
|
+
}
|
|
300
|
+
const MAX_PREVIEW_LENGTH = 4e3;
|
|
301
|
+
if (combinedOutput.length <= MAX_PREVIEW_LENGTH) {
|
|
302
|
+
return combinedOutput;
|
|
303
|
+
}
|
|
304
|
+
return combinedOutput.slice(-4e3);
|
|
305
|
+
}
|
|
306
|
+
function createShellCommandExecutionError(failureDetails, exitSummary) {
|
|
307
|
+
const failurePreview = getShellCommandFailurePreview(failureDetails);
|
|
308
|
+
const error = new Error(`\uC258 \uBA85\uB839 \uC2E4\uD589 \uC2E4\uD328 (${exitSummary})${failurePreview ? `
|
|
309
|
+
${failurePreview}` : ""}`);
|
|
310
|
+
error.code = failureDetails.code;
|
|
311
|
+
error.signal = failureDetails.signal;
|
|
312
|
+
error.stdout = failureDetails.stdout;
|
|
313
|
+
error.stderr = failureDetails.stderr;
|
|
314
|
+
error.command = failureDetails.command;
|
|
315
|
+
return error;
|
|
316
|
+
}
|
|
248
317
|
function formatReviewTargetFiles(files, visibleCount = 5) {
|
|
249
318
|
if (files.length === 0) {
|
|
250
319
|
return "(\uC5C6\uC74C)";
|
|
@@ -317,7 +386,7 @@ function serializeError(error) {
|
|
|
317
386
|
}
|
|
318
387
|
if (error && typeof error === "object") {
|
|
319
388
|
const errorLike = error;
|
|
320
|
-
const extraKeys = ["code", "errno", "syscall", "path", "cmd", "status", "signal", "spawnargs"];
|
|
389
|
+
const extraKeys = ["code", "errno", "syscall", "path", "cmd", "status", "signal", "spawnargs", "command"];
|
|
321
390
|
extraKeys.forEach((key) => {
|
|
322
391
|
if (errorLike[key] !== void 0) {
|
|
323
392
|
serialized[key] = errorLike[key];
|
|
@@ -423,6 +492,87 @@ ${section.markdown}`).join("\n")}
|
|
|
423
492
|
return "";
|
|
424
493
|
}
|
|
425
494
|
}
|
|
495
|
+
function getExecutionLogSummary(status, title) {
|
|
496
|
+
if (title) {
|
|
497
|
+
return title;
|
|
498
|
+
}
|
|
499
|
+
switch (status) {
|
|
500
|
+
case "success":
|
|
501
|
+
return "\uB9AC\uBDF0 \uC2E4\uD589\uC774 \uC131\uACF5\uC801\uC73C\uB85C \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.";
|
|
502
|
+
case "failed":
|
|
503
|
+
return "\uB9AC\uBDF0 \uC2E4\uD589 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.";
|
|
504
|
+
case "partial_failure":
|
|
505
|
+
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.";
|
|
506
|
+
default:
|
|
507
|
+
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.";
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
function formatExecutionDuration(startedAt, finishedAt) {
|
|
511
|
+
const durationMs = Math.max(0, finishedAt.getTime() - startedAt.getTime());
|
|
512
|
+
if (durationMs < 1e3) {
|
|
513
|
+
return `${durationMs}ms`;
|
|
514
|
+
}
|
|
515
|
+
const durationSeconds = durationMs / 1e3;
|
|
516
|
+
if (durationSeconds < 60) {
|
|
517
|
+
return `${durationSeconds.toFixed(1)}s`;
|
|
518
|
+
}
|
|
519
|
+
const minutes = Math.floor(durationSeconds / 60);
|
|
520
|
+
const seconds = Math.round(durationSeconds % 60);
|
|
521
|
+
return `${minutes}m ${seconds}s`;
|
|
522
|
+
}
|
|
523
|
+
function writeExecutionLog(options = {}) {
|
|
524
|
+
try {
|
|
525
|
+
const startedAt = options.startedAt ?? /* @__PURE__ */ new Date();
|
|
526
|
+
const finishedAt = options.finishedAt ?? /* @__PURE__ */ new Date();
|
|
527
|
+
const status = options.status ?? "success";
|
|
528
|
+
helperTrace("execution-log:write:start", options.scope || "unknown");
|
|
529
|
+
createReportDirectory();
|
|
530
|
+
const reportPath = getAvailableFilePath(REPORT_DIR, `${getNowString(finishedAt)}-execution-log`, ".md");
|
|
531
|
+
const traceSnapshot = options.traceMessages ?? getTraceMessages();
|
|
532
|
+
const extraSections = options.extraSections || [];
|
|
533
|
+
const serializedError = options.error ? serializeError(options.error) : null;
|
|
534
|
+
const report = `# Execution Log
|
|
535
|
+
|
|
536
|
+
- \uC2DC\uC791 \uC2DC\uAC01: ${getHumanReadableNowString(startedAt)}
|
|
537
|
+
- \uC885\uB8CC \uC2DC\uAC01: ${getHumanReadableNowString(finishedAt)}
|
|
538
|
+
- \uC2E4\uD589 \uC2DC\uAC04: ${formatExecutionDuration(startedAt, finishedAt)}
|
|
539
|
+
- \uC0C1\uD0DC: \`${status}\`
|
|
540
|
+
- Scope: \`${options.scope || "unknown"}\`
|
|
541
|
+
- \uC791\uC5C5 \uACBD\uB85C: \`${process.cwd()}\`
|
|
542
|
+
- \uC2E4\uD589 \uC778\uC790: \`${JSON.stringify(options.args ?? process.argv.slice(2))}\`
|
|
543
|
+
- \uC2E4\uD589 \uD658\uACBD: \`${process.platform} ${process.arch} / Node ${process.version}\`
|
|
544
|
+
|
|
545
|
+
## Summary
|
|
546
|
+
|
|
547
|
+
${getExecutionLogSummary(status, options.title)}
|
|
548
|
+
${serializedError ? `
|
|
549
|
+
|
|
550
|
+
## Error
|
|
551
|
+
|
|
552
|
+
\`\`\`json
|
|
553
|
+
${JSON.stringify(serializedError, null, 2)}
|
|
554
|
+
\`\`\`` : ""}
|
|
555
|
+
|
|
556
|
+
## Trace
|
|
557
|
+
|
|
558
|
+
\`\`\`json
|
|
559
|
+
${JSON.stringify(traceSnapshot, null, 2)}
|
|
560
|
+
\`\`\`${extraSections.length ? `
|
|
561
|
+
${extraSections.map((section) => `
|
|
562
|
+
## ${section.heading}
|
|
563
|
+
|
|
564
|
+
${section.markdown}`).join("\n")}
|
|
565
|
+
` : "\n"}
|
|
566
|
+
`;
|
|
567
|
+
fs.writeFileSync(reportPath, report);
|
|
568
|
+
helperTrace("execution-log:write:done", reportPath);
|
|
569
|
+
return reportPath;
|
|
570
|
+
} catch (writeError) {
|
|
571
|
+
console.error("\u26A0\uFE0F \uC2E4\uD589 \uB85C\uADF8 \uD30C\uC77C \uC0DD\uC131\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
|
|
572
|
+
console.error(writeError);
|
|
573
|
+
return "";
|
|
574
|
+
}
|
|
575
|
+
}
|
|
426
576
|
function exitWithError(message, options = {}) {
|
|
427
577
|
const reportPath = writeErrorReport(options.error || new Error(message), {
|
|
428
578
|
...options,
|
|
@@ -473,6 +623,62 @@ function truncateCommitSubject(subject) {
|
|
|
473
623
|
}
|
|
474
624
|
return `${subject.slice(0, 69)}...`;
|
|
475
625
|
}
|
|
626
|
+
function formatReviewTargetFileCount(fileCount) {
|
|
627
|
+
return fileCount === 0 ? "\uBCC0\uACBD \uC5C6\uC74C" : `${fileCount}\uAC1C \uD30C\uC77C`;
|
|
628
|
+
}
|
|
629
|
+
function buildReviewTargetSectionTitle(target) {
|
|
630
|
+
return target.kind === "commit" ? `${target.hash} ${target.subject}` : `${target.hash} | ${target.subject}`;
|
|
631
|
+
}
|
|
632
|
+
function buildReviewTargetSummaryLine(target) {
|
|
633
|
+
if (target.kind === "commit") {
|
|
634
|
+
return `- ${target.hash} | ${target.subject} | ${target.author} | ${target.relativeDate}`;
|
|
635
|
+
}
|
|
636
|
+
return `- ${target.hash} | ${target.subject}`;
|
|
637
|
+
}
|
|
638
|
+
function buildReviewTargetDiffArgs(target, filePath) {
|
|
639
|
+
const reviewPathspecArgs = getReviewPathspecArgs();
|
|
640
|
+
if (target.kind === "commit") {
|
|
641
|
+
return ["show", "--stat", "--patch", "--format=", target.hash, "--", ...reviewPathspecArgs];
|
|
642
|
+
}
|
|
643
|
+
const diffArgs = ["diff"];
|
|
644
|
+
if (target.kind === "staged") {
|
|
645
|
+
diffArgs.push("--cached");
|
|
646
|
+
}
|
|
647
|
+
diffArgs.push("--stat", "--patch", "--");
|
|
648
|
+
return [...diffArgs, ...reviewPathspecArgs];
|
|
649
|
+
}
|
|
650
|
+
function buildReviewTargetFileArgs(target) {
|
|
651
|
+
const reviewPathspecArgs = getReviewPathspecArgs();
|
|
652
|
+
if (target.kind === "commit") {
|
|
653
|
+
return ["show", "--pretty=format:", "--name-only", target.hash, "--", ...reviewPathspecArgs];
|
|
654
|
+
}
|
|
655
|
+
const diffArgs = ["diff"];
|
|
656
|
+
if (target.kind === "staged") {
|
|
657
|
+
diffArgs.push("--cached");
|
|
658
|
+
}
|
|
659
|
+
return [...diffArgs, "--name-only", "--", ...reviewPathspecArgs];
|
|
660
|
+
}
|
|
661
|
+
function getReviewTargetFiles(target) {
|
|
662
|
+
const output = runGitCommand(buildReviewTargetFileArgs(target), {
|
|
663
|
+
allowFailure: true
|
|
664
|
+
});
|
|
665
|
+
return output.split("\n").map((line) => line.trim()).filter(Boolean);
|
|
666
|
+
}
|
|
667
|
+
function createWorkingTreeReviewOption(kind) {
|
|
668
|
+
const files = getReviewTargetFiles({
|
|
669
|
+
hash: kind,
|
|
670
|
+
kind});
|
|
671
|
+
const subject = kind === "unstaged" ? "\uC544\uC9C1 git add \uD558\uC9C0 \uC54A\uC740 \uBCC0\uACBD\uC0AC\uD56D" : "git add \uB41C \uBCC0\uACBD\uC0AC\uD56D";
|
|
672
|
+
return {
|
|
673
|
+
author: "",
|
|
674
|
+
description: `${subject} | ${formatReviewTargetFileCount(files.length)}`,
|
|
675
|
+
hash: kind,
|
|
676
|
+
kind,
|
|
677
|
+
label: kind,
|
|
678
|
+
relativeDate: "",
|
|
679
|
+
subject
|
|
680
|
+
};
|
|
681
|
+
}
|
|
476
682
|
function getRecentCommitOptions() {
|
|
477
683
|
const output = runGitCommand(
|
|
478
684
|
["log", `-${COMMIT_FETCH_LIMIT}`, "--date=relative", "--pretty=format:%h%x09%an%x09%ar%x09%s"],
|
|
@@ -488,44 +694,43 @@ function getRecentCommitOptions() {
|
|
|
488
694
|
author,
|
|
489
695
|
description: `${author} | ${relativeDate}`,
|
|
490
696
|
hash,
|
|
697
|
+
kind: "commit",
|
|
491
698
|
label: `${hash} | ${truncateCommitSubject(subject)}`,
|
|
492
699
|
relativeDate,
|
|
493
700
|
subject
|
|
494
701
|
};
|
|
495
702
|
});
|
|
496
703
|
}
|
|
704
|
+
function getReviewTargetOptions() {
|
|
705
|
+
return [createWorkingTreeReviewOption("unstaged"), createWorkingTreeReviewOption("staged"), ...getRecentCommitOptions()];
|
|
706
|
+
}
|
|
497
707
|
function buildSelectedCommitSummary(commits) {
|
|
498
|
-
return commits.map((commit) =>
|
|
708
|
+
return commits.map((commit) => buildReviewTargetSummaryLine(commit)).join("\n");
|
|
499
709
|
}
|
|
500
710
|
function getReviewPathspecArgs() {
|
|
501
711
|
const { includePatterns, excludePatterns } = getGitDiffPathspecs();
|
|
502
712
|
return [...includePatterns, ...excludePatterns];
|
|
503
713
|
}
|
|
504
714
|
function buildSelectedCommitDiff(commits) {
|
|
505
|
-
const reviewPathspecArgs = getReviewPathspecArgs();
|
|
506
715
|
const sections = commits.map((commit) => {
|
|
507
|
-
const diff = runGitCommand(
|
|
716
|
+
const diff = runGitCommand(buildReviewTargetDiffArgs(commit), {
|
|
508
717
|
allowFailure: true,
|
|
509
718
|
trimOutput: false
|
|
510
719
|
}).trim();
|
|
511
720
|
if (!diff) {
|
|
512
721
|
return "";
|
|
513
722
|
}
|
|
514
|
-
return [`## ${commit
|
|
723
|
+
return [`## ${buildReviewTargetSectionTitle(commit)}`, diff].join("\n\n");
|
|
515
724
|
}).filter(Boolean).join("\n\n");
|
|
516
725
|
if (!sections) {
|
|
517
726
|
return "";
|
|
518
727
|
}
|
|
519
|
-
return ["# \uC120\uD0DD\uD55C \
|
|
728
|
+
return ["# \uC120\uD0DD\uD55C \uB9AC\uBDF0 \uB300\uC0C1", buildSelectedCommitSummary(commits), "", "# \uB9AC\uBDF0 \uB300\uC0C1 diff", sections].join("\n");
|
|
520
729
|
}
|
|
521
730
|
function getSelectedCommitFiles(commits) {
|
|
522
|
-
const reviewPathspecArgs = getReviewPathspecArgs();
|
|
523
731
|
const files = /* @__PURE__ */ new Set();
|
|
524
732
|
commits.forEach((commit) => {
|
|
525
|
-
|
|
526
|
-
allowFailure: true
|
|
527
|
-
});
|
|
528
|
-
output.split("\n").map((line) => line.trim()).filter(Boolean).forEach((filePath) => files.add(filePath));
|
|
733
|
+
getReviewTargetFiles(commit).forEach((filePath) => files.add(filePath));
|
|
529
734
|
});
|
|
530
735
|
return [...files];
|
|
531
736
|
}
|
|
@@ -713,13 +918,13 @@ async function showMultiSelect(question, options, windowSize = COMMIT_SELECTION_
|
|
|
713
918
|
});
|
|
714
919
|
}
|
|
715
920
|
async function selectReviewCommits() {
|
|
716
|
-
const commits =
|
|
921
|
+
const commits = getReviewTargetOptions();
|
|
717
922
|
if (commits.length === 0) {
|
|
718
|
-
console.log("\u2139\uFE0F \uB9AC\uBDF0\uD560 \
|
|
923
|
+
console.log("\u2139\uFE0F \uB9AC\uBDF0\uD560 \uB300\uC0C1\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
719
924
|
return [];
|
|
720
925
|
}
|
|
721
926
|
return showMultiSelect(
|
|
722
|
-
"\uB9AC\uBDF0\uD560 \
|
|
927
|
+
"\uB9AC\uBDF0\uD560 \uB300\uC0C1\uC744 \uC120\uD0DD\uD574\uC8FC\uC138\uC694.",
|
|
723
928
|
commits.map((commit) => ({
|
|
724
929
|
description: commit.description,
|
|
725
930
|
label: commit.label,
|
|
@@ -810,6 +1015,13 @@ var ALLOWED_REASONING_EFFORTS = ["minimal", "low", "medium", "high"];
|
|
|
810
1015
|
function shellQuote(value) {
|
|
811
1016
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
812
1017
|
}
|
|
1018
|
+
function toShellOptionToken(value) {
|
|
1019
|
+
const SIMPLE_SHELL_TOKEN_PATTERN = /^[A-Za-z0-9._:/=-]+$/;
|
|
1020
|
+
if (SIMPLE_SHELL_TOKEN_PATTERN.test(value)) {
|
|
1021
|
+
return value;
|
|
1022
|
+
}
|
|
1023
|
+
return shellQuote(value);
|
|
1024
|
+
}
|
|
813
1025
|
function getArgValue(flag) {
|
|
814
1026
|
const index = args.indexOf(flag);
|
|
815
1027
|
if (index === -1 || !args[index + 1]) {
|
|
@@ -889,9 +1101,9 @@ function getAliasFallbacks(primaryAlias) {
|
|
|
889
1101
|
}
|
|
890
1102
|
function buildClaudeExecCommand(options) {
|
|
891
1103
|
const { tempDiffPath: tempDiffPath2, prompt, systemPromptFiles, effort, model, fallbackModel } = options;
|
|
892
|
-
const modelOption = model ? `--model ${
|
|
893
|
-
const fallbackOption = model && fallbackModel ? `--fallback-model ${
|
|
894
|
-
const effortOption = `--effort ${
|
|
1104
|
+
const modelOption = model ? `--model ${toShellOptionToken(model)}` : "";
|
|
1105
|
+
const fallbackOption = model && fallbackModel ? `--fallback-model ${toShellOptionToken(fallbackModel)}` : "";
|
|
1106
|
+
const effortOption = `--effort ${toShellOptionToken(effort)}`;
|
|
895
1107
|
const appendedPromptFiles = systemPromptFiles.map((path3) => `--append-system-prompt-file ${shellQuote(path3)}`).join(" ");
|
|
896
1108
|
return `cat ${shellQuote(tempDiffPath2)} | claude ${[
|
|
897
1109
|
modelOption,
|
|
@@ -1016,12 +1228,22 @@ function printNotice2(message) {
|
|
|
1016
1228
|
console.warn(message);
|
|
1017
1229
|
}
|
|
1018
1230
|
}
|
|
1231
|
+
function normalizeEffort2(level) {
|
|
1232
|
+
if (level === "minimal") {
|
|
1233
|
+
return "low";
|
|
1234
|
+
}
|
|
1235
|
+
return level;
|
|
1236
|
+
}
|
|
1019
1237
|
function resolveReasoningEffort2() {
|
|
1020
1238
|
const customReasoningEffort = getArgValue2("--reasoning-effort");
|
|
1021
1239
|
if (customReasoningEffort) {
|
|
1022
1240
|
if (ALLOWED_REASONING_EFFORTS2.includes(customReasoningEffort)) {
|
|
1023
|
-
|
|
1024
|
-
|
|
1241
|
+
const normalized = normalizeEffort2(customReasoningEffort);
|
|
1242
|
+
trace3("reasoning:custom", `${customReasoningEffort} -> ${normalized}`);
|
|
1243
|
+
if (customReasoningEffort === "minimal") {
|
|
1244
|
+
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.");
|
|
1245
|
+
}
|
|
1246
|
+
return normalized;
|
|
1025
1247
|
}
|
|
1026
1248
|
printNotice2(
|
|
1027
1249
|
`\u26A0\uFE0F \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 reasoning effort(${customReasoningEffort})\uC785\uB2C8\uB2E4. allowed: ${ALLOWED_REASONING_EFFORTS2.join(
|
|
@@ -1030,8 +1252,8 @@ function resolveReasoningEffort2() {
|
|
|
1030
1252
|
);
|
|
1031
1253
|
}
|
|
1032
1254
|
if (args2.includes("--flash")) {
|
|
1033
|
-
trace3("reasoning:flash-default", "
|
|
1034
|
-
return "
|
|
1255
|
+
trace3("reasoning:flash-default", "low");
|
|
1256
|
+
return "low";
|
|
1035
1257
|
}
|
|
1036
1258
|
if (args2.includes("--review")) {
|
|
1037
1259
|
trace3("reasoning:review-default", "high");
|
|
@@ -1226,7 +1448,7 @@ function buildGeminiFileReferenceSection(files) {
|
|
|
1226
1448
|
const existingFiles = files.filter((file) => fs.existsSync(file.path));
|
|
1227
1449
|
return {
|
|
1228
1450
|
count: existingFiles.length,
|
|
1229
|
-
|
|
1451
|
+
items: existingFiles.map((file) => `${file.display} ${toGeminiFileReference(file.path)}`)
|
|
1230
1452
|
};
|
|
1231
1453
|
}
|
|
1232
1454
|
var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
@@ -1245,19 +1467,19 @@ var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
|
1245
1467
|
const ruleSection = buildGeminiFileReferenceSection(rules);
|
|
1246
1468
|
trace5("rules:loaded", `count=${ruleSection.count}`);
|
|
1247
1469
|
const reviewFormExists = fs.existsSync(resolvedReviewFormPath);
|
|
1248
|
-
const
|
|
1470
|
+
const reviewFormText = reviewFormExists ? `\uB9AC\uBDF0 \uC591\uC2DD ${toGeminiFileReference(resolvedReviewFormPath)}` : "\uB9AC\uBDF0 \uC591\uC2DD (\uC5C6\uC74C)";
|
|
1249
1471
|
trace5("reviewForm:status", reviewFormExists ? "exists" : "missing");
|
|
1250
1472
|
const reasoningInstruction = getReasoningInstruction(reasoningEffort);
|
|
1251
|
-
const
|
|
1252
|
-
\
|
|
1253
|
-
|
|
1254
|
-
\uB9AC\uBDF0 \
|
|
1255
|
-
${
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
\
|
|
1260
|
-
|
|
1473
|
+
const ruleText = ruleSection.items.join(" ") || "(\uC5C6\uC74C)";
|
|
1474
|
+
const diffText = `\uB9AC\uBDF0 \uB300\uC0C1 diff ${toGeminiFileReference(resolvedTempDiffPath)}`;
|
|
1475
|
+
const prompt = [
|
|
1476
|
+
"\uC544\uB798 \uD30C\uC77C\uB4E4\uC744 \uC21C\uC11C\uB300\uB85C \uC77D\uACE0 \uCF54\uB4DC \uB9AC\uBDF0\uB97C \uC9C4\uD589\uD574\uC918.",
|
|
1477
|
+
`\uADDC\uCE59 \uD30C\uC77C: ${ruleText}`,
|
|
1478
|
+
`\uB9AC\uBDF0 \uC591\uC2DD \uD30C\uC77C: ${reviewFormText}`,
|
|
1479
|
+
`\uB9AC\uBDF0 \uB300\uC0C1 diff \uD30C\uC77C: ${diffText}`,
|
|
1480
|
+
"\uBC18\uB4DC\uC2DC \uB9AC\uBDF0 \uC591\uC2DD\uC5D0 \uB9DE\uCDB0 \uC791\uC131\uD574\uC918.",
|
|
1481
|
+
`\uCD94\uB860 \uAC15\uB3C4 \uC9C0\uCE68: ${reasoningInstruction}`
|
|
1482
|
+
].join(" ");
|
|
1261
1483
|
trace5("prompt:prepared", `length=${prompt.length}`);
|
|
1262
1484
|
const modelCandidates = toUnique2(customModel ? [customModel, ...aliasFallbacks] : aliasFallbacks);
|
|
1263
1485
|
trace5("model:candidates", modelCandidates.join(", "));
|
|
@@ -1320,8 +1542,10 @@ function checkGeminiCliInstalled() {
|
|
|
1320
1542
|
// src/pr-review/review.ts
|
|
1321
1543
|
async function main() {
|
|
1322
1544
|
const args4 = process.argv.slice(2);
|
|
1545
|
+
const startedAt = /* @__PURE__ */ new Date();
|
|
1323
1546
|
clearTraceMessages();
|
|
1324
1547
|
const isTest = isTestMode(args4);
|
|
1548
|
+
const shouldStreamOutput = shouldStreamAIOutput(args4);
|
|
1325
1549
|
const trace7 = createTraceLogger("review", args4);
|
|
1326
1550
|
trace7("main:start", `args=${JSON.stringify(args4)}`);
|
|
1327
1551
|
let command = "";
|
|
@@ -1330,6 +1554,12 @@ async function main() {
|
|
|
1330
1554
|
let service = "";
|
|
1331
1555
|
let selectedCommitSummary = "";
|
|
1332
1556
|
let reviewTargetFiles = [];
|
|
1557
|
+
let executionLogPath = "";
|
|
1558
|
+
let executionStatus = "cancelled";
|
|
1559
|
+
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.";
|
|
1560
|
+
let executionError = null;
|
|
1561
|
+
let resultLength = 0;
|
|
1562
|
+
let exitCode = 0;
|
|
1333
1563
|
try {
|
|
1334
1564
|
trace7("service-selection:start");
|
|
1335
1565
|
service = await showSelectionAIService();
|
|
@@ -1353,14 +1583,18 @@ async function main() {
|
|
|
1353
1583
|
}
|
|
1354
1584
|
trace7("review-flow:start");
|
|
1355
1585
|
console.log("\u{1F680} AI Code Review\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4...");
|
|
1586
|
+
if (shouldStreamOutput) {
|
|
1587
|
+
console.log("\u2139\uFE0F AI \uC2E4\uC2DC\uAC04 \uC751\uB2F5 \uD45C\uC2DC \uBAA8\uB4DC\uAC00 \uD65C\uC131\uD654\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
1588
|
+
}
|
|
1356
1589
|
trace7("commit-selection:start");
|
|
1357
1590
|
const selectedCommits = await selectReviewCommits();
|
|
1358
1591
|
trace7("commit-selection:done", `count=${selectedCommits.length}`);
|
|
1359
1592
|
if (selectedCommits.length === 0) {
|
|
1360
1593
|
trace7("commit-selection:empty");
|
|
1361
|
-
|
|
1594
|
+
executionTitle = "\uC120\uD0DD\uB41C \uB9AC\uBDF0 \uB300\uC0C1\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.";
|
|
1595
|
+
console.log("\u2139\uFE0F \uC120\uD0DD\uB41C \uB9AC\uBDF0 \uB300\uC0C1\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
1362
1596
|
deleteTempDiff();
|
|
1363
|
-
|
|
1597
|
+
return;
|
|
1364
1598
|
}
|
|
1365
1599
|
selectedCommitSummary = buildSelectedCommitSummary(selectedCommits);
|
|
1366
1600
|
trace7("commit-summary:prepared", selectedCommitSummary);
|
|
@@ -1372,9 +1606,10 @@ async function main() {
|
|
|
1372
1606
|
trace7("git-diff:build:done", `length=${diff.length}`);
|
|
1373
1607
|
if (!diff.trim() && !isTest) {
|
|
1374
1608
|
trace7("empty-diff:exit");
|
|
1375
|
-
|
|
1609
|
+
executionTitle = "\uC120\uD0DD\uD55C \uB9AC\uBDF0 \uB300\uC0C1\uC5D0\uC11C \uB9AC\uBDF0\uD560 \uBCC0\uACBD\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.";
|
|
1610
|
+
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.");
|
|
1376
1611
|
deleteTempDiff();
|
|
1377
|
-
|
|
1612
|
+
return;
|
|
1378
1613
|
}
|
|
1379
1614
|
const nowStr = getNowString();
|
|
1380
1615
|
trace7("timestamp:created", nowStr);
|
|
@@ -1404,8 +1639,9 @@ async function main() {
|
|
|
1404
1639
|
trace7("command:exec:start");
|
|
1405
1640
|
const result = (await executeShellCommandWithProgress(command, {
|
|
1406
1641
|
progressMessage: `\u23F3 [\uB9AC\uBDF0 \uC9C4\uD589] ${service} | \uB300\uC0C1 ${reviewTargetFiles.length}\uAC1C \uD30C\uC77C`,
|
|
1407
|
-
streamOutput: isTest
|
|
1642
|
+
streamOutput: isTest || shouldStreamOutput
|
|
1408
1643
|
})).stdout;
|
|
1644
|
+
resultLength = result.length;
|
|
1409
1645
|
trace7("command:exec:done", `resultLength=${result.length}`);
|
|
1410
1646
|
trace7("report:write:start");
|
|
1411
1647
|
savedReportPath = getNextFilePath(REPORT_DIR, nowStr, ".md");
|
|
@@ -1431,9 +1667,15 @@ ${command}`);
|
|
|
1431
1667
|
deleteTempDiff();
|
|
1432
1668
|
trace7("cleanup-temp-diff:done");
|
|
1433
1669
|
trace7("review-flow:end");
|
|
1670
|
+
executionStatus = "success";
|
|
1671
|
+
executionTitle = "\uB9AC\uBDF0\uAC00 \uC131\uACF5\uC801\uC73C\uB85C \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.";
|
|
1434
1672
|
} catch (error) {
|
|
1435
1673
|
trace7("review-flow:catch", getErrorSummary(error));
|
|
1436
1674
|
let errorReportPath = "";
|
|
1675
|
+
executionStatus = "failed";
|
|
1676
|
+
executionTitle = "\uB9AC\uBDF0 \uC2E4\uD589 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.";
|
|
1677
|
+
executionError = error;
|
|
1678
|
+
exitCode = 1;
|
|
1437
1679
|
trace7("cleanup-temp-diff:start(catch)");
|
|
1438
1680
|
try {
|
|
1439
1681
|
deleteTempDiff();
|
|
@@ -1473,7 +1715,50 @@ ${JSON.stringify(
|
|
|
1473
1715
|
if (errorReportPath) {
|
|
1474
1716
|
console.error(`\u{1F4C4} \uC5D0\uB7EC \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${errorReportPath}`);
|
|
1475
1717
|
}
|
|
1476
|
-
|
|
1718
|
+
} finally {
|
|
1719
|
+
executionLogPath = writeExecutionLog({
|
|
1720
|
+
scope: "review",
|
|
1721
|
+
status: executionStatus,
|
|
1722
|
+
title: executionTitle,
|
|
1723
|
+
args: args4,
|
|
1724
|
+
startedAt,
|
|
1725
|
+
error: executionError,
|
|
1726
|
+
extraSections: [
|
|
1727
|
+
{
|
|
1728
|
+
heading: "Execution Context",
|
|
1729
|
+
markdown: `\`\`\`json
|
|
1730
|
+
${JSON.stringify(
|
|
1731
|
+
{
|
|
1732
|
+
service: service || null,
|
|
1733
|
+
selectedCommitSummary: selectedCommitSummary || null,
|
|
1734
|
+
reviewTargetFiles,
|
|
1735
|
+
command: command || null,
|
|
1736
|
+
tempDiffPath,
|
|
1737
|
+
savedDiffPath: savedDiffPath || null,
|
|
1738
|
+
savedReportPath: savedReportPath || null,
|
|
1739
|
+
shouldStreamOutput,
|
|
1740
|
+
resultLength
|
|
1741
|
+
},
|
|
1742
|
+
null,
|
|
1743
|
+
2
|
|
1744
|
+
)}
|
|
1745
|
+
\`\`\``
|
|
1746
|
+
},
|
|
1747
|
+
{
|
|
1748
|
+
heading: "Generated Command",
|
|
1749
|
+
markdown: command ? `\`\`\`sh
|
|
1750
|
+
${command}
|
|
1751
|
+
\`\`\`` : "(\uC5C6\uC74C)"
|
|
1752
|
+
}
|
|
1753
|
+
]
|
|
1754
|
+
});
|
|
1755
|
+
if (executionLogPath) {
|
|
1756
|
+
const writeLog = executionStatus === "failed" ? console.error : console.log;
|
|
1757
|
+
writeLog(`\u{1F4DD} \uC2E4\uD589 \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${executionLogPath}`);
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
if (exitCode !== 0) {
|
|
1761
|
+
process.exit(exitCode);
|
|
1477
1762
|
}
|
|
1478
1763
|
}
|
|
1479
1764
|
main();
|