sales-frontend-gemini-cli 0.4.1 → 0.4.2
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 +226 -32
- package/dist/common/helper.cjs.map +1 -1
- package/dist/common/helper.d.cts +22 -2
- package/dist/common/helper.d.ts +22 -2
- package/dist/common/helper.js +220 -33
- package/dist/common/helper.js.map +1 -1
- package/dist/pr-review/claude/claude-commander.cjs +8 -1
- package/dist/pr-review/claude/claude-commander.cjs.map +1 -1
- package/dist/pr-review/claude/claude-commander.js +8 -1
- package/dist/pr-review/claude/claude-commander.js.map +1 -1
- package/dist/pr-review/claude/installation-claude.cjs +178 -8
- package/dist/pr-review/claude/installation-claude.cjs.map +1 -1
- package/dist/pr-review/claude/installation-claude.js +177 -8
- package/dist/pr-review/claude/installation-claude.js.map +1 -1
- package/dist/pr-review/codex/codex-commander.cjs +6 -1
- package/dist/pr-review/codex/codex-commander.cjs.map +1 -1
- package/dist/pr-review/codex/codex-commander.js +6 -1
- package/dist/pr-review/codex/codex-commander.js.map +1 -1
- package/dist/pr-review/codex/installation-codex.cjs +178 -8
- package/dist/pr-review/codex/installation-codex.cjs.map +1 -1
- package/dist/pr-review/codex/installation-codex.js +177 -8
- package/dist/pr-review/codex/installation-codex.js.map +1 -1
- package/dist/pr-review/gemini/gemini-commander.cjs +7 -1
- package/dist/pr-review/gemini/gemini-commander.cjs.map +1 -1
- package/dist/pr-review/gemini/gemini-commander.js +7 -1
- package/dist/pr-review/gemini/gemini-commander.js.map +1 -1
- package/dist/pr-review/gemini/installation-gemini.cjs +178 -8
- package/dist/pr-review/gemini/installation-gemini.cjs.map +1 -1
- package/dist/pr-review/gemini/installation-gemini.js +177 -8
- package/dist/pr-review/gemini/installation-gemini.js.map +1 -1
- package/dist/pr-review/review-one-by-one.cjs +368 -108
- package/dist/pr-review/review-one-by-one.cjs.map +1 -1
- package/dist/pr-review/review-one-by-one.js +368 -108
- package/dist/pr-review/review-one-by-one.js.map +1 -1
- package/dist/pr-review/review.cjs +316 -80
- package/dist/pr-review/review.cjs.map +1 -1
- package/dist/pr-review/review.js +316 -80
- package/dist/pr-review/review.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { exec, execSync } from 'child_process';
|
|
3
|
-
import
|
|
4
|
-
import util from 'util';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import util, { inspect } from 'util';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import readline from 'readline';
|
|
7
7
|
import { fileURLToPath } from 'url';
|
|
8
8
|
|
|
9
9
|
var __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
10
|
+
var traceMessages = [];
|
|
10
11
|
var rulesPath = path.resolve(__dirname, "../../src/common/rules/review-rules.md");
|
|
11
12
|
var namingRulesPath = path.resolve(__dirname, "../../src/common/rules/naming-rule.md");
|
|
12
13
|
var codingConventionRulesPath = path.resolve(__dirname, "../../src/common/rules/coding-convention.md");
|
|
@@ -29,66 +30,226 @@ var ignoreList = [
|
|
|
29
30
|
".review-report/"
|
|
30
31
|
// 생성되는 리포트 폴더도 제외
|
|
31
32
|
];
|
|
32
|
-
function parseServiceFromArgs(args4 = process.argv.slice(2)) {
|
|
33
|
-
const serviceIndex = args4.indexOf("--service");
|
|
34
|
-
const rawService = serviceIndex !== -1 ? args4[serviceIndex + 1] : "";
|
|
35
|
-
if (!rawService) {
|
|
36
|
-
return "";
|
|
37
|
-
}
|
|
38
|
-
const normalizedService = rawService.toLowerCase();
|
|
39
|
-
if (AIServices.includes(normalizedService)) {
|
|
40
|
-
return normalizedService;
|
|
41
|
-
}
|
|
42
|
-
console.error(
|
|
43
|
-
`\u274C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uC11C\uBE44\uC2A4\uC785\uB2C8\uB2E4: ${rawService}. \uC0AC\uC6A9 \uAC00\uB2A5 \uAC12: ${AIServices.join(", ")} (\uC608: --service codex)`
|
|
44
|
-
);
|
|
45
|
-
process.exit(1);
|
|
46
|
-
}
|
|
47
33
|
function isTestMode(args4 = process.argv.slice(2)) {
|
|
48
34
|
return args4.includes("--test");
|
|
49
35
|
}
|
|
36
|
+
function clearTraceMessages() {
|
|
37
|
+
traceMessages.length = 0;
|
|
38
|
+
}
|
|
39
|
+
function getTraceMessages() {
|
|
40
|
+
return [...traceMessages];
|
|
41
|
+
}
|
|
50
42
|
function createTraceLogger(scope, args4 = process.argv.slice(2)) {
|
|
51
43
|
const enabled = isTestMode(args4);
|
|
52
44
|
return (step, detail) => {
|
|
45
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
46
|
+
const message = `[${timestamp}][TRACE][${scope}] ${step}${detail ? ` | ${detail}` : ""}`;
|
|
47
|
+
traceMessages.push(message);
|
|
53
48
|
if (!enabled) {
|
|
54
49
|
return;
|
|
55
50
|
}
|
|
56
|
-
console.log(
|
|
51
|
+
console.log(message);
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
var helperTrace = createTraceLogger("helper");
|
|
55
|
+
function getTimestampParts(now = /* @__PURE__ */ new Date()) {
|
|
56
|
+
return {
|
|
57
|
+
YYYY: now.getFullYear(),
|
|
58
|
+
MM: String(now.getMonth() + 1).padStart(2, "0"),
|
|
59
|
+
DD: String(now.getDate()).padStart(2, "0"),
|
|
60
|
+
HH: String(now.getHours()).padStart(2, "0"),
|
|
61
|
+
mm: String(now.getMinutes()).padStart(2, "0"),
|
|
62
|
+
ss: String(now.getSeconds()).padStart(2, "0")
|
|
57
63
|
};
|
|
58
64
|
}
|
|
65
|
+
function getHumanReadableNowString(now = /* @__PURE__ */ new Date()) {
|
|
66
|
+
const { YYYY, MM, DD, HH, mm, ss } = getTimestampParts(now);
|
|
67
|
+
return `${YYYY}-${MM}-${DD} ${HH}:${mm}:${ss}`;
|
|
68
|
+
}
|
|
69
|
+
function stringifyUnknown(value) {
|
|
70
|
+
if (value === void 0 || value === null) {
|
|
71
|
+
return "";
|
|
72
|
+
}
|
|
73
|
+
if (typeof value === "string") {
|
|
74
|
+
return value;
|
|
75
|
+
}
|
|
76
|
+
if (Buffer.isBuffer(value)) {
|
|
77
|
+
return value.toString();
|
|
78
|
+
}
|
|
79
|
+
if (value instanceof Error) {
|
|
80
|
+
return value.stack || value.message;
|
|
81
|
+
}
|
|
82
|
+
return inspect(value, { depth: 5, breakLength: 120 });
|
|
83
|
+
}
|
|
84
|
+
function getErrorSummary(error) {
|
|
85
|
+
if (error instanceof Error) {
|
|
86
|
+
return `${error.name}: ${error.message}`;
|
|
87
|
+
}
|
|
88
|
+
return stringifyUnknown(error) || "Unknown error";
|
|
89
|
+
}
|
|
90
|
+
function serializeError(error) {
|
|
91
|
+
const serialized = {
|
|
92
|
+
summary: getErrorSummary(error)
|
|
93
|
+
};
|
|
94
|
+
if (error instanceof Error) {
|
|
95
|
+
serialized.name = error.name;
|
|
96
|
+
serialized.message = error.message;
|
|
97
|
+
serialized.stack = error.stack;
|
|
98
|
+
} else {
|
|
99
|
+
serialized.value = stringifyUnknown(error);
|
|
100
|
+
}
|
|
101
|
+
if (error && typeof error === "object") {
|
|
102
|
+
const errorLike = error;
|
|
103
|
+
const extraKeys = ["code", "errno", "syscall", "path", "cmd", "status", "signal", "spawnargs"];
|
|
104
|
+
extraKeys.forEach((key) => {
|
|
105
|
+
if (errorLike[key] !== void 0) {
|
|
106
|
+
serialized[key] = errorLike[key];
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
const stdout = stringifyUnknown(errorLike.stdout);
|
|
110
|
+
if (stdout) {
|
|
111
|
+
serialized.stdout = stdout;
|
|
112
|
+
}
|
|
113
|
+
const stderr = stringifyUnknown(errorLike.stderr);
|
|
114
|
+
if (stderr) {
|
|
115
|
+
serialized.stderr = stderr;
|
|
116
|
+
}
|
|
117
|
+
const cause = stringifyUnknown(errorLike.cause);
|
|
118
|
+
if (cause) {
|
|
119
|
+
serialized.cause = cause;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return serialized;
|
|
123
|
+
}
|
|
59
124
|
function getNextFilePath(dir, baseName, extension) {
|
|
60
125
|
let counter = 1;
|
|
61
126
|
while (true) {
|
|
62
127
|
const filePath = path.join(dir, `${baseName}-${counter}${extension}`);
|
|
63
|
-
if (!
|
|
128
|
+
if (!fs.existsSync(filePath)) {
|
|
64
129
|
return filePath;
|
|
65
130
|
}
|
|
66
131
|
counter++;
|
|
67
132
|
}
|
|
68
133
|
}
|
|
134
|
+
function getAvailableFilePath(dir, baseName, extension) {
|
|
135
|
+
const firstFilePath = path.join(dir, `${baseName}${extension}`);
|
|
136
|
+
if (!fs.existsSync(firstFilePath)) {
|
|
137
|
+
return firstFilePath;
|
|
138
|
+
}
|
|
139
|
+
return getNextFilePath(dir, baseName, extension);
|
|
140
|
+
}
|
|
69
141
|
function deleteFile(filePath) {
|
|
70
|
-
if (
|
|
71
|
-
|
|
142
|
+
if (fs.existsSync(filePath)) {
|
|
143
|
+
fs.unlinkSync(filePath);
|
|
72
144
|
}
|
|
73
145
|
}
|
|
74
146
|
function deleteTempDiff() {
|
|
75
147
|
deleteFile(tempDiffPath);
|
|
76
148
|
}
|
|
77
149
|
function createReportDirectory() {
|
|
78
|
-
if (!
|
|
79
|
-
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
function getNowString() {
|
|
83
|
-
const
|
|
84
|
-
const YYYY = now.getFullYear();
|
|
85
|
-
const MM = String(now.getMonth() + 1).padStart(2, "0");
|
|
86
|
-
const DD = String(now.getDate()).padStart(2, "0");
|
|
87
|
-
const HH = String(now.getHours()).padStart(2, "0");
|
|
88
|
-
const mm = String(now.getMinutes()).padStart(2, "0");
|
|
89
|
-
const ss = String(now.getSeconds()).padStart(2, "0");
|
|
150
|
+
if (!fs.existsSync(REPORT_DIR)) {
|
|
151
|
+
fs.mkdirSync(REPORT_DIR, { recursive: true });
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function getNowString(now = /* @__PURE__ */ new Date()) {
|
|
155
|
+
const { YYYY, MM, DD, HH, mm, ss } = getTimestampParts(now);
|
|
90
156
|
return `${YYYY}-${MM}-${DD}_${HH}-${mm}-${ss}`;
|
|
91
157
|
}
|
|
158
|
+
function getErrorLogTimestamp(now = /* @__PURE__ */ new Date()) {
|
|
159
|
+
const { YYYY, MM, DD, HH, mm, ss } = getTimestampParts(now);
|
|
160
|
+
return `${YYYY}-${MM}-${DD}-${HH}\uC2DC-${mm}\uBD84-${ss}\uCD08`;
|
|
161
|
+
}
|
|
162
|
+
function writeErrorReport(error, options = {}) {
|
|
163
|
+
try {
|
|
164
|
+
const now = /* @__PURE__ */ new Date();
|
|
165
|
+
helperTrace("error-report:write:start", options.scope || "unknown");
|
|
166
|
+
createReportDirectory();
|
|
167
|
+
const reportPath = getAvailableFilePath(REPORT_DIR, `error-log-${getErrorLogTimestamp(now)}`, ".md");
|
|
168
|
+
const serializedError = serializeError(error);
|
|
169
|
+
const traceSnapshot = options.traceMessages ?? getTraceMessages();
|
|
170
|
+
const extraSections = options.extraSections || [];
|
|
171
|
+
const report = `# Error Log
|
|
172
|
+
|
|
173
|
+
- \uBC1C\uC0DD \uC2DC\uAC01: ${getHumanReadableNowString(now)}
|
|
174
|
+
- Scope: \`${options.scope || "unknown"}\`
|
|
175
|
+
- \uC791\uC5C5 \uACBD\uB85C: \`${process.cwd()}\`
|
|
176
|
+
- \uC2E4\uD589 \uC778\uC790: \`${JSON.stringify(options.args ?? process.argv.slice(2))}\`
|
|
177
|
+
- \uC2E4\uD589 \uD658\uACBD: \`${process.platform} ${process.arch} / Node ${process.version}\`
|
|
178
|
+
|
|
179
|
+
## Summary
|
|
180
|
+
|
|
181
|
+
${options.title || serializedError.summary || "Unknown error"}
|
|
182
|
+
|
|
183
|
+
## Error
|
|
184
|
+
|
|
185
|
+
\`\`\`json
|
|
186
|
+
${JSON.stringify(serializedError, null, 2)}
|
|
187
|
+
\`\`\`
|
|
188
|
+
|
|
189
|
+
## Trace
|
|
190
|
+
|
|
191
|
+
\`\`\`json
|
|
192
|
+
${JSON.stringify(traceSnapshot, null, 2)}
|
|
193
|
+
\`\`\`${extraSections.length ? `
|
|
194
|
+
${extraSections.map((section) => `
|
|
195
|
+
## ${section.heading}
|
|
196
|
+
|
|
197
|
+
${section.markdown}`).join("\n")}
|
|
198
|
+
` : "\n"}
|
|
199
|
+
`;
|
|
200
|
+
fs.writeFileSync(reportPath, report);
|
|
201
|
+
helperTrace("error-report:write:done", reportPath);
|
|
202
|
+
return reportPath;
|
|
203
|
+
} catch (writeError) {
|
|
204
|
+
console.error("\u26A0\uFE0F \uC5D0\uB7EC \uB85C\uADF8 \uD30C\uC77C \uC0DD\uC131\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
|
|
205
|
+
console.error(writeError);
|
|
206
|
+
return "";
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
function exitWithError(message, options = {}) {
|
|
210
|
+
const reportPath = writeErrorReport(options.error || new Error(message), {
|
|
211
|
+
...options,
|
|
212
|
+
title: message
|
|
213
|
+
});
|
|
214
|
+
console.error(message);
|
|
215
|
+
if (options.error) {
|
|
216
|
+
console.error(options.error);
|
|
217
|
+
}
|
|
218
|
+
if (reportPath) {
|
|
219
|
+
console.error(`\u{1F4C4} \uC5D0\uB7EC \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${reportPath}`);
|
|
220
|
+
}
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
function parseServiceFromArgs(args4 = process.argv.slice(2)) {
|
|
224
|
+
helperTrace("parse-service:start", `args=${JSON.stringify(args4)}`);
|
|
225
|
+
const serviceIndex = args4.indexOf("--service");
|
|
226
|
+
const rawService = serviceIndex !== -1 ? args4[serviceIndex + 1] : "";
|
|
227
|
+
if (!rawService) {
|
|
228
|
+
helperTrace("parse-service:empty");
|
|
229
|
+
return "";
|
|
230
|
+
}
|
|
231
|
+
const normalizedService = rawService.toLowerCase();
|
|
232
|
+
if (AIServices.includes(normalizedService)) {
|
|
233
|
+
helperTrace("parse-service:resolved", normalizedService);
|
|
234
|
+
return normalizedService;
|
|
235
|
+
}
|
|
236
|
+
helperTrace("parse-service:invalid", rawService);
|
|
237
|
+
exitWithError(
|
|
238
|
+
`\u274C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uC11C\uBE44\uC2A4\uC785\uB2C8\uB2E4: ${rawService}. \uC0AC\uC6A9 \uAC00\uB2A5 \uAC12: ${AIServices.join(", ")} (\uC608: --service codex)`,
|
|
239
|
+
{
|
|
240
|
+
scope: "helper:parseServiceFromArgs",
|
|
241
|
+
args: args4,
|
|
242
|
+
extraSections: [
|
|
243
|
+
{
|
|
244
|
+
heading: "Allowed Services",
|
|
245
|
+
markdown: `\`\`\`json
|
|
246
|
+
${JSON.stringify(AIServices, null, 2)}
|
|
247
|
+
\`\`\``
|
|
248
|
+
}
|
|
249
|
+
]
|
|
250
|
+
}
|
|
251
|
+
);
|
|
252
|
+
}
|
|
92
253
|
function getGitDiffFilter() {
|
|
93
254
|
const includeExtensions = ["*.ts", "*.tsx", "*.js", "*.jsx"];
|
|
94
255
|
const excludePatterns = ignoreList.map((item) => `:(exclude)${item}`);
|
|
@@ -100,6 +261,7 @@ function getGitDiffFilter() {
|
|
|
100
261
|
function openReport(reportPath) {
|
|
101
262
|
const resolvedPath = path.resolve(reportPath);
|
|
102
263
|
const { platform } = process;
|
|
264
|
+
helperTrace("open-report:start", resolvedPath);
|
|
103
265
|
const openWithChrome = () => {
|
|
104
266
|
if (platform === "darwin") {
|
|
105
267
|
execSync(`open -a "Google Chrome" "${resolvedPath}"`, { stdio: "ignore" });
|
|
@@ -124,32 +286,41 @@ function openReport(reportPath) {
|
|
|
124
286
|
};
|
|
125
287
|
try {
|
|
126
288
|
if (openWithChrome()) {
|
|
289
|
+
helperTrace("open-report:chrome:success", platform);
|
|
127
290
|
console.log("\u{1F680} Google Chrome\uC5D0\uC11C \uB9AC\uD3EC\uD2B8\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
128
291
|
return;
|
|
129
292
|
}
|
|
130
|
-
} catch {
|
|
293
|
+
} catch (error) {
|
|
294
|
+
helperTrace("open-report:chrome:failed", getErrorSummary(error));
|
|
131
295
|
}
|
|
132
296
|
try {
|
|
133
297
|
if (openWithDefaultBrowser()) {
|
|
298
|
+
helperTrace("open-report:default-browser:success", platform);
|
|
134
299
|
console.log("\u{1F680} \uAE30\uBCF8 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB9AC\uD3EC\uD2B8\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
135
300
|
return;
|
|
136
301
|
}
|
|
137
|
-
} catch (
|
|
138
|
-
|
|
302
|
+
} catch (error) {
|
|
303
|
+
helperTrace("open-report:default-browser:failed", getErrorSummary(error));
|
|
304
|
+
console.error("\u26A0\uFE0F \uBE0C\uB77C\uC6B0\uC800 \uC5F4\uAE30 \uC2E4\uD328:", error);
|
|
139
305
|
return;
|
|
140
306
|
}
|
|
307
|
+
helperTrace("open-report:unsupported-platform", platform);
|
|
141
308
|
console.error(`\u26A0\uFE0F \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD50C\uB7AB\uD3FC\uC785\uB2C8\uB2E4: ${platform}`);
|
|
142
309
|
}
|
|
143
310
|
function getDiffArgs() {
|
|
144
311
|
const args4 = process.argv.slice(2);
|
|
145
312
|
const commitIndex = args4.indexOf("--commit");
|
|
146
313
|
const { includeParams, excludeParams } = getGitDiffFilter();
|
|
314
|
+
helperTrace("diff-args:resolve:start", `args=${JSON.stringify(args4)}`);
|
|
147
315
|
let diffArgs = "";
|
|
148
316
|
if (commitIndex !== -1) {
|
|
149
317
|
const commitHash = args4[commitIndex + 1];
|
|
150
318
|
if (!commitHash) {
|
|
151
|
-
|
|
152
|
-
|
|
319
|
+
helperTrace("diff-args:commit-hash-missing");
|
|
320
|
+
exitWithError("\u274C \uCEE4\uBC0B \uD574\uC2DC\uAC00 \uC81C\uACF5\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.", {
|
|
321
|
+
scope: "helper:getDiffArgs",
|
|
322
|
+
args: args4
|
|
323
|
+
});
|
|
153
324
|
}
|
|
154
325
|
const nextArg = args4[commitIndex + 2];
|
|
155
326
|
let n = 0;
|
|
@@ -159,28 +330,37 @@ function getDiffArgs() {
|
|
|
159
330
|
n = 0;
|
|
160
331
|
}
|
|
161
332
|
}
|
|
333
|
+
helperTrace("diff-args:commit-mode", `${commitHash}~${n + 1} ${commitHash}`);
|
|
162
334
|
console.log(`\u2139\uFE0F \uCEE4\uBC0B '${commitHash}' ${n > 0 ? ` \uD3EC\uD568 \uCD1D ${n + 1}\uAC1C\uC758 \uCEE4\uBC0B` : ""}\uC744 \uB9AC\uBDF0\uD569\uB2C8\uB2E4...`);
|
|
163
335
|
diffArgs = `${commitHash}~${n + 1} ${commitHash}`;
|
|
164
336
|
} else {
|
|
165
337
|
try {
|
|
338
|
+
helperTrace("diff-args:unstaged-check:start");
|
|
166
339
|
const check = execSync(`git diff --name-only -- ${includeParams} ${excludeParams}`).toString();
|
|
167
340
|
if (!check.trim()) {
|
|
341
|
+
helperTrace("diff-args:unstaged-check:empty", "use HEAD~1 HEAD");
|
|
168
342
|
console.log("\u2139\uFE0F Unstaged \uBCC0\uACBD\uC0AC\uD56D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uB9C8\uC9C0\uB9C9 \uCEE4\uBC0B(HEAD)\uC744 \uB9AC\uBDF0\uD569\uB2C8\uB2E4...");
|
|
169
343
|
diffArgs = "HEAD~1 HEAD";
|
|
344
|
+
} else {
|
|
345
|
+
helperTrace("diff-args:unstaged-check:has-changes", `length=${check.length}`);
|
|
170
346
|
}
|
|
171
|
-
} catch {
|
|
347
|
+
} catch (error) {
|
|
348
|
+
helperTrace("diff-args:unstaged-check:failed", getErrorSummary(error));
|
|
172
349
|
}
|
|
173
350
|
}
|
|
351
|
+
helperTrace("diff-args:resolve:done", diffArgs || "(default)");
|
|
174
352
|
return diffArgs;
|
|
175
353
|
}
|
|
176
354
|
async function showSelectionAIService() {
|
|
177
355
|
const selectedServiceFromArgs = parseServiceFromArgs();
|
|
178
356
|
if (selectedServiceFromArgs) {
|
|
357
|
+
helperTrace("show-selection:from-args", selectedServiceFromArgs);
|
|
179
358
|
console.log(`
|
|
180
359
|
\u2705 \x1B[32m${selectedServiceFromArgs}\x1B[0m \uC11C\uBE44\uC2A4\uAC00 \uC120\uD0DD\uB418\uC5C8\uC2B5\uB2C8\uB2E4. (--service)
|
|
181
360
|
`);
|
|
182
361
|
return selectedServiceFromArgs;
|
|
183
362
|
}
|
|
363
|
+
helperTrace("show-selection:interactive:start");
|
|
184
364
|
let selectedIndex = 0;
|
|
185
365
|
const rl = readline.createInterface({
|
|
186
366
|
input: process.stdin,
|
|
@@ -194,6 +374,7 @@ async function showSelectionAIService() {
|
|
|
194
374
|
readline.moveCursor(process.stdout, 0, -(AIServices.length + 1));
|
|
195
375
|
}
|
|
196
376
|
firstRender = false;
|
|
377
|
+
helperTrace("show-selection:interactive:render", AIServices[selectedIndex] || "unknown");
|
|
197
378
|
readline.clearScreenDown(process.stdout);
|
|
198
379
|
process.stdout.write(
|
|
199
380
|
"\u{1F916} AI \uC11C\uBE44\uC2A4\uB97C \uC120\uD0DD\uD574\uC8FC\uC138\uC694 (\x1B[33m\u2191\u2193 \uBC29\uD5A5\uD0A4\x1B[0m \uC774\uB3D9, \x1B[33mEnter\x1B[0m \uC120\uD0DD):\n"
|
|
@@ -213,6 +394,7 @@ async function showSelectionAIService() {
|
|
|
213
394
|
const onData = (data) => {
|
|
214
395
|
const key = data.toString();
|
|
215
396
|
if (key === "") {
|
|
397
|
+
helperTrace("show-selection:interactive:ctrl-c");
|
|
216
398
|
process.stdout.write("\x1B[?25h");
|
|
217
399
|
process.exit(0);
|
|
218
400
|
}
|
|
@@ -233,6 +415,7 @@ async function showSelectionAIService() {
|
|
|
233
415
|
`);
|
|
234
416
|
const result = AIServices[selectedIndex];
|
|
235
417
|
if (result) {
|
|
418
|
+
helperTrace("show-selection:interactive:confirmed", result);
|
|
236
419
|
resolve(result);
|
|
237
420
|
}
|
|
238
421
|
}
|
|
@@ -346,14 +529,17 @@ var createClaudeCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
|
346
529
|
{ path: namingRulesPath, display: "\uB124\uC774\uBC0D \uADDC\uCE59" },
|
|
347
530
|
{ path: codingConventionRulesPath, display: "\uCF54\uB529 \uCEE8\uBCA4\uC158" }
|
|
348
531
|
];
|
|
349
|
-
const existingRuleFiles = rules.filter((rule) =>
|
|
532
|
+
const existingRuleFiles = rules.filter((rule) => fs.existsSync(rule.path)).map((rule) => rule.path);
|
|
350
533
|
trace("rules:loaded", `count=${existingRuleFiles.length}`);
|
|
351
|
-
const reviewFormExists =
|
|
534
|
+
const reviewFormExists = fs.existsSync(reviewFormPath2);
|
|
352
535
|
trace("reviewForm:status", reviewFormExists ? "exists" : "missing");
|
|
353
536
|
const systemPromptFiles = reviewFormExists ? [...existingRuleFiles, reviewFormPath2] : existingRuleFiles;
|
|
354
537
|
const prompt = "\uC704 \uADDC\uCE59\uB4E4\uC744 \uCC38\uACE0\uD558\uC5EC \uC774 diff\uB97C \uCF54\uB4DC\uB9AC\uBDF0\uD574\uC918. \uB9AC\uBDF0\uC591\uC2DD\uC5D0 \uB9DE\uCDB0\uC11C \uC791\uC131\uD574\uC918.";
|
|
538
|
+
trace("prompt:prepared", `length=${prompt.length}`);
|
|
539
|
+
trace("system-prompt-files", `count=${systemPromptFiles.length}`);
|
|
355
540
|
const modelCandidates = toUnique(customModel ? [customModel, ...aliasFallbacks] : aliasFallbacks);
|
|
356
541
|
trace("model:candidates", modelCandidates.join(", "));
|
|
542
|
+
trace("command:candidates:count", String(modelCandidates.length + 1));
|
|
357
543
|
if (customModel) {
|
|
358
544
|
console.warn(
|
|
359
545
|
`\u26A0\uFE0F \uCEE4\uC2A4\uD140 \uBAA8\uB378(${customModel})\uC744 \uC6B0\uC120 \uC2DC\uB3C4\uD558\uACE0 \uC2E4\uD328\uD558\uBA74 alias(${aliasFallbacks.join(
|
|
@@ -394,6 +580,7 @@ var createClaudeCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
|
394
580
|
\uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
|
|
395
581
|
${safeCommand}"`;
|
|
396
582
|
}
|
|
583
|
+
trace("command:mode", "execute");
|
|
397
584
|
trace("createClaudeCommand:end");
|
|
398
585
|
return command;
|
|
399
586
|
};
|
|
@@ -404,23 +591,25 @@ function checkClaudeCliInstalled() {
|
|
|
404
591
|
trace2("version-check:run", "claude --version");
|
|
405
592
|
execSync("claude --version", { stdio: "ignore" });
|
|
406
593
|
trace2("version-check:ok");
|
|
407
|
-
} catch {
|
|
408
|
-
trace2("version-check:failed",
|
|
594
|
+
} catch (error) {
|
|
595
|
+
trace2("version-check:failed", getErrorSummary(error));
|
|
596
|
+
trace2("install:start", "@anthropic-ai/claude-code");
|
|
409
597
|
console.log(
|
|
410
598
|
"\u2139\uFE0F claude-cli\uAC00 \uC124\uCE58\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC124\uCE58\uB97C \uC9C4\uD589\uD569\uB2C8\uB2E4... npm install -g @anthropic-ai/claude-code"
|
|
411
599
|
);
|
|
412
600
|
try {
|
|
413
601
|
execSync("npm install -g @anthropic-ai/claude-code", { stdio: "inherit" });
|
|
414
|
-
trace2("install:ok", "
|
|
602
|
+
trace2("install:ok", "login-required");
|
|
415
603
|
console.log("\u2705 claude-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
416
604
|
console.log("\u26A0\uFE0F claude-cli \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
417
605
|
console.log(' \uD130\uBBF8\uB110\uC5D0\uC11C "claude" \uB97C \uC785\uB825\uD558\uC5EC \uBE0C\uB77C\uC6B0\uC800 \uB85C\uADF8\uC778\uC744 \uC644\uB8CC\uD55C \uD6C4, \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.');
|
|
418
606
|
process.exit(1);
|
|
419
607
|
} catch (installError) {
|
|
420
|
-
trace2("install:failed");
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
608
|
+
trace2("install:failed", getErrorSummary(installError));
|
|
609
|
+
exitWithError("\u274C claude-cli \uC124\uCE58 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4. \uAD8C\uD55C \uBB38\uC81C\uC77C \uC218 \uC788\uC2B5\uB2C8\uB2E4 (sudo \uD544\uC694).", {
|
|
610
|
+
scope: "installation-claude",
|
|
611
|
+
error: installError
|
|
612
|
+
});
|
|
424
613
|
}
|
|
425
614
|
}
|
|
426
615
|
trace2("checkClaudeCliInstalled:end");
|
|
@@ -471,10 +660,10 @@ var createCodexCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
|
471
660
|
trace3("createCodexCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
|
|
472
661
|
const customModel = getArgValue2("--model");
|
|
473
662
|
const reasoningEffort = resolveReasoningEffort2();
|
|
474
|
-
const rules = [rulesPath, namingRulesPath, codingConventionRulesPath].filter((filePath) =>
|
|
663
|
+
const rules = [rulesPath, namingRulesPath, codingConventionRulesPath].filter((filePath) => fs.existsSync(filePath)).map((filePath) => `- ${filePath}`).join("\n");
|
|
475
664
|
const rulesCount = rules ? rules.split("\n").length : 0;
|
|
476
665
|
trace3("rules:loaded", `count=${rulesCount}`);
|
|
477
|
-
const hasReviewForm =
|
|
666
|
+
const hasReviewForm = fs.existsSync(reviewFormPath2);
|
|
478
667
|
const reviewFormLine = hasReviewForm ? `- ${reviewFormPath2}` : "";
|
|
479
668
|
trace3("reviewForm:status", reviewFormLine ? "exists" : "missing");
|
|
480
669
|
const prompt = `\uC544\uB798 \uD30C\uC77C\uB4E4\uC744 \uCC38\uACE0\uD574\uC11C \uCF54\uB4DC \uB9AC\uBDF0\uB97C \uC9C4\uD589\uD574\uC918.
|
|
@@ -486,6 +675,7 @@ ${reviewFormLine || "- (\uC5C6\uC74C)"}
|
|
|
486
675
|
- ${tempDiffPath2}
|
|
487
676
|
|
|
488
677
|
\uBC18\uB4DC\uC2DC \uB9AC\uBDF0 \uC591\uC2DD\uC5D0 \uB9DE\uCDB0 \uC791\uC131\uD574\uC918.`;
|
|
678
|
+
trace3("prompt:prepared", `length=${prompt.length}`);
|
|
489
679
|
let command = "";
|
|
490
680
|
if (customModel) {
|
|
491
681
|
console.warn("\u26A0\uFE0F \uC9C0\uC815\uD55C \uBAA8\uB378\uC774 \uC5C6\uB294 \uACBD\uC6B0, \uC5D0\uB7EC\uAC00 \uBC1C\uC0DD\uD558\uB2C8 \uC8FC\uC758\uD558\uC138\uC694.");
|
|
@@ -511,6 +701,7 @@ ${reviewFormLine || "- (\uC5C6\uC74C)"}
|
|
|
511
701
|
\uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
|
|
512
702
|
${safeCommand}"`;
|
|
513
703
|
}
|
|
704
|
+
trace3("command:mode", "execute");
|
|
514
705
|
trace3("createCodexCommand:end");
|
|
515
706
|
return command;
|
|
516
707
|
};
|
|
@@ -521,21 +712,23 @@ function checkCodexCliInstalled() {
|
|
|
521
712
|
trace4("version-check:run", "codex --version");
|
|
522
713
|
execSync("codex --version", { stdio: "ignore" });
|
|
523
714
|
trace4("version-check:ok");
|
|
524
|
-
} catch {
|
|
525
|
-
trace4("version-check:failed",
|
|
715
|
+
} catch (error) {
|
|
716
|
+
trace4("version-check:failed", getErrorSummary(error));
|
|
717
|
+
trace4("install:start", "@openai/codex");
|
|
526
718
|
console.log("\u2139\uFE0F codex-cli\uAC00 \uC124\uCE58\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC124\uCE58\uB97C \uC9C4\uD589\uD569\uB2C8\uB2E4... npm install -g @openai/codex");
|
|
527
719
|
try {
|
|
528
720
|
execSync("npm install -g @openai/codex", { stdio: "inherit" });
|
|
529
|
-
trace4("install:ok", "
|
|
721
|
+
trace4("install:ok", "login-required");
|
|
530
722
|
console.log("\u2705 codex-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
531
723
|
console.log("\u26A0\uFE0F codex-cli \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
532
724
|
console.log(' \uD130\uBBF8\uB110\uC5D0\uC11C "codex login" \uC744 \uC785\uB825\uD558\uC5EC \uB85C\uADF8\uC778\uC744 \uC644\uB8CC\uD55C \uD6C4, \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.');
|
|
533
725
|
process.exit(1);
|
|
534
726
|
} catch (installError) {
|
|
535
|
-
trace4("install:failed");
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
727
|
+
trace4("install:failed", getErrorSummary(installError));
|
|
728
|
+
exitWithError("\u274C codex-cli \uC124\uCE58 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4. \uAD8C\uD55C \uBB38\uC81C\uC77C \uC218 \uC788\uC2B5\uB2C8\uB2E4 (sudo \uD544\uC694).", {
|
|
729
|
+
scope: "installation-codex",
|
|
730
|
+
error: installError
|
|
731
|
+
});
|
|
539
732
|
}
|
|
540
733
|
}
|
|
541
734
|
trace4("checkCodexCliInstalled:end");
|
|
@@ -643,17 +836,19 @@ var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
|
643
836
|
{ path: namingRulesPath, display: "\uB124\uC774\uBC0D \uADDC\uCE59" },
|
|
644
837
|
{ path: codingConventionRulesPath, display: "\uCF54\uB529 \uCEE8\uBCA4\uC158" }
|
|
645
838
|
];
|
|
646
|
-
const validRules = rules.filter((rule) =>
|
|
839
|
+
const validRules = rules.filter((rule) => fs.existsSync(rule.path)).map((rule) => `@${rule.path}`).join(", ");
|
|
647
840
|
const rulesCount = validRules ? validRules.split(",").length : 0;
|
|
648
841
|
trace5("rules:loaded", `count=${rulesCount}`);
|
|
649
|
-
const reviewFormRef =
|
|
842
|
+
const reviewFormRef = fs.existsSync(reviewFormPath2) ? `@${reviewFormPath2}` : "(\uC5C6\uC74C)";
|
|
650
843
|
trace5("reviewForm:status", reviewFormRef === "(\uC5C6\uC74C)" ? "missing" : "exists");
|
|
651
844
|
const reasoningInstruction = getReasoningInstruction(reasoningEffort);
|
|
652
845
|
const prompt = `\uB2E4\uC74C \uADDC\uCE59\uB4E4\uC744 \uCC38\uACE0\uD574\uC11C(${validRules || "(\uC5C6\uC74C)"}) \uC774 diff(@${tempDiffPath2})\uB97C \uB9AC\uBDF0\uD574\uC918.
|
|
653
846
|
\uB9AC\uBDF0 \uC591\uC2DD\uC740 ${reviewFormRef} \uC5D0 \uB9DE\uCDB0\uC11C \uC791\uC131\uD574\uC918.
|
|
654
847
|
\uCD94\uB860 \uAC15\uB3C4 \uC9C0\uCE68: ${reasoningInstruction}`;
|
|
848
|
+
trace5("prompt:prepared", `length=${prompt.length}`);
|
|
655
849
|
const modelCandidates = toUnique2(customModel ? [customModel, ...aliasFallbacks] : aliasFallbacks);
|
|
656
850
|
trace5("model:candidates", modelCandidates.join(", "));
|
|
851
|
+
trace5("command:candidates:count", String(modelCandidates.length + 1));
|
|
657
852
|
if (customModel) {
|
|
658
853
|
console.warn(
|
|
659
854
|
`\u26A0\uFE0F \uCEE4\uC2A4\uD140 \uBAA8\uB378(${customModel})\uC744 \uC6B0\uC120 \uC2DC\uB3C4\uD558\uACE0 \uC2E4\uD328\uD558\uBA74 alias(${aliasFallbacks.join(
|
|
@@ -676,6 +871,7 @@ var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
|
676
871
|
\uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
|
|
677
872
|
${safeCommand}"`;
|
|
678
873
|
}
|
|
874
|
+
trace5("command:mode", "execute");
|
|
679
875
|
trace5("createGeminiCommand:end");
|
|
680
876
|
return command;
|
|
681
877
|
};
|
|
@@ -686,21 +882,23 @@ function checkGeminiCliInstalled() {
|
|
|
686
882
|
trace6("version-check:run", "gemini --version");
|
|
687
883
|
execSync("gemini --version", { stdio: "ignore" });
|
|
688
884
|
trace6("version-check:ok");
|
|
689
|
-
} catch {
|
|
690
|
-
trace6("version-check:failed",
|
|
885
|
+
} catch (error) {
|
|
886
|
+
trace6("version-check:failed", getErrorSummary(error));
|
|
887
|
+
trace6("install:start", "@google/gemini-cli");
|
|
691
888
|
console.log("\u2139\uFE0F gemini-cli\uAC00 \uC124\uCE58\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC124\uCE58\uB97C \uC9C4\uD589\uD569\uB2C8\uB2E4... npm install -g @google/gemini-cli");
|
|
692
889
|
try {
|
|
693
890
|
execSync("npm install -g @google/gemini-cli", { stdio: "inherit" });
|
|
694
|
-
trace6("install:ok", "
|
|
891
|
+
trace6("install:ok", "login-required");
|
|
695
892
|
console.log("\u2705 gemini-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
696
893
|
console.log("\u26A0\uFE0F Gemini API \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
697
894
|
console.log(' \uD130\uBBF8\uB110\uC5D0\uC11C "gemini" \uB97C \uC785\uB825\uD558\uC5EC \uBE0C\uB77C\uC6B0\uC800 \uB85C\uADF8\uC778\uC744 \uC644\uB8CC\uD55C \uD6C4, \uB2E4\uC2DC \uC2DC\uB3C4\uD574\uC8FC\uC138\uC694.');
|
|
698
895
|
process.exit(1);
|
|
699
896
|
} catch (installError) {
|
|
700
|
-
trace6("install:failed");
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
897
|
+
trace6("install:failed", getErrorSummary(installError));
|
|
898
|
+
exitWithError("\u274C gemini-cli \uC124\uCE58 \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4. \uAD8C\uD55C \uBB38\uC81C\uC77C \uC218 \uC788\uC2B5\uB2C8\uB2E4 (sudo \uD544\uC694).", {
|
|
899
|
+
scope: "installation-gemini",
|
|
900
|
+
error: installError
|
|
901
|
+
});
|
|
704
902
|
}
|
|
705
903
|
}
|
|
706
904
|
trace6("checkGeminiCliInstalled:end");
|
|
@@ -710,30 +908,34 @@ function checkGeminiCliInstalled() {
|
|
|
710
908
|
var execAsync = util.promisify(exec);
|
|
711
909
|
async function main() {
|
|
712
910
|
const args4 = process.argv.slice(2);
|
|
911
|
+
clearTraceMessages();
|
|
713
912
|
const isTest = isTestMode(args4);
|
|
714
913
|
const trace7 = createTraceLogger("review-one-by-one", args4);
|
|
715
914
|
trace7("main:start", `args=${JSON.stringify(args4)}`);
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
switch (service) {
|
|
720
|
-
case "gemini":
|
|
721
|
-
trace7("install-check:start", "service=gemini");
|
|
722
|
-
checkGeminiCliInstalled();
|
|
723
|
-
trace7("install-check:done", "service=gemini");
|
|
724
|
-
break;
|
|
725
|
-
case "claude":
|
|
726
|
-
trace7("install-check:start", "service=claude");
|
|
727
|
-
checkClaudeCliInstalled();
|
|
728
|
-
trace7("install-check:done", "service=claude");
|
|
729
|
-
break;
|
|
730
|
-
case "codex":
|
|
731
|
-
trace7("install-check:start", "service=codex");
|
|
732
|
-
checkCodexCliInstalled();
|
|
733
|
-
trace7("install-check:done", "service=codex");
|
|
734
|
-
break;
|
|
735
|
-
}
|
|
915
|
+
let service = "";
|
|
916
|
+
let savedDiffPath = "";
|
|
917
|
+
let savedReportPath = "";
|
|
736
918
|
try {
|
|
919
|
+
trace7("service-selection:start");
|
|
920
|
+
service = await showSelectionAIService();
|
|
921
|
+
trace7("service-selection:done", `service=${service}`);
|
|
922
|
+
switch (service) {
|
|
923
|
+
case "gemini":
|
|
924
|
+
trace7("install-check:start", "service=gemini");
|
|
925
|
+
checkGeminiCliInstalled();
|
|
926
|
+
trace7("install-check:done", "service=gemini");
|
|
927
|
+
break;
|
|
928
|
+
case "claude":
|
|
929
|
+
trace7("install-check:start", "service=claude");
|
|
930
|
+
checkClaudeCliInstalled();
|
|
931
|
+
trace7("install-check:done", "service=claude");
|
|
932
|
+
break;
|
|
933
|
+
case "codex":
|
|
934
|
+
trace7("install-check:start", "service=codex");
|
|
935
|
+
checkCodexCliInstalled();
|
|
936
|
+
trace7("install-check:done", "service=codex");
|
|
937
|
+
break;
|
|
938
|
+
}
|
|
737
939
|
trace7("review-flow:start");
|
|
738
940
|
console.log("\u{1F680} AI Code Review\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4...");
|
|
739
941
|
trace7("report-dir:create:start");
|
|
@@ -741,6 +943,7 @@ async function main() {
|
|
|
741
943
|
trace7("report-dir:create:done");
|
|
742
944
|
const { includeParams, excludeParams } = getGitDiffFilter();
|
|
743
945
|
trace7("diff-filter:loaded", `include=${includeParams} | exclude=${excludeParams}`);
|
|
946
|
+
trace7("diff-args:build:start");
|
|
744
947
|
const diffArgs = getDiffArgs();
|
|
745
948
|
trace7("diff-args:build:done", `diffArgs=${diffArgs || "(default)"}`);
|
|
746
949
|
const filesCommand = `git diff --name-only ${diffArgs} -- ${includeParams} ${excludeParams}`;
|
|
@@ -760,26 +963,26 @@ async function main() {
|
|
|
760
963
|
trace7("full-diff:done", `length=${fullDiff.length}`);
|
|
761
964
|
trace7("timestamp:created", nowStr);
|
|
762
965
|
trace7("temp-diff:write:start", tempDiffPath);
|
|
763
|
-
|
|
966
|
+
fs.writeFileSync(tempDiffPath, fullDiff);
|
|
764
967
|
trace7("temp-diff:write:done");
|
|
765
968
|
trace7("saved-diff:copy:start");
|
|
766
|
-
|
|
767
|
-
|
|
969
|
+
savedDiffPath = getNextFilePath(REPORT_DIR, `${nowStr}-diff`, ".txt");
|
|
970
|
+
fs.copyFileSync(tempDiffPath, savedDiffPath);
|
|
768
971
|
trace7("saved-diff:copy:done", savedDiffPath);
|
|
769
|
-
|
|
972
|
+
savedReportPath = getNextFilePath(REPORT_DIR, nowStr, ".md");
|
|
770
973
|
trace7("saved-report:path", savedReportPath);
|
|
771
974
|
const promises = fileList.map(async (file) => {
|
|
975
|
+
const tempOneFileDiffPath = `temp_diff_${file.replace(/\//g, "_")}.txt`;
|
|
976
|
+
let command = "";
|
|
772
977
|
try {
|
|
773
978
|
trace7("file-review:start", file);
|
|
774
979
|
console.log(`\u{1F50D} Reviewing: ${file}...`);
|
|
775
980
|
trace7("file-diff:run", file);
|
|
776
981
|
const fileDiff = execSync(`git diff ${diffArgs} -- "${file}"`).toString();
|
|
777
982
|
trace7("file-diff:done", `${file} | length=${fileDiff.length}`);
|
|
778
|
-
const tempOneFileDiffPath = `temp_diff_${file.replace(/\//g, "_")}.txt`;
|
|
779
983
|
trace7("file-temp-diff:write:start", tempOneFileDiffPath);
|
|
780
|
-
|
|
984
|
+
fs.writeFileSync(tempOneFileDiffPath, fileDiff);
|
|
781
985
|
trace7("file-temp-diff:write:done", tempOneFileDiffPath);
|
|
782
|
-
let command = "";
|
|
783
986
|
trace7("file-command:create:start", file);
|
|
784
987
|
switch (service) {
|
|
785
988
|
case "gemini":
|
|
@@ -792,7 +995,7 @@ async function main() {
|
|
|
792
995
|
command = createCodexCommand(tempOneFileDiffPath, reviewFormOneByOnePath);
|
|
793
996
|
break;
|
|
794
997
|
}
|
|
795
|
-
trace7("file-command:create:done", file);
|
|
998
|
+
trace7("file-command:create:done", `${file} | commandLength=${command.length}`);
|
|
796
999
|
trace7("file-command:exec:start", file);
|
|
797
1000
|
const { stdout } = await execAsync(command, { maxBuffer: 1024 * 1024 * 20 });
|
|
798
1001
|
const result = stdout.toString();
|
|
@@ -806,11 +1009,11 @@ ${result}
|
|
|
806
1009
|
`;
|
|
807
1010
|
console.log(tempReport);
|
|
808
1011
|
trace7("file-report:append:start", file);
|
|
809
|
-
|
|
1012
|
+
fs.appendFileSync(savedReportPath, tempReport);
|
|
810
1013
|
trace7("file-report:append:done", file);
|
|
811
1014
|
if (isTest) {
|
|
812
1015
|
trace7("file-test-command:append:start", file);
|
|
813
|
-
|
|
1016
|
+
fs.appendFileSync(savedReportPath, `
|
|
814
1017
|
|
|
815
1018
|
## \uC0AC\uC6A9\uB41C \uBA85\uB839\uC5B4
|
|
816
1019
|
|
|
@@ -819,26 +1022,51 @@ ${command}`);
|
|
|
819
1022
|
}
|
|
820
1023
|
trace7("file-review:end", file);
|
|
821
1024
|
} catch (err) {
|
|
822
|
-
trace7("file-review:catch", file);
|
|
1025
|
+
trace7("file-review:catch", `${file} | ${getErrorSummary(err)}`);
|
|
1026
|
+
const errorLogPath = writeErrorReport(err, {
|
|
1027
|
+
scope: "review-one-by-one:file",
|
|
1028
|
+
args: args4,
|
|
1029
|
+
extraSections: [
|
|
1030
|
+
{
|
|
1031
|
+
heading: "Execution Context",
|
|
1032
|
+
markdown: `\`\`\`json
|
|
1033
|
+
${JSON.stringify(
|
|
1034
|
+
{
|
|
1035
|
+
service,
|
|
1036
|
+
file,
|
|
1037
|
+
command: command || null,
|
|
1038
|
+
tempOneFileDiffPath,
|
|
1039
|
+
savedDiffPath: savedDiffPath || null,
|
|
1040
|
+
savedReportPath: savedReportPath || null
|
|
1041
|
+
},
|
|
1042
|
+
null,
|
|
1043
|
+
2
|
|
1044
|
+
)}
|
|
1045
|
+
\`\`\``
|
|
1046
|
+
}
|
|
1047
|
+
]
|
|
1048
|
+
});
|
|
823
1049
|
console.error(`\u274C Error reviewing file ${file}:`, err);
|
|
1050
|
+
if (errorLogPath) {
|
|
1051
|
+
console.error(`\u{1F4C4} \uC5D0\uB7EC \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${errorLogPath}`);
|
|
1052
|
+
}
|
|
824
1053
|
const errorReport = `### File: ${file}
|
|
825
1054
|
\u274C Review Failed
|
|
826
1055
|
\`\`\`
|
|
827
|
-
${err}
|
|
1056
|
+
${getErrorSummary(err)}
|
|
828
1057
|
\`\`\`
|
|
829
1058
|
|
|
830
1059
|
`;
|
|
831
|
-
|
|
1060
|
+
fs.appendFileSync(savedReportPath, errorReport);
|
|
832
1061
|
try {
|
|
833
|
-
|
|
834
|
-
if (fs5.existsSync(tempOneFileDiffPath)) {
|
|
1062
|
+
if (fs.existsSync(tempOneFileDiffPath)) {
|
|
835
1063
|
trace7("file-temp-diff:delete:start(catch)", tempOneFileDiffPath);
|
|
836
1064
|
deleteFile(tempOneFileDiffPath);
|
|
837
1065
|
trace7("file-temp-diff:delete:done(catch)", tempOneFileDiffPath);
|
|
838
1066
|
}
|
|
839
|
-
} catch (
|
|
840
|
-
trace7("file-temp-diff:delete:failed(catch)", file);
|
|
841
|
-
console.error(`\u274C Error deleting temp file for ${file}:`,
|
|
1067
|
+
} catch (cleanupError) {
|
|
1068
|
+
trace7("file-temp-diff:delete:failed(catch)", `${file} | ${getErrorSummary(cleanupError)}`);
|
|
1069
|
+
console.error(`\u274C Error deleting temp file for ${file}:`, cleanupError);
|
|
842
1070
|
}
|
|
843
1071
|
}
|
|
844
1072
|
});
|
|
@@ -857,12 +1085,44 @@ ${err}
|
|
|
857
1085
|
trace7("cleanup-temp-diff:done");
|
|
858
1086
|
trace7("review-flow:end");
|
|
859
1087
|
} catch (error) {
|
|
860
|
-
trace7("review-flow:catch");
|
|
1088
|
+
trace7("review-flow:catch", getErrorSummary(error));
|
|
1089
|
+
let errorReportPath = "";
|
|
1090
|
+
trace7("cleanup-temp-diff:start(catch)");
|
|
1091
|
+
try {
|
|
1092
|
+
deleteTempDiff();
|
|
1093
|
+
trace7("cleanup-temp-diff:done(catch)");
|
|
1094
|
+
} catch (cleanupError) {
|
|
1095
|
+
trace7("cleanup-temp-diff:failed(catch)", getErrorSummary(cleanupError));
|
|
1096
|
+
console.error("\u26A0\uFE0F \uC784\uC2DC diff \uC815\uB9AC \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
|
|
1097
|
+
console.error(cleanupError);
|
|
1098
|
+
}
|
|
1099
|
+
trace7("error-report:prepare", `service=${service || "unknown"}`);
|
|
1100
|
+
errorReportPath = writeErrorReport(error, {
|
|
1101
|
+
scope: "review-one-by-one",
|
|
1102
|
+
args: args4,
|
|
1103
|
+
extraSections: [
|
|
1104
|
+
{
|
|
1105
|
+
heading: "Execution Context",
|
|
1106
|
+
markdown: `\`\`\`json
|
|
1107
|
+
${JSON.stringify(
|
|
1108
|
+
{
|
|
1109
|
+
service: service || null,
|
|
1110
|
+
tempDiffPath,
|
|
1111
|
+
savedDiffPath: savedDiffPath || null,
|
|
1112
|
+
savedReportPath: savedReportPath || null
|
|
1113
|
+
},
|
|
1114
|
+
null,
|
|
1115
|
+
2
|
|
1116
|
+
)}
|
|
1117
|
+
\`\`\``
|
|
1118
|
+
}
|
|
1119
|
+
]
|
|
1120
|
+
});
|
|
861
1121
|
console.error("\u274C \uB9AC\uBDF0 \uB3C4\uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
|
|
862
1122
|
console.error(error);
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
1123
|
+
if (errorReportPath) {
|
|
1124
|
+
console.error(`\u{1F4C4} \uC5D0\uB7EC \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${errorReportPath}`);
|
|
1125
|
+
}
|
|
866
1126
|
process.exit(1);
|
|
867
1127
|
}
|
|
868
1128
|
}
|