sales-frontend-gemini-cli 0.4.2 → 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.
- package/dist/common/helper.cjs +581 -53
- package/dist/common/helper.cjs.map +1 -1
- package/dist/common/helper.d.cts +114 -3
- package/dist/common/helper.d.ts +114 -3
- package/dist/common/helper.js +570 -54
- package/dist/common/helper.js.map +1 -1
- package/dist/common/types.d.cts +24 -1
- package/dist/common/types.d.ts +24 -1
- package/dist/pr-review/claude/claude-commander.cjs +60 -12
- package/dist/pr-review/claude/claude-commander.cjs.map +1 -1
- package/dist/pr-review/claude/claude-commander.js +60 -12
- package/dist/pr-review/claude/claude-commander.js.map +1 -1
- package/dist/pr-review/claude/installation-claude.cjs +42 -6
- package/dist/pr-review/claude/installation-claude.cjs.map +1 -1
- package/dist/pr-review/claude/installation-claude.js +42 -6
- package/dist/pr-review/claude/installation-claude.js.map +1 -1
- package/dist/pr-review/codex/codex-commander.cjs +63 -12
- 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 +63 -12
- package/dist/pr-review/codex/codex-commander.js.map +1 -1
- package/dist/pr-review/codex/installation-codex.cjs +42 -6
- package/dist/pr-review/codex/installation-codex.cjs.map +1 -1
- package/dist/pr-review/codex/installation-codex.js +42 -6
- package/dist/pr-review/codex/installation-codex.js.map +1 -1
- package/dist/pr-review/gemini/gemini-commander.cjs +76 -16
- package/dist/pr-review/gemini/gemini-commander.cjs.map +1 -1
- package/dist/pr-review/gemini/gemini-commander.js +76 -16
- package/dist/pr-review/gemini/gemini-commander.js.map +1 -1
- package/dist/pr-review/gemini/installation-gemini.cjs +42 -6
- package/dist/pr-review/gemini/installation-gemini.cjs.map +1 -1
- package/dist/pr-review/gemini/installation-gemini.js +42 -6
- package/dist/pr-review/gemini/installation-gemini.js.map +1 -1
- package/dist/pr-review/review-one-by-one.cjs +699 -106
- package/dist/pr-review/review-one-by-one.cjs.map +1 -1
- package/dist/pr-review/review-one-by-one.js +700 -107
- package/dist/pr-review/review-one-by-one.js.map +1 -1
- package/dist/pr-review/review.cjs +722 -105
- package/dist/pr-review/review.cjs.map +1 -1
- package/dist/pr-review/review.js +722 -105
- package/dist/pr-review/review.js.map +1 -1
- package/package.json +4 -7
- package/src/common/rules/coding-convention.md +393 -0
- package/src/common/rules/coding-convention.pdf +0 -0
- package/src/common/rules/naming-rule.md +347 -0
- package/src/common/rules/naming-rule.pdf +0 -0
|
@@ -18,14 +18,52 @@ var readline__default = /*#__PURE__*/_interopDefault(readline);
|
|
|
18
18
|
|
|
19
19
|
var __dirname$1 = path__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('review-one-by-one.cjs', document.baseURI).href))));
|
|
20
20
|
var traceMessages = [];
|
|
21
|
-
var
|
|
22
|
-
var
|
|
23
|
-
|
|
24
|
-
path__default.default.
|
|
25
|
-
|
|
21
|
+
var GEMINI_CLI_PACKAGE_NAME = "sales-frontend-gemini-cli";
|
|
22
|
+
var cachedPackageRootPath = "";
|
|
23
|
+
function isGeminiCliPackageRoot(directory) {
|
|
24
|
+
const packageJsonPath = path__default.default.join(directory, "package.json");
|
|
25
|
+
if (!fs__default.default.existsSync(packageJsonPath)) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const packageJson = JSON.parse(fs__default.default.readFileSync(packageJsonPath, "utf8"));
|
|
30
|
+
return packageJson.name === GEMINI_CLI_PACKAGE_NAME;
|
|
31
|
+
} catch {
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function resolveGeminiCliPackageRoot(startDirectory = __dirname$1) {
|
|
36
|
+
if (cachedPackageRootPath) {
|
|
37
|
+
return cachedPackageRootPath;
|
|
38
|
+
}
|
|
39
|
+
let currentDirectory = startDirectory;
|
|
40
|
+
while (true) {
|
|
41
|
+
if (isGeminiCliPackageRoot(currentDirectory)) {
|
|
42
|
+
cachedPackageRootPath = currentDirectory;
|
|
43
|
+
return cachedPackageRootPath;
|
|
44
|
+
}
|
|
45
|
+
const parentDirectory = path__default.default.dirname(currentDirectory);
|
|
46
|
+
if (parentDirectory === currentDirectory) {
|
|
47
|
+
break;
|
|
48
|
+
}
|
|
49
|
+
currentDirectory = parentDirectory;
|
|
50
|
+
}
|
|
51
|
+
cachedPackageRootPath = path__default.default.resolve(startDirectory, "../..");
|
|
52
|
+
return cachedPackageRootPath;
|
|
53
|
+
}
|
|
54
|
+
function resolvePackageAssetPath(relativeFilePath) {
|
|
55
|
+
return path__default.default.resolve(resolveGeminiCliPackageRoot(), relativeFilePath);
|
|
56
|
+
}
|
|
57
|
+
var rulesPath = resolvePackageAssetPath("src/common/rules/review-rules.md");
|
|
58
|
+
var namingRulesPath = resolvePackageAssetPath("src/common/rules/naming-rule.md");
|
|
59
|
+
var codingConventionRulesPath = resolvePackageAssetPath("src/common/rules/coding-convention.md");
|
|
60
|
+
resolvePackageAssetPath("src/common/form/review-form.md");
|
|
61
|
+
var reviewFormOneByOnePath = resolvePackageAssetPath("src/common/form/review-form-one-by-one.md");
|
|
26
62
|
var REPORT_DIR = ".review-report";
|
|
27
63
|
var tempDiffPath = "temp_diff.txt";
|
|
28
64
|
var AIServices = ["gemini", "claude", "codex"];
|
|
65
|
+
var COMMIT_FETCH_LIMIT = 20;
|
|
66
|
+
var COMMIT_SELECTION_WINDOW = 8;
|
|
29
67
|
var ignoreList = [
|
|
30
68
|
"package.json",
|
|
31
69
|
"*.yml",
|
|
@@ -49,6 +87,137 @@ function clearTraceMessages() {
|
|
|
49
87
|
function getTraceMessages() {
|
|
50
88
|
return [...traceMessages];
|
|
51
89
|
}
|
|
90
|
+
var ANSI = {
|
|
91
|
+
bold: "\x1B[1m",
|
|
92
|
+
cyan: "\x1B[36m",
|
|
93
|
+
dim: "\x1B[2m",
|
|
94
|
+
green: "\x1B[32m",
|
|
95
|
+
reset: "\x1B[0m",
|
|
96
|
+
yellow: "\x1B[33m"
|
|
97
|
+
};
|
|
98
|
+
var ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
|
|
99
|
+
var COMBINING_MARK_PATTERN = /\p{Mark}/u;
|
|
100
|
+
var GRAPHEME_SEGMENTER = typeof Intl !== "undefined" && "Segmenter" in Intl ? new Intl.Segmenter("ko", { granularity: "grapheme" }) : null;
|
|
101
|
+
function getGitDiffPathspecs() {
|
|
102
|
+
return {
|
|
103
|
+
excludePatterns: ignoreList.map((item) => `:(exclude)${item}`),
|
|
104
|
+
includePatterns: ["*.ts", "*.tsx", "*.js", "*.jsx"]
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
function segmentGraphemes(value) {
|
|
108
|
+
if (!GRAPHEME_SEGMENTER) {
|
|
109
|
+
return [...value];
|
|
110
|
+
}
|
|
111
|
+
return [...GRAPHEME_SEGMENTER.segment(value)].map(({ segment }) => segment);
|
|
112
|
+
}
|
|
113
|
+
function isWideCodePoint(codePoint) {
|
|
114
|
+
return codePoint >= 4352 && (codePoint <= 4447 || codePoint === 9001 || codePoint === 9002 || codePoint >= 11904 && codePoint <= 12871 && codePoint !== 12351 || codePoint >= 12880 && codePoint <= 19903 || codePoint >= 19968 && codePoint <= 42182 || codePoint >= 43360 && codePoint <= 43388 || codePoint >= 44032 && codePoint <= 55203 || codePoint >= 63744 && codePoint <= 64255 || codePoint >= 65040 && codePoint <= 65049 || codePoint >= 65072 && codePoint <= 65131 || codePoint >= 65281 && codePoint <= 65376 || codePoint >= 65504 && codePoint <= 65510 || codePoint >= 127488 && codePoint <= 127569 || codePoint >= 131072 && codePoint <= 262141);
|
|
115
|
+
}
|
|
116
|
+
function isEmojiCodePoint(codePoint) {
|
|
117
|
+
return codePoint >= 127462 && codePoint <= 127487 || codePoint >= 127744 && codePoint <= 129791 || codePoint >= 9728 && codePoint <= 10175;
|
|
118
|
+
}
|
|
119
|
+
function getGraphemeWidth(grapheme) {
|
|
120
|
+
let width = 0;
|
|
121
|
+
for (const character of grapheme) {
|
|
122
|
+
const codePoint = character.codePointAt(0);
|
|
123
|
+
if (!codePoint || COMBINING_MARK_PATTERN.test(character) || codePoint === 8205) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (codePoint >= 65024 && codePoint <= 65039 || codePoint >= 917760 && codePoint <= 917999) {
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
if (isWideCodePoint(codePoint) || isEmojiCodePoint(codePoint)) {
|
|
130
|
+
width = Math.max(width, 2);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
width = Math.max(width, 1);
|
|
134
|
+
}
|
|
135
|
+
return width;
|
|
136
|
+
}
|
|
137
|
+
function tokenizePlainText(value) {
|
|
138
|
+
return segmentGraphemes(value).map((segment) => ({
|
|
139
|
+
value: segment,
|
|
140
|
+
visibleWidth: getGraphemeWidth(segment)
|
|
141
|
+
}));
|
|
142
|
+
}
|
|
143
|
+
function tokenizeVisibleText(value) {
|
|
144
|
+
const tokens = [];
|
|
145
|
+
let lastIndex = 0;
|
|
146
|
+
for (const match of value.matchAll(ANSI_PATTERN)) {
|
|
147
|
+
const index = match.index ?? 0;
|
|
148
|
+
if (index > lastIndex) {
|
|
149
|
+
tokens.push(...tokenizePlainText(value.slice(lastIndex, index)));
|
|
150
|
+
}
|
|
151
|
+
tokens.push({
|
|
152
|
+
value: match[0],
|
|
153
|
+
visibleWidth: 0
|
|
154
|
+
});
|
|
155
|
+
lastIndex = index + match[0].length;
|
|
156
|
+
}
|
|
157
|
+
if (lastIndex < value.length) {
|
|
158
|
+
tokens.push(...tokenizePlainText(value.slice(lastIndex)));
|
|
159
|
+
}
|
|
160
|
+
return tokens;
|
|
161
|
+
}
|
|
162
|
+
function truncateLineForTerminal(value, maxWidth) {
|
|
163
|
+
if (maxWidth <= 0) {
|
|
164
|
+
return "";
|
|
165
|
+
}
|
|
166
|
+
const tokens = tokenizeVisibleText(value);
|
|
167
|
+
const totalWidth = tokens.reduce((sum, token) => sum + token.visibleWidth, 0);
|
|
168
|
+
if (totalWidth <= maxWidth) {
|
|
169
|
+
return value;
|
|
170
|
+
}
|
|
171
|
+
const ellipsis = "...";
|
|
172
|
+
const ellipsisWidth = 3;
|
|
173
|
+
const targetWidth = Math.max(0, maxWidth - ellipsisWidth);
|
|
174
|
+
let usedWidth = 0;
|
|
175
|
+
let result = "";
|
|
176
|
+
for (const token of tokens) {
|
|
177
|
+
if (token.visibleWidth === 0) {
|
|
178
|
+
result += token.value;
|
|
179
|
+
continue;
|
|
180
|
+
}
|
|
181
|
+
if (usedWidth + token.visibleWidth > targetWidth) {
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
result += token.value;
|
|
185
|
+
usedWidth += token.visibleWidth;
|
|
186
|
+
}
|
|
187
|
+
return `${result}${ellipsis}${ANSI.reset}`;
|
|
188
|
+
}
|
|
189
|
+
function fitLinesToTerminal(lines) {
|
|
190
|
+
const maxWidth = Math.max(20, (process.stdout.columns || 120) - 1);
|
|
191
|
+
return lines.map((line) => truncateLineForTerminal(line, maxWidth));
|
|
192
|
+
}
|
|
193
|
+
function runGitCommand(args4, options = {}) {
|
|
194
|
+
const { allowFailure = false, trimOutput = true } = options;
|
|
195
|
+
try {
|
|
196
|
+
const output = child_process.execFileSync("git", args4, {
|
|
197
|
+
encoding: "utf8",
|
|
198
|
+
maxBuffer: 1024 * 1024 * 20,
|
|
199
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
200
|
+
});
|
|
201
|
+
return trimOutput ? output.trim() : output;
|
|
202
|
+
} catch (error) {
|
|
203
|
+
helperTrace("git-command:failed", `${args4.join(" ")} | ${getErrorSummary(error)}`);
|
|
204
|
+
if (allowFailure) {
|
|
205
|
+
return "";
|
|
206
|
+
}
|
|
207
|
+
throw error;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function formatReviewTargetFiles(files, visibleCount = 5) {
|
|
211
|
+
if (files.length === 0) {
|
|
212
|
+
return "(\uC5C6\uC74C)";
|
|
213
|
+
}
|
|
214
|
+
const visibleFiles = files.slice(0, visibleCount);
|
|
215
|
+
const hiddenCount = Math.max(0, files.length - visibleFiles.length);
|
|
216
|
+
if (hiddenCount === 0) {
|
|
217
|
+
return visibleFiles.join(", ");
|
|
218
|
+
}
|
|
219
|
+
return `${visibleFiles.join(", ")} \uC678 ${hiddenCount}\uAC1C`;
|
|
220
|
+
}
|
|
52
221
|
function createTraceLogger(scope, args4 = process.argv.slice(2)) {
|
|
53
222
|
const enabled = isTestMode(args4);
|
|
54
223
|
return (step, detail) => {
|
|
@@ -110,7 +279,7 @@ function serializeError(error) {
|
|
|
110
279
|
}
|
|
111
280
|
if (error && typeof error === "object") {
|
|
112
281
|
const errorLike = error;
|
|
113
|
-
const extraKeys = ["code", "errno", "syscall", "path", "cmd", "status", "signal", "spawnargs"];
|
|
282
|
+
const extraKeys = ["code", "errno", "syscall", "path", "cmd", "status", "signal", "spawnargs", "command"];
|
|
114
283
|
extraKeys.forEach((key) => {
|
|
115
284
|
if (errorLike[key] !== void 0) {
|
|
116
285
|
serialized[key] = errorLike[key];
|
|
@@ -216,6 +385,87 @@ ${section.markdown}`).join("\n")}
|
|
|
216
385
|
return "";
|
|
217
386
|
}
|
|
218
387
|
}
|
|
388
|
+
function getExecutionLogSummary(status, title) {
|
|
389
|
+
if (title) {
|
|
390
|
+
return title;
|
|
391
|
+
}
|
|
392
|
+
switch (status) {
|
|
393
|
+
case "success":
|
|
394
|
+
return "\uB9AC\uBDF0 \uC2E4\uD589\uC774 \uC131\uACF5\uC801\uC73C\uB85C \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.";
|
|
395
|
+
case "failed":
|
|
396
|
+
return "\uB9AC\uBDF0 \uC2E4\uD589 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.";
|
|
397
|
+
case "partial_failure":
|
|
398
|
+
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.";
|
|
399
|
+
default:
|
|
400
|
+
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.";
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
function formatExecutionDuration(startedAt, finishedAt) {
|
|
404
|
+
const durationMs = Math.max(0, finishedAt.getTime() - startedAt.getTime());
|
|
405
|
+
if (durationMs < 1e3) {
|
|
406
|
+
return `${durationMs}ms`;
|
|
407
|
+
}
|
|
408
|
+
const durationSeconds = durationMs / 1e3;
|
|
409
|
+
if (durationSeconds < 60) {
|
|
410
|
+
return `${durationSeconds.toFixed(1)}s`;
|
|
411
|
+
}
|
|
412
|
+
const minutes = Math.floor(durationSeconds / 60);
|
|
413
|
+
const seconds = Math.round(durationSeconds % 60);
|
|
414
|
+
return `${minutes}m ${seconds}s`;
|
|
415
|
+
}
|
|
416
|
+
function writeExecutionLog(options = {}) {
|
|
417
|
+
try {
|
|
418
|
+
const startedAt = options.startedAt ?? /* @__PURE__ */ new Date();
|
|
419
|
+
const finishedAt = options.finishedAt ?? /* @__PURE__ */ new Date();
|
|
420
|
+
const status = options.status ?? "success";
|
|
421
|
+
helperTrace("execution-log:write:start", options.scope || "unknown");
|
|
422
|
+
createReportDirectory();
|
|
423
|
+
const reportPath = getAvailableFilePath(REPORT_DIR, `${getNowString(finishedAt)}-execution-log`, ".md");
|
|
424
|
+
const traceSnapshot = options.traceMessages ?? getTraceMessages();
|
|
425
|
+
const extraSections = options.extraSections || [];
|
|
426
|
+
const serializedError = options.error ? serializeError(options.error) : null;
|
|
427
|
+
const report = `# Execution Log
|
|
428
|
+
|
|
429
|
+
- \uC2DC\uC791 \uC2DC\uAC01: ${getHumanReadableNowString(startedAt)}
|
|
430
|
+
- \uC885\uB8CC \uC2DC\uAC01: ${getHumanReadableNowString(finishedAt)}
|
|
431
|
+
- \uC2E4\uD589 \uC2DC\uAC04: ${formatExecutionDuration(startedAt, finishedAt)}
|
|
432
|
+
- \uC0C1\uD0DC: \`${status}\`
|
|
433
|
+
- Scope: \`${options.scope || "unknown"}\`
|
|
434
|
+
- \uC791\uC5C5 \uACBD\uB85C: \`${process.cwd()}\`
|
|
435
|
+
- \uC2E4\uD589 \uC778\uC790: \`${JSON.stringify(options.args ?? process.argv.slice(2))}\`
|
|
436
|
+
- \uC2E4\uD589 \uD658\uACBD: \`${process.platform} ${process.arch} / Node ${process.version}\`
|
|
437
|
+
|
|
438
|
+
## Summary
|
|
439
|
+
|
|
440
|
+
${getExecutionLogSummary(status, options.title)}
|
|
441
|
+
${serializedError ? `
|
|
442
|
+
|
|
443
|
+
## Error
|
|
444
|
+
|
|
445
|
+
\`\`\`json
|
|
446
|
+
${JSON.stringify(serializedError, null, 2)}
|
|
447
|
+
\`\`\`` : ""}
|
|
448
|
+
|
|
449
|
+
## Trace
|
|
450
|
+
|
|
451
|
+
\`\`\`json
|
|
452
|
+
${JSON.stringify(traceSnapshot, null, 2)}
|
|
453
|
+
\`\`\`${extraSections.length ? `
|
|
454
|
+
${extraSections.map((section) => `
|
|
455
|
+
## ${section.heading}
|
|
456
|
+
|
|
457
|
+
${section.markdown}`).join("\n")}
|
|
458
|
+
` : "\n"}
|
|
459
|
+
`;
|
|
460
|
+
fs__default.default.writeFileSync(reportPath, report);
|
|
461
|
+
helperTrace("execution-log:write:done", reportPath);
|
|
462
|
+
return reportPath;
|
|
463
|
+
} catch (writeError) {
|
|
464
|
+
console.error("\u26A0\uFE0F \uC2E4\uD589 \uB85C\uADF8 \uD30C\uC77C \uC0DD\uC131\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
|
|
465
|
+
console.error(writeError);
|
|
466
|
+
return "";
|
|
467
|
+
}
|
|
468
|
+
}
|
|
219
469
|
function exitWithError(message, options = {}) {
|
|
220
470
|
const reportPath = writeErrorReport(options.error || new Error(message), {
|
|
221
471
|
...options,
|
|
@@ -260,13 +510,83 @@ ${JSON.stringify(AIServices, null, 2)}
|
|
|
260
510
|
}
|
|
261
511
|
);
|
|
262
512
|
}
|
|
263
|
-
function
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
513
|
+
function truncateCommitSubject(subject) {
|
|
514
|
+
if (subject.length <= 72) {
|
|
515
|
+
return subject;
|
|
516
|
+
}
|
|
517
|
+
return `${subject.slice(0, 69)}...`;
|
|
518
|
+
}
|
|
519
|
+
function getRecentCommitOptions() {
|
|
520
|
+
const output = runGitCommand(
|
|
521
|
+
["log", `-${COMMIT_FETCH_LIMIT}`, "--date=relative", "--pretty=format:%h%x09%an%x09%ar%x09%s"],
|
|
522
|
+
{ allowFailure: true }
|
|
523
|
+
);
|
|
524
|
+
if (!output) {
|
|
525
|
+
return [];
|
|
526
|
+
}
|
|
527
|
+
return output.split("\n").map((line) => {
|
|
528
|
+
const [hash = "", author = "", relativeDate = "", ...subjectParts] = line.split(" ");
|
|
529
|
+
const subject = subjectParts.join(" ").trim();
|
|
530
|
+
return {
|
|
531
|
+
author,
|
|
532
|
+
description: `${author} | ${relativeDate}`,
|
|
533
|
+
hash,
|
|
534
|
+
label: `${hash} | ${truncateCommitSubject(subject)}`,
|
|
535
|
+
relativeDate,
|
|
536
|
+
subject
|
|
537
|
+
};
|
|
538
|
+
});
|
|
539
|
+
}
|
|
540
|
+
function buildSelectedCommitSummary(commits) {
|
|
541
|
+
return commits.map((commit) => `- ${commit.hash} | ${commit.subject} | ${commit.author} | ${commit.relativeDate}`).join("\n");
|
|
542
|
+
}
|
|
543
|
+
function getReviewPathspecArgs() {
|
|
544
|
+
const { includePatterns, excludePatterns } = getGitDiffPathspecs();
|
|
545
|
+
return [...includePatterns, ...excludePatterns];
|
|
546
|
+
}
|
|
547
|
+
function buildSelectedCommitDiff(commits) {
|
|
548
|
+
const reviewPathspecArgs = getReviewPathspecArgs();
|
|
549
|
+
const sections = commits.map((commit) => {
|
|
550
|
+
const diff = runGitCommand(["show", "--stat", "--patch", "--format=", commit.hash, "--", ...reviewPathspecArgs], {
|
|
551
|
+
allowFailure: true,
|
|
552
|
+
trimOutput: false
|
|
553
|
+
}).trim();
|
|
554
|
+
if (!diff) {
|
|
555
|
+
return "";
|
|
556
|
+
}
|
|
557
|
+
return [`## ${commit.hash} ${commit.subject}`, diff].join("\n\n");
|
|
558
|
+
}).filter(Boolean).join("\n\n");
|
|
559
|
+
if (!sections) {
|
|
560
|
+
return "";
|
|
561
|
+
}
|
|
562
|
+
return ["# \uC120\uD0DD\uD55C \uCEE4\uBC0B", buildSelectedCommitSummary(commits), "", "# \uB9AC\uBDF0 \uB300\uC0C1 diff", sections].join("\n");
|
|
563
|
+
}
|
|
564
|
+
function getSelectedCommitFiles(commits) {
|
|
565
|
+
const reviewPathspecArgs = getReviewPathspecArgs();
|
|
566
|
+
const files = /* @__PURE__ */ new Set();
|
|
567
|
+
commits.forEach((commit) => {
|
|
568
|
+
const output = runGitCommand(["show", "--pretty=format:", "--name-only", commit.hash, "--", ...reviewPathspecArgs], {
|
|
569
|
+
allowFailure: true
|
|
570
|
+
});
|
|
571
|
+
output.split("\n").map((line) => line.trim()).filter(Boolean).forEach((filePath) => files.add(filePath));
|
|
572
|
+
});
|
|
573
|
+
return [...files];
|
|
574
|
+
}
|
|
575
|
+
function buildSelectedFileDiff(commits, filePath) {
|
|
576
|
+
const sections = commits.map((commit) => {
|
|
577
|
+
const diff = runGitCommand(["show", "--stat", "--patch", "--format=", commit.hash, "--", filePath], {
|
|
578
|
+
allowFailure: true,
|
|
579
|
+
trimOutput: false
|
|
580
|
+
}).trim();
|
|
581
|
+
if (!diff) {
|
|
582
|
+
return "";
|
|
583
|
+
}
|
|
584
|
+
return [`## ${commit.hash} ${commit.subject}`, diff].join("\n\n");
|
|
585
|
+
}).filter(Boolean).join("\n\n");
|
|
586
|
+
if (!sections) {
|
|
587
|
+
return "";
|
|
588
|
+
}
|
|
589
|
+
return ["# \uC120\uD0DD\uD55C \uCEE4\uBC0B", buildSelectedCommitSummary(commits), "", `# \uD30C\uC77C: ${filePath}`, sections].join("\n\n");
|
|
270
590
|
}
|
|
271
591
|
function openReport(reportPath) {
|
|
272
592
|
const resolvedPath = path__default.default.resolve(reportPath);
|
|
@@ -317,59 +637,166 @@ function openReport(reportPath) {
|
|
|
317
637
|
helperTrace("open-report:unsupported-platform", platform);
|
|
318
638
|
console.error(`\u26A0\uFE0F \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD50C\uB7AB\uD3FC\uC785\uB2C8\uB2E4: ${platform}`);
|
|
319
639
|
}
|
|
320
|
-
function
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
helperTrace(
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
640
|
+
function ensureInteractiveSelectionAvailable(scope, message) {
|
|
641
|
+
if (process.stdin.isTTY && process.stdout.isTTY && typeof process.stdin.setRawMode === "function") {
|
|
642
|
+
return;
|
|
643
|
+
}
|
|
644
|
+
helperTrace(`${scope}:tty-missing`);
|
|
645
|
+
exitWithError(message, {
|
|
646
|
+
scope: `helper:${scope}`
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
function renderSelectionBlock(lines, previousLineCount) {
|
|
650
|
+
if (previousLineCount > 0) {
|
|
651
|
+
readline__default.default.moveCursor(process.stdout, 0, -previousLineCount);
|
|
652
|
+
readline__default.default.clearScreenDown(process.stdout);
|
|
653
|
+
}
|
|
654
|
+
const fittedLines = fitLinesToTerminal(lines);
|
|
655
|
+
process.stdout.write(`${fittedLines.join("\n")}
|
|
656
|
+
`);
|
|
657
|
+
return fittedLines.length;
|
|
658
|
+
}
|
|
659
|
+
function getSelectionWindowRange(optionCount, selectedIndex, windowSize) {
|
|
660
|
+
if (optionCount <= windowSize) {
|
|
661
|
+
return {
|
|
662
|
+
end: optionCount,
|
|
663
|
+
start: 0
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
const halfWindow = Math.floor(windowSize / 2);
|
|
667
|
+
const maxStart = optionCount - windowSize;
|
|
668
|
+
const start = Math.max(0, Math.min(selectedIndex - halfWindow, maxStart));
|
|
669
|
+
return {
|
|
670
|
+
end: Math.min(optionCount, start + windowSize),
|
|
671
|
+
start
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
function buildMultiSelectLines(question, options, selectedIndex, toggled, windowSize) {
|
|
675
|
+
const { start, end } = getSelectionWindowRange(options.length, selectedIndex, windowSize);
|
|
676
|
+
const lines = [
|
|
677
|
+
`${ANSI.bold}${question}${ANSI.reset}`,
|
|
678
|
+
`${ANSI.dim}\u2191\u2193 \uC774\uB3D9 | Space \uC120\uD0DD/\uD574\uC81C | Enter \uC644\uB8CC | Esc \uCDE8\uC18C${ANSI.reset}`,
|
|
679
|
+
`${ANSI.dim}\uC120\uD0DD\uB428: ${toggled.size}\uAC1C / \uC804\uCCB4: ${options.length}\uAC1C${ANSI.reset}`
|
|
680
|
+
];
|
|
681
|
+
for (let index = start; index < end; index += 1) {
|
|
682
|
+
const option = options[index];
|
|
683
|
+
if (!option) {
|
|
684
|
+
continue;
|
|
334
685
|
}
|
|
335
|
-
const
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
686
|
+
const cursor = index === selectedIndex ? `${ANSI.cyan}>${ANSI.reset}` : " ";
|
|
687
|
+
const checked = toggled.has(index) ? `${ANSI.green}\u2611${ANSI.reset}` : "\u2610";
|
|
688
|
+
const description = option.description ? ` ${ANSI.dim}${option.description}${ANSI.reset}` : "";
|
|
689
|
+
lines.push(`${cursor} ${checked} ${option.label}${description}`);
|
|
690
|
+
}
|
|
691
|
+
if (options.length > windowSize) {
|
|
692
|
+
lines.push(`${ANSI.dim}\uD45C\uC2DC \uBC94\uC704: ${start + 1}-${end} / ${options.length}${ANSI.reset}`);
|
|
693
|
+
}
|
|
694
|
+
return lines;
|
|
695
|
+
}
|
|
696
|
+
async function showMultiSelect(question, options, windowSize = COMMIT_SELECTION_WINDOW) {
|
|
697
|
+
ensureInteractiveSelectionAvailable("showMultiSelect", "\u274C \uCEE4\uBC0B \uC120\uD0DD \uBAA8\uB2EC\uC740 TTY \uD658\uACBD\uC5D0\uC11C\uB9CC \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.");
|
|
698
|
+
let selectedIndex = 0;
|
|
699
|
+
let renderedLineCount = 0;
|
|
700
|
+
const toggled = /* @__PURE__ */ new Set();
|
|
701
|
+
const rl = readline__default.default.createInterface({
|
|
702
|
+
input: process.stdin,
|
|
703
|
+
output: process.stdout,
|
|
704
|
+
terminal: true
|
|
705
|
+
});
|
|
706
|
+
process.stdout.write("\x1B[?25l");
|
|
707
|
+
const cleanup = () => {
|
|
708
|
+
if (renderedLineCount > 0) {
|
|
709
|
+
readline__default.default.moveCursor(process.stdout, 0, -renderedLineCount);
|
|
710
|
+
readline__default.default.clearScreenDown(process.stdout);
|
|
711
|
+
renderedLineCount = 0;
|
|
342
712
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
713
|
+
process.stdin.removeListener("data", onData);
|
|
714
|
+
process.stdin.setRawMode(false);
|
|
715
|
+
process.stdin.pause();
|
|
716
|
+
rl.close();
|
|
717
|
+
process.stdout.write("\x1B[?25h");
|
|
718
|
+
};
|
|
719
|
+
const render = () => {
|
|
720
|
+
const lines = buildMultiSelectLines(question, options, selectedIndex, toggled, windowSize);
|
|
721
|
+
renderedLineCount = renderSelectionBlock(lines, renderedLineCount);
|
|
722
|
+
};
|
|
723
|
+
const confirmSelection = (resolve) => {
|
|
724
|
+
const values = [...toggled].sort((left, right) => left - right).map((index) => options[index]?.value).filter((value) => value !== void 0);
|
|
725
|
+
cleanup();
|
|
726
|
+
resolve(values);
|
|
727
|
+
};
|
|
728
|
+
const cancelSelection = (resolve) => {
|
|
729
|
+
cleanup();
|
|
730
|
+
resolve([]);
|
|
731
|
+
};
|
|
732
|
+
let onData = (_data) => {
|
|
733
|
+
};
|
|
734
|
+
render();
|
|
735
|
+
return new Promise((resolve) => {
|
|
736
|
+
onData = (data) => {
|
|
737
|
+
const key = data.toString();
|
|
738
|
+
if (key === "") {
|
|
739
|
+
cleanup();
|
|
740
|
+
process.exit(0);
|
|
356
741
|
}
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
742
|
+
if (key === "\x1B") {
|
|
743
|
+
cancelSelection(resolve);
|
|
744
|
+
return;
|
|
745
|
+
}
|
|
746
|
+
if (key === "\x1B[A") {
|
|
747
|
+
selectedIndex = (selectedIndex - 1 + options.length) % options.length;
|
|
748
|
+
render();
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
if (key === "\x1B[B") {
|
|
752
|
+
selectedIndex = (selectedIndex + 1) % options.length;
|
|
753
|
+
render();
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
if (key === " ") {
|
|
757
|
+
if (toggled.has(selectedIndex)) {
|
|
758
|
+
toggled.delete(selectedIndex);
|
|
759
|
+
} else {
|
|
760
|
+
toggled.add(selectedIndex);
|
|
761
|
+
}
|
|
762
|
+
render();
|
|
763
|
+
return;
|
|
764
|
+
}
|
|
765
|
+
if (key === "\r" || key === "\n") {
|
|
766
|
+
confirmSelection(resolve);
|
|
767
|
+
}
|
|
768
|
+
};
|
|
769
|
+
process.stdin.setRawMode(true);
|
|
770
|
+
process.stdin.resume();
|
|
771
|
+
process.stdin.on("data", onData);
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
async function selectReviewCommits() {
|
|
775
|
+
const commits = getRecentCommitOptions();
|
|
776
|
+
if (commits.length === 0) {
|
|
777
|
+
console.log("\u2139\uFE0F \uB9AC\uBDF0\uD560 \uCD5C\uADFC \uCEE4\uBC0B\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
778
|
+
return [];
|
|
360
779
|
}
|
|
361
|
-
|
|
362
|
-
|
|
780
|
+
return showMultiSelect(
|
|
781
|
+
"\uB9AC\uBDF0\uD560 \uCEE4\uBC0B\uC744 \uC120\uD0DD\uD574\uC8FC\uC138\uC694.",
|
|
782
|
+
commits.map((commit) => ({
|
|
783
|
+
description: commit.description,
|
|
784
|
+
label: commit.label,
|
|
785
|
+
value: commit
|
|
786
|
+
})),
|
|
787
|
+
COMMIT_SELECTION_WINDOW
|
|
788
|
+
);
|
|
363
789
|
}
|
|
364
790
|
async function showSelectionAIService() {
|
|
365
791
|
const selectedServiceFromArgs = parseServiceFromArgs();
|
|
366
792
|
if (selectedServiceFromArgs) {
|
|
367
793
|
helperTrace("show-selection:from-args", selectedServiceFromArgs);
|
|
368
794
|
console.log(`
|
|
369
|
-
\u2705
|
|
795
|
+
\u2705 ${ANSI.green}${selectedServiceFromArgs}${ANSI.reset} \uC11C\uBE44\uC2A4\uAC00 \uC120\uD0DD\uB418\uC5C8\uC2B5\uB2C8\uB2E4. (--service)
|
|
370
796
|
`);
|
|
371
797
|
return selectedServiceFromArgs;
|
|
372
798
|
}
|
|
799
|
+
ensureInteractiveSelectionAvailable("showSelectionAIService", "\u274C AI \uC11C\uBE44\uC2A4 \uC120\uD0DD UI\uB294 TTY \uD658\uACBD\uC5D0\uC11C\uB9CC \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.");
|
|
373
800
|
helperTrace("show-selection:interactive:start");
|
|
374
801
|
let selectedIndex = 0;
|
|
375
802
|
const rl = readline__default.default.createInterface({
|
|
@@ -387,11 +814,12 @@ async function showSelectionAIService() {
|
|
|
387
814
|
helperTrace("show-selection:interactive:render", AIServices[selectedIndex] || "unknown");
|
|
388
815
|
readline__default.default.clearScreenDown(process.stdout);
|
|
389
816
|
process.stdout.write(
|
|
390
|
-
|
|
817
|
+
`\u{1F916} AI \uC11C\uBE44\uC2A4\uB97C \uC120\uD0DD\uD574\uC8FC\uC138\uC694 (${ANSI.yellow}\u2191\u2193 \uBC29\uD5A5\uD0A4${ANSI.reset} \uC774\uB3D9, ${ANSI.yellow}Enter${ANSI.reset} \uC120\uD0DD):
|
|
818
|
+
`
|
|
391
819
|
);
|
|
392
820
|
AIServices.forEach((service, index) => {
|
|
393
821
|
if (index === selectedIndex) {
|
|
394
|
-
process.stdout.write(`
|
|
822
|
+
process.stdout.write(` ${ANSI.cyan}>${ANSI.reset} ${ANSI.cyan}\u25C9${ANSI.reset} ${ANSI.bold}${service}${ANSI.reset}
|
|
395
823
|
`);
|
|
396
824
|
} else {
|
|
397
825
|
process.stdout.write(` \u25EF ${service}
|
|
@@ -421,7 +849,7 @@ async function showSelectionAIService() {
|
|
|
421
849
|
rl.close();
|
|
422
850
|
process.stdout.write("\x1B[?25h");
|
|
423
851
|
console.log(`
|
|
424
|
-
\u2705
|
|
852
|
+
\u2705 ${ANSI.green}${AIServices[selectedIndex]}${ANSI.reset} \uC11C\uBE44\uC2A4\uAC00 \uC120\uD0DD\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
|
|
425
853
|
`);
|
|
426
854
|
const result = AIServices[selectedIndex];
|
|
427
855
|
if (result) {
|
|
@@ -441,6 +869,13 @@ var ALLOWED_REASONING_EFFORTS = ["minimal", "low", "medium", "high"];
|
|
|
441
869
|
function shellQuote(value) {
|
|
442
870
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
443
871
|
}
|
|
872
|
+
function toShellOptionToken(value) {
|
|
873
|
+
const SIMPLE_SHELL_TOKEN_PATTERN = /^[A-Za-z0-9._:/=-]+$/;
|
|
874
|
+
if (SIMPLE_SHELL_TOKEN_PATTERN.test(value)) {
|
|
875
|
+
return value;
|
|
876
|
+
}
|
|
877
|
+
return shellQuote(value);
|
|
878
|
+
}
|
|
444
879
|
function getArgValue(flag) {
|
|
445
880
|
const index = args.indexOf(flag);
|
|
446
881
|
if (index === -1 || !args[index + 1]) {
|
|
@@ -448,6 +883,11 @@ function getArgValue(flag) {
|
|
|
448
883
|
}
|
|
449
884
|
return args[index + 1];
|
|
450
885
|
}
|
|
886
|
+
function printNotice(message) {
|
|
887
|
+
if (args.includes("--test")) {
|
|
888
|
+
console.warn(message);
|
|
889
|
+
}
|
|
890
|
+
}
|
|
451
891
|
function toUnique(values) {
|
|
452
892
|
const seen = /* @__PURE__ */ new Set();
|
|
453
893
|
return values.filter((value) => {
|
|
@@ -471,11 +911,11 @@ function resolveReasoningEffort() {
|
|
|
471
911
|
const normalized = normalizeEffort(customReasoningEffort);
|
|
472
912
|
trace("reasoning:custom", `${customReasoningEffort} -> ${normalized}`);
|
|
473
913
|
if (customReasoningEffort === "minimal") {
|
|
474
|
-
|
|
914
|
+
printNotice("\u26A0\uFE0F Claude\uB294 minimal\uC744 \uC9C1\uC811 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC544 low\uB85C \uB9E4\uD551\uD569\uB2C8\uB2E4.");
|
|
475
915
|
}
|
|
476
916
|
return normalized;
|
|
477
917
|
}
|
|
478
|
-
|
|
918
|
+
printNotice(
|
|
479
919
|
`\u26A0\uFE0F \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 reasoning effort(${customReasoningEffort})\uC785\uB2C8\uB2E4. allowed: ${ALLOWED_REASONING_EFFORTS.join(
|
|
480
920
|
", "
|
|
481
921
|
)}`
|
|
@@ -515,10 +955,10 @@ function getAliasFallbacks(primaryAlias) {
|
|
|
515
955
|
}
|
|
516
956
|
function buildClaudeExecCommand(options) {
|
|
517
957
|
const { tempDiffPath: tempDiffPath2, prompt, systemPromptFiles, effort, model, fallbackModel } = options;
|
|
518
|
-
const modelOption = model ? `--model ${
|
|
519
|
-
const fallbackOption = model && fallbackModel ? `--fallback-model ${
|
|
520
|
-
const effortOption = `--effort ${
|
|
521
|
-
const appendedPromptFiles = systemPromptFiles.map((
|
|
958
|
+
const modelOption = model ? `--model ${toShellOptionToken(model)}` : "";
|
|
959
|
+
const fallbackOption = model && fallbackModel ? `--fallback-model ${toShellOptionToken(fallbackModel)}` : "";
|
|
960
|
+
const effortOption = `--effort ${toShellOptionToken(effort)}`;
|
|
961
|
+
const appendedPromptFiles = systemPromptFiles.map((path3) => `--append-system-prompt-file ${shellQuote(path3)}`).join(" ");
|
|
522
962
|
return `cat ${shellQuote(tempDiffPath2)} | claude ${[
|
|
523
963
|
modelOption,
|
|
524
964
|
fallbackOption,
|
|
@@ -551,13 +991,13 @@ var createClaudeCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
|
551
991
|
trace("model:candidates", modelCandidates.join(", "));
|
|
552
992
|
trace("command:candidates:count", String(modelCandidates.length + 1));
|
|
553
993
|
if (customModel) {
|
|
554
|
-
|
|
994
|
+
printNotice(
|
|
555
995
|
`\u26A0\uFE0F \uCEE4\uC2A4\uD140 \uBAA8\uB378(${customModel})\uC744 \uC6B0\uC120 \uC2DC\uB3C4\uD558\uACE0 \uC2E4\uD328\uD558\uBA74 alias(${aliasFallbacks.join(
|
|
556
996
|
" -> "
|
|
557
997
|
)}) \uBC0F \uAE30\uBCF8 \uBAA8\uB378 \uC21C\uC73C\uB85C \uD3F4\uBC31\uD569\uB2C8\uB2E4.`
|
|
558
998
|
);
|
|
559
999
|
} else {
|
|
560
|
-
|
|
1000
|
+
printNotice(
|
|
561
1001
|
`\u26A0\uFE0F \uBAA8\uB378\uC774 \uC9C0\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. alias(${aliasFallbacks.join(" -> ")})\uB97C \uC21C\uCC28 \uC2DC\uB3C4\uD558\uACE0 \uB9C8\uC9C0\uB9C9\uC5D0 \uAE30\uBCF8 \uBAA8\uB378\uB85C \uD3F4\uBC31\uD569\uB2C8\uB2E4.`
|
|
562
1002
|
);
|
|
563
1003
|
}
|
|
@@ -637,22 +1077,37 @@ function getArgValue2(flag) {
|
|
|
637
1077
|
}
|
|
638
1078
|
return args2[index + 1];
|
|
639
1079
|
}
|
|
1080
|
+
function printNotice2(message) {
|
|
1081
|
+
if (args2.includes("--test")) {
|
|
1082
|
+
console.warn(message);
|
|
1083
|
+
}
|
|
1084
|
+
}
|
|
1085
|
+
function normalizeEffort2(level) {
|
|
1086
|
+
if (level === "minimal") {
|
|
1087
|
+
return "low";
|
|
1088
|
+
}
|
|
1089
|
+
return level;
|
|
1090
|
+
}
|
|
640
1091
|
function resolveReasoningEffort2() {
|
|
641
1092
|
const customReasoningEffort = getArgValue2("--reasoning-effort");
|
|
642
1093
|
if (customReasoningEffort) {
|
|
643
1094
|
if (ALLOWED_REASONING_EFFORTS2.includes(customReasoningEffort)) {
|
|
644
|
-
|
|
645
|
-
|
|
1095
|
+
const normalized = normalizeEffort2(customReasoningEffort);
|
|
1096
|
+
trace3("reasoning:custom", `${customReasoningEffort} -> ${normalized}`);
|
|
1097
|
+
if (customReasoningEffort === "minimal") {
|
|
1098
|
+
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.");
|
|
1099
|
+
}
|
|
1100
|
+
return normalized;
|
|
646
1101
|
}
|
|
647
|
-
|
|
1102
|
+
printNotice2(
|
|
648
1103
|
`\u26A0\uFE0F \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 reasoning effort(${customReasoningEffort})\uC785\uB2C8\uB2E4. allowed: ${ALLOWED_REASONING_EFFORTS2.join(
|
|
649
1104
|
", "
|
|
650
1105
|
)}`
|
|
651
1106
|
);
|
|
652
1107
|
}
|
|
653
1108
|
if (args2.includes("--flash")) {
|
|
654
|
-
trace3("reasoning:flash-default", "
|
|
655
|
-
return "
|
|
1109
|
+
trace3("reasoning:flash-default", "low");
|
|
1110
|
+
return "low";
|
|
656
1111
|
}
|
|
657
1112
|
if (args2.includes("--review")) {
|
|
658
1113
|
trace3("reasoning:review-default", "high");
|
|
@@ -688,14 +1143,14 @@ ${reviewFormLine || "- (\uC5C6\uC74C)"}
|
|
|
688
1143
|
trace3("prompt:prepared", `length=${prompt.length}`);
|
|
689
1144
|
let command = "";
|
|
690
1145
|
if (customModel) {
|
|
691
|
-
|
|
1146
|
+
printNotice2("\u26A0\uFE0F \uC9C0\uC815\uD55C \uBAA8\uB378\uC774 \uC5C6\uB294 \uACBD\uC6B0, \uC5D0\uB7EC\uAC00 \uBC1C\uC0DD\uD558\uB2C8 \uC8FC\uC758\uD558\uC138\uC694.");
|
|
692
1147
|
trace3("model:custom", customModel);
|
|
693
1148
|
command = buildCodexExecCommand(prompt, reasoningEffort, customModel);
|
|
694
1149
|
} else {
|
|
695
1150
|
const preferredModelAlias = "gpt-5";
|
|
696
1151
|
const aliasCommand = buildCodexExecCommand(prompt, reasoningEffort, preferredModelAlias);
|
|
697
1152
|
const fallbackCommand = buildCodexExecCommand(prompt, reasoningEffort);
|
|
698
|
-
|
|
1153
|
+
printNotice2(
|
|
699
1154
|
`\u26A0\uFE0F \uBAA8\uB378\uC774 \uC9C0\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. alias(${preferredModelAlias})\uB97C \uC6B0\uC120 \uC2DC\uB3C4\uD558\uACE0 \uC2E4\uD328\uD558\uBA74 \uACC4\uC815 \uAE30\uBCF8 \uBAA8\uB378\uB85C \uC790\uB3D9 \uD3F4\uBC31\uD569\uB2C8\uB2E4.`
|
|
700
1155
|
);
|
|
701
1156
|
trace3("model:alias-first", preferredModelAlias);
|
|
@@ -756,6 +1211,11 @@ function getArgValue3(flag) {
|
|
|
756
1211
|
}
|
|
757
1212
|
return args3[index + 1];
|
|
758
1213
|
}
|
|
1214
|
+
function printNotice3(message) {
|
|
1215
|
+
if (args3.includes("--test")) {
|
|
1216
|
+
console.warn(message);
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
759
1219
|
function toUnique2(values) {
|
|
760
1220
|
const seen = /* @__PURE__ */ new Set();
|
|
761
1221
|
return values.filter((value) => {
|
|
@@ -773,7 +1233,7 @@ function resolveReasoningEffort3() {
|
|
|
773
1233
|
trace5("reasoning:custom", customReasoningEffort);
|
|
774
1234
|
return customReasoningEffort;
|
|
775
1235
|
}
|
|
776
|
-
|
|
1236
|
+
printNotice3(
|
|
777
1237
|
`\u26A0\uFE0F \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 reasoning effort(${customReasoningEffort})\uC785\uB2C8\uB2E4. allowed: ${ALLOWED_REASONING_EFFORTS3.join(
|
|
778
1238
|
", "
|
|
779
1239
|
)}`
|
|
@@ -835,38 +1295,57 @@ function buildGeminiExecCommand(prompt, model) {
|
|
|
835
1295
|
const modelOption = model ? `--model ${shellQuote3(model)}` : "";
|
|
836
1296
|
return `gemini ${[modelOption, "-p", shellQuote3(prompt)].filter(Boolean).join(" ")}`;
|
|
837
1297
|
}
|
|
1298
|
+
function toGeminiFileReference(filePath) {
|
|
1299
|
+
return `@${filePath}`;
|
|
1300
|
+
}
|
|
1301
|
+
function buildGeminiFileReferenceSection(files) {
|
|
1302
|
+
const existingFiles = files.filter((file) => fs__default.default.existsSync(file.path));
|
|
1303
|
+
return {
|
|
1304
|
+
count: existingFiles.length,
|
|
1305
|
+
items: existingFiles.map((file) => `${file.display} ${toGeminiFileReference(file.path)}`)
|
|
1306
|
+
};
|
|
1307
|
+
}
|
|
838
1308
|
var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
839
1309
|
trace5("createGeminiCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
|
|
840
1310
|
const customModel = getArgValue3("--model");
|
|
841
1311
|
const reasoningEffort = resolveReasoningEffort3();
|
|
842
1312
|
const primaryAlias = resolvePrimaryAlias2(reasoningEffort);
|
|
843
1313
|
const aliasFallbacks = toUnique2(getAliasFallbacks2(primaryAlias));
|
|
1314
|
+
const resolvedTempDiffPath = path__default.default.resolve(tempDiffPath2);
|
|
1315
|
+
const resolvedReviewFormPath = path__default.default.resolve(reviewFormPath2);
|
|
844
1316
|
const rules = [
|
|
845
1317
|
{ path: rulesPath, display: "\uB8F0\uC14B" },
|
|
846
1318
|
{ path: namingRulesPath, display: "\uB124\uC774\uBC0D \uADDC\uCE59" },
|
|
847
1319
|
{ path: codingConventionRulesPath, display: "\uCF54\uB529 \uCEE8\uBCA4\uC158" }
|
|
848
1320
|
];
|
|
849
|
-
const
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
const
|
|
853
|
-
trace5("reviewForm:status",
|
|
1321
|
+
const ruleSection = buildGeminiFileReferenceSection(rules);
|
|
1322
|
+
trace5("rules:loaded", `count=${ruleSection.count}`);
|
|
1323
|
+
const reviewFormExists = fs__default.default.existsSync(resolvedReviewFormPath);
|
|
1324
|
+
const reviewFormText = reviewFormExists ? `\uB9AC\uBDF0 \uC591\uC2DD ${toGeminiFileReference(resolvedReviewFormPath)}` : "\uB9AC\uBDF0 \uC591\uC2DD (\uC5C6\uC74C)";
|
|
1325
|
+
trace5("reviewForm:status", reviewFormExists ? "exists" : "missing");
|
|
854
1326
|
const reasoningInstruction = getReasoningInstruction(reasoningEffort);
|
|
855
|
-
const
|
|
856
|
-
|
|
857
|
-
|
|
1327
|
+
const ruleText = ruleSection.items.join(" ") || "(\uC5C6\uC74C)";
|
|
1328
|
+
const diffText = `\uB9AC\uBDF0 \uB300\uC0C1 diff ${toGeminiFileReference(resolvedTempDiffPath)}`;
|
|
1329
|
+
const prompt = [
|
|
1330
|
+
"\uC544\uB798 \uD30C\uC77C\uB4E4\uC744 \uC21C\uC11C\uB300\uB85C \uC77D\uACE0 \uCF54\uB4DC \uB9AC\uBDF0\uB97C \uC9C4\uD589\uD574\uC918.",
|
|
1331
|
+
`\uADDC\uCE59 \uD30C\uC77C: ${ruleText}`,
|
|
1332
|
+
`\uB9AC\uBDF0 \uC591\uC2DD \uD30C\uC77C: ${reviewFormText}`,
|
|
1333
|
+
`\uB9AC\uBDF0 \uB300\uC0C1 diff \uD30C\uC77C: ${diffText}`,
|
|
1334
|
+
"\uBC18\uB4DC\uC2DC \uB9AC\uBDF0 \uC591\uC2DD\uC5D0 \uB9DE\uCDB0 \uC791\uC131\uD574\uC918.",
|
|
1335
|
+
`\uCD94\uB860 \uAC15\uB3C4 \uC9C0\uCE68: ${reasoningInstruction}`
|
|
1336
|
+
].join(" ");
|
|
858
1337
|
trace5("prompt:prepared", `length=${prompt.length}`);
|
|
859
1338
|
const modelCandidates = toUnique2(customModel ? [customModel, ...aliasFallbacks] : aliasFallbacks);
|
|
860
1339
|
trace5("model:candidates", modelCandidates.join(", "));
|
|
861
1340
|
trace5("command:candidates:count", String(modelCandidates.length + 1));
|
|
862
1341
|
if (customModel) {
|
|
863
|
-
|
|
1342
|
+
printNotice3(
|
|
864
1343
|
`\u26A0\uFE0F \uCEE4\uC2A4\uD140 \uBAA8\uB378(${customModel})\uC744 \uC6B0\uC120 \uC2DC\uB3C4\uD558\uACE0 \uC2E4\uD328\uD558\uBA74 alias(${aliasFallbacks.join(
|
|
865
1344
|
" -> "
|
|
866
1345
|
)}) \uBC0F \uAE30\uBCF8 \uBAA8\uB378 \uC21C\uC73C\uB85C \uD3F4\uBC31\uD569\uB2C8\uB2E4.`
|
|
867
1346
|
);
|
|
868
1347
|
} else {
|
|
869
|
-
|
|
1348
|
+
printNotice3(
|
|
870
1349
|
`\u26A0\uFE0F \uBAA8\uB378\uC774 \uC9C0\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. alias(${aliasFallbacks.join(" -> ")})\uB97C \uC21C\uCC28 \uC2DC\uB3C4\uD558\uACE0 \uB9C8\uC9C0\uB9C9\uC5D0 \uAE30\uBCF8 \uBAA8\uB378\uB85C \uD3F4\uBC31\uD569\uB2C8\uB2E4.`
|
|
871
1350
|
);
|
|
872
1351
|
}
|
|
@@ -918,6 +1397,7 @@ function checkGeminiCliInstalled() {
|
|
|
918
1397
|
var execAsync = util__default.default.promisify(child_process.exec);
|
|
919
1398
|
async function main() {
|
|
920
1399
|
const args4 = process.argv.slice(2);
|
|
1400
|
+
const startedAt = /* @__PURE__ */ new Date();
|
|
921
1401
|
clearTraceMessages();
|
|
922
1402
|
const isTest = isTestMode(args4);
|
|
923
1403
|
const trace7 = createTraceLogger("review-one-by-one", args4);
|
|
@@ -925,6 +1405,14 @@ async function main() {
|
|
|
925
1405
|
let service = "";
|
|
926
1406
|
let savedDiffPath = "";
|
|
927
1407
|
let savedReportPath = "";
|
|
1408
|
+
let selectedCommitSummary = "";
|
|
1409
|
+
let fileList = [];
|
|
1410
|
+
let executionLogPath = "";
|
|
1411
|
+
let executionStatus = "cancelled";
|
|
1412
|
+
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.";
|
|
1413
|
+
let executionError = null;
|
|
1414
|
+
let exitCode = 0;
|
|
1415
|
+
const fileExecutionLogs = [];
|
|
928
1416
|
try {
|
|
929
1417
|
trace7("service-selection:start");
|
|
930
1418
|
service = await showSelectionAIService();
|
|
@@ -948,29 +1436,37 @@ async function main() {
|
|
|
948
1436
|
}
|
|
949
1437
|
trace7("review-flow:start");
|
|
950
1438
|
console.log("\u{1F680} AI Code Review\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4...");
|
|
951
|
-
trace7("
|
|
952
|
-
|
|
953
|
-
trace7("
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
1439
|
+
trace7("commit-selection:start");
|
|
1440
|
+
const selectedCommits = await selectReviewCommits();
|
|
1441
|
+
trace7("commit-selection:done", `count=${selectedCommits.length}`);
|
|
1442
|
+
if (selectedCommits.length === 0) {
|
|
1443
|
+
trace7("commit-selection:empty");
|
|
1444
|
+
executionTitle = "\uC120\uD0DD\uB41C \uCEE4\uBC0B\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.";
|
|
1445
|
+
console.log("\u2139\uFE0F \uC120\uD0DD\uB41C \uCEE4\uBC0B\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
1446
|
+
deleteTempDiff();
|
|
1447
|
+
return;
|
|
1448
|
+
}
|
|
1449
|
+
selectedCommitSummary = buildSelectedCommitSummary(selectedCommits);
|
|
1450
|
+
trace7("commit-summary:prepared", selectedCommitSummary);
|
|
1451
|
+
console.log("\u23F3 \uC120\uD0DD\uD55C \uCEE4\uBC0B\uC758 \uD30C\uC77C \uBAA9\uB85D\uACFC diff\uB97C \uC815\uB9AC\uD558\uB294 \uC911\uC785\uB2C8\uB2E4...");
|
|
1452
|
+
trace7("files-command:run");
|
|
1453
|
+
fileList = getSelectedCommitFiles(selectedCommits);
|
|
962
1454
|
trace7("files-command:done", `fileCount=${fileList.length}`);
|
|
1455
|
+
console.log(`\u{1F4C2} \uB9AC\uBDF0 \uB300\uC0C1 \uD30C\uC77C(${fileList.length}\uAC1C): ${formatReviewTargetFiles(fileList)}`);
|
|
963
1456
|
if (fileList.length === 0) {
|
|
964
1457
|
trace7("empty-file-list:exit");
|
|
965
|
-
|
|
1458
|
+
executionTitle = "\uC120\uD0DD\uD55C \uCEE4\uBC0B\uC5D0\uC11C \uB9AC\uBDF0 \uB300\uC0C1 \uD30C\uC77C \uBCC0\uACBD\uC744 \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.";
|
|
1459
|
+
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.");
|
|
966
1460
|
deleteTempDiff();
|
|
967
|
-
|
|
1461
|
+
return;
|
|
968
1462
|
}
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
1463
|
+
trace7("report-dir:create:start");
|
|
1464
|
+
createReportDirectory();
|
|
1465
|
+
trace7("report-dir:create:done");
|
|
1466
|
+
trace7("full-diff:build:start");
|
|
1467
|
+
const fullDiff = buildSelectedCommitDiff(selectedCommits);
|
|
972
1468
|
const nowStr = getNowString();
|
|
973
|
-
trace7("full-diff:done", `length=${fullDiff.length}`);
|
|
1469
|
+
trace7("full-diff:build:done", `length=${fullDiff.length}`);
|
|
974
1470
|
trace7("timestamp:created", nowStr);
|
|
975
1471
|
trace7("temp-diff:write:start", tempDiffPath);
|
|
976
1472
|
fs__default.default.writeFileSync(tempDiffPath, fullDiff);
|
|
@@ -981,15 +1477,28 @@ async function main() {
|
|
|
981
1477
|
trace7("saved-diff:copy:done", savedDiffPath);
|
|
982
1478
|
savedReportPath = getNextFilePath(REPORT_DIR, nowStr, ".md");
|
|
983
1479
|
trace7("saved-report:path", savedReportPath);
|
|
984
|
-
const promises = fileList.map(async (file) => {
|
|
1480
|
+
const promises = fileList.map(async (file, index) => {
|
|
985
1481
|
const tempOneFileDiffPath = `temp_diff_${file.replace(/\//g, "_")}.txt`;
|
|
986
1482
|
let command = "";
|
|
987
1483
|
try {
|
|
988
1484
|
trace7("file-review:start", file);
|
|
989
|
-
console.log(`\u{1F50D}
|
|
990
|
-
trace7("file-diff:
|
|
991
|
-
const fileDiff =
|
|
992
|
-
trace7("file-diff:done", `${file} | length=${fileDiff.length}`);
|
|
1485
|
+
console.log(`\u{1F50D} [${index + 1}/${fileList.length}] \uB9AC\uBDF0 \uC900\uBE44: ${file}`);
|
|
1486
|
+
trace7("file-diff:build:start", file);
|
|
1487
|
+
const fileDiff = buildSelectedFileDiff(selectedCommits, file);
|
|
1488
|
+
trace7("file-diff:build:done", `${file} | length=${fileDiff.length}`);
|
|
1489
|
+
if (!fileDiff.trim()) {
|
|
1490
|
+
trace7("file-diff:empty", file);
|
|
1491
|
+
fileExecutionLogs.push({
|
|
1492
|
+
command: null,
|
|
1493
|
+
errorSummary: null,
|
|
1494
|
+
file,
|
|
1495
|
+
index,
|
|
1496
|
+
resultLength: 0,
|
|
1497
|
+
status: "skipped",
|
|
1498
|
+
tempOneFileDiffPath
|
|
1499
|
+
});
|
|
1500
|
+
return;
|
|
1501
|
+
}
|
|
993
1502
|
trace7("file-temp-diff:write:start", tempOneFileDiffPath);
|
|
994
1503
|
fs__default.default.writeFileSync(tempOneFileDiffPath, fileDiff);
|
|
995
1504
|
trace7("file-temp-diff:write:done", tempOneFileDiffPath);
|
|
@@ -1006,6 +1515,7 @@ async function main() {
|
|
|
1006
1515
|
break;
|
|
1007
1516
|
}
|
|
1008
1517
|
trace7("file-command:create:done", `${file} | commandLength=${command.length}`);
|
|
1518
|
+
console.log(`\u23F3 [${index + 1}/${fileList.length}] \uB9AC\uBDF0 \uC9C4\uD589: ${file}`);
|
|
1009
1519
|
trace7("file-command:exec:start", file);
|
|
1010
1520
|
const { stdout } = await execAsync(command, { maxBuffer: 1024 * 1024 * 20 });
|
|
1011
1521
|
const result = stdout.toString();
|
|
@@ -1017,7 +1527,6 @@ async function main() {
|
|
|
1017
1527
|
${result}
|
|
1018
1528
|
|
|
1019
1529
|
`;
|
|
1020
|
-
console.log(tempReport);
|
|
1021
1530
|
trace7("file-report:append:start", file);
|
|
1022
1531
|
fs__default.default.appendFileSync(savedReportPath, tempReport);
|
|
1023
1532
|
trace7("file-report:append:done", file);
|
|
@@ -1030,9 +1539,27 @@ ${result}
|
|
|
1030
1539
|
${command}`);
|
|
1031
1540
|
trace7("file-test-command:append:done", file);
|
|
1032
1541
|
}
|
|
1542
|
+
fileExecutionLogs.push({
|
|
1543
|
+
command,
|
|
1544
|
+
errorSummary: null,
|
|
1545
|
+
file,
|
|
1546
|
+
index,
|
|
1547
|
+
resultLength: result.length,
|
|
1548
|
+
status: "success",
|
|
1549
|
+
tempOneFileDiffPath
|
|
1550
|
+
});
|
|
1033
1551
|
trace7("file-review:end", file);
|
|
1034
1552
|
} catch (err) {
|
|
1035
1553
|
trace7("file-review:catch", `${file} | ${getErrorSummary(err)}`);
|
|
1554
|
+
fileExecutionLogs.push({
|
|
1555
|
+
command: command || null,
|
|
1556
|
+
errorSummary: getErrorSummary(err),
|
|
1557
|
+
file,
|
|
1558
|
+
index,
|
|
1559
|
+
resultLength: 0,
|
|
1560
|
+
status: "failed",
|
|
1561
|
+
tempOneFileDiffPath
|
|
1562
|
+
});
|
|
1036
1563
|
const errorLogPath = writeErrorReport(err, {
|
|
1037
1564
|
scope: "review-one-by-one:file",
|
|
1038
1565
|
args: args4,
|
|
@@ -1043,6 +1570,7 @@ ${command}`);
|
|
|
1043
1570
|
${JSON.stringify(
|
|
1044
1571
|
{
|
|
1045
1572
|
service,
|
|
1573
|
+
selectedCommitSummary: selectedCommitSummary || null,
|
|
1046
1574
|
file,
|
|
1047
1575
|
command: command || null,
|
|
1048
1576
|
tempOneFileDiffPath,
|
|
@@ -1083,6 +1611,15 @@ ${getErrorSummary(err)}
|
|
|
1083
1611
|
trace7("parallel-review:await-start");
|
|
1084
1612
|
await Promise.all(promises);
|
|
1085
1613
|
trace7("parallel-review:await-done");
|
|
1614
|
+
const failedFileCount = fileExecutionLogs.filter((log) => log.status === "failed").length;
|
|
1615
|
+
const successfulFileCount = fileExecutionLogs.filter((log) => log.status === "success").length;
|
|
1616
|
+
if (failedFileCount > 0) {
|
|
1617
|
+
executionStatus = "partial_failure";
|
|
1618
|
+
executionTitle = `\uD30C\uC77C\uBCC4 \uB9AC\uBDF0 \uC911 \uC77C\uBD80\uAC00 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4. (\uC131\uACF5 ${successfulFileCount}\uAC74 / \uC2E4\uD328 ${failedFileCount}\uAC74)`;
|
|
1619
|
+
} else {
|
|
1620
|
+
executionStatus = "success";
|
|
1621
|
+
executionTitle = "\uD30C\uC77C\uBCC4 \uB9AC\uBDF0\uAC00 \uC131\uACF5\uC801\uC73C\uB85C \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.";
|
|
1622
|
+
}
|
|
1086
1623
|
console.log(`
|
|
1087
1624
|
\u2705 \uB9AC\uBDF0\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`);
|
|
1088
1625
|
console.log(`\u{1F4C4} \uB9AC\uD3EC\uD2B8 \uC800\uC7A5 \uC704\uCE58: ${savedReportPath}`);
|
|
@@ -1097,6 +1634,10 @@ ${getErrorSummary(err)}
|
|
|
1097
1634
|
} catch (error) {
|
|
1098
1635
|
trace7("review-flow:catch", getErrorSummary(error));
|
|
1099
1636
|
let errorReportPath = "";
|
|
1637
|
+
executionStatus = "failed";
|
|
1638
|
+
executionTitle = "\uD30C\uC77C\uBCC4 \uB9AC\uBDF0 \uC2E4\uD589 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.";
|
|
1639
|
+
executionError = error;
|
|
1640
|
+
exitCode = 1;
|
|
1100
1641
|
trace7("cleanup-temp-diff:start(catch)");
|
|
1101
1642
|
try {
|
|
1102
1643
|
deleteTempDiff();
|
|
@@ -1117,6 +1658,7 @@ ${getErrorSummary(err)}
|
|
|
1117
1658
|
${JSON.stringify(
|
|
1118
1659
|
{
|
|
1119
1660
|
service: service || null,
|
|
1661
|
+
selectedCommitSummary: selectedCommitSummary || null,
|
|
1120
1662
|
tempDiffPath,
|
|
1121
1663
|
savedDiffPath: savedDiffPath || null,
|
|
1122
1664
|
savedReportPath: savedReportPath || null
|
|
@@ -1133,7 +1675,58 @@ ${JSON.stringify(
|
|
|
1133
1675
|
if (errorReportPath) {
|
|
1134
1676
|
console.error(`\u{1F4C4} \uC5D0\uB7EC \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${errorReportPath}`);
|
|
1135
1677
|
}
|
|
1136
|
-
|
|
1678
|
+
} finally {
|
|
1679
|
+
executionLogPath = writeExecutionLog({
|
|
1680
|
+
scope: "review-one-by-one",
|
|
1681
|
+
status: executionStatus,
|
|
1682
|
+
title: executionTitle,
|
|
1683
|
+
args: args4,
|
|
1684
|
+
startedAt,
|
|
1685
|
+
error: executionError,
|
|
1686
|
+
extraSections: [
|
|
1687
|
+
{
|
|
1688
|
+
heading: "Execution Context",
|
|
1689
|
+
markdown: `\`\`\`json
|
|
1690
|
+
${JSON.stringify(
|
|
1691
|
+
{
|
|
1692
|
+
service: service || null,
|
|
1693
|
+
selectedCommitSummary: selectedCommitSummary || null,
|
|
1694
|
+
fileList,
|
|
1695
|
+
tempDiffPath,
|
|
1696
|
+
savedDiffPath: savedDiffPath || null,
|
|
1697
|
+
savedReportPath: savedReportPath || null
|
|
1698
|
+
},
|
|
1699
|
+
null,
|
|
1700
|
+
2
|
|
1701
|
+
)}
|
|
1702
|
+
\`\`\``
|
|
1703
|
+
},
|
|
1704
|
+
{
|
|
1705
|
+
heading: "Generated Commands",
|
|
1706
|
+
markdown: `\`\`\`json
|
|
1707
|
+
${JSON.stringify(
|
|
1708
|
+
fileExecutionLogs.slice().sort((left, right) => left.index - right.index).map((log) => ({
|
|
1709
|
+
file: log.file,
|
|
1710
|
+
status: log.status,
|
|
1711
|
+
resultLength: log.resultLength,
|
|
1712
|
+
errorSummary: log.errorSummary,
|
|
1713
|
+
tempOneFileDiffPath: log.tempOneFileDiffPath,
|
|
1714
|
+
command: log.command
|
|
1715
|
+
})),
|
|
1716
|
+
null,
|
|
1717
|
+
2
|
|
1718
|
+
)}
|
|
1719
|
+
\`\`\``
|
|
1720
|
+
}
|
|
1721
|
+
]
|
|
1722
|
+
});
|
|
1723
|
+
if (executionLogPath) {
|
|
1724
|
+
const writeLog = executionStatus === "failed" ? console.error : console.log;
|
|
1725
|
+
writeLog(`\u{1F4DD} \uC2E4\uD589 \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${executionLogPath}`);
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
if (exitCode !== 0) {
|
|
1729
|
+
process.exit(exitCode);
|
|
1137
1730
|
}
|
|
1138
1731
|
}
|
|
1139
1732
|
main();
|