sales-frontend-gemini-cli 0.4.0 → 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 +234 -20
- package/dist/common/helper.cjs.map +1 -1
- package/dist/common/helper.d.cts +23 -3
- package/dist/common/helper.d.ts +23 -3
- package/dist/common/helper.js +228 -21
- package/dist/common/helper.js.map +1 -1
- package/dist/pr-review/claude/claude-commander.cjs +142 -28
- package/dist/pr-review/claude/claude-commander.cjs.map +1 -1
- package/dist/pr-review/claude/claude-commander.d.cts +7 -8
- package/dist/pr-review/claude/claude-commander.d.ts +7 -8
- package/dist/pr-review/claude/claude-commander.js +142 -28
- 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 +64 -21
- package/dist/pr-review/codex/codex-commander.cjs.map +1 -1
- package/dist/pr-review/codex/codex-commander.d.cts +8 -3
- package/dist/pr-review/codex/codex-commander.d.ts +8 -3
- package/dist/pr-review/codex/codex-commander.js +64 -21
- 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 +122 -21
- package/dist/pr-review/gemini/gemini-commander.cjs.map +1 -1
- package/dist/pr-review/gemini/gemini-commander.d.cts +10 -13
- package/dist/pr-review/gemini/gemini-commander.d.ts +10 -13
- package/dist/pr-review/gemini/gemini-commander.js +122 -21
- 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 +679 -157
- package/dist/pr-review/review-one-by-one.cjs.map +1 -1
- package/dist/pr-review/review-one-by-one.js +679 -157
- package/dist/pr-review/review-one-by-one.js.map +1 -1
- package/dist/pr-review/review.cjs +630 -132
- package/dist/pr-review/review.cjs.map +1 -1
- package/dist/pr-review/review.js +630 -132
- 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");
|
|
@@ -32,48 +33,223 @@ var ignoreList = [
|
|
|
32
33
|
function isTestMode(args4 = process.argv.slice(2)) {
|
|
33
34
|
return args4.includes("--test");
|
|
34
35
|
}
|
|
36
|
+
function clearTraceMessages() {
|
|
37
|
+
traceMessages.length = 0;
|
|
38
|
+
}
|
|
39
|
+
function getTraceMessages() {
|
|
40
|
+
return [...traceMessages];
|
|
41
|
+
}
|
|
35
42
|
function createTraceLogger(scope, args4 = process.argv.slice(2)) {
|
|
36
43
|
const enabled = isTestMode(args4);
|
|
37
44
|
return (step, detail) => {
|
|
45
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
46
|
+
const message = `[${timestamp}][TRACE][${scope}] ${step}${detail ? ` | ${detail}` : ""}`;
|
|
47
|
+
traceMessages.push(message);
|
|
38
48
|
if (!enabled) {
|
|
39
49
|
return;
|
|
40
50
|
}
|
|
41
|
-
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")
|
|
42
63
|
};
|
|
43
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
|
+
}
|
|
44
124
|
function getNextFilePath(dir, baseName, extension) {
|
|
45
125
|
let counter = 1;
|
|
46
126
|
while (true) {
|
|
47
127
|
const filePath = path.join(dir, `${baseName}-${counter}${extension}`);
|
|
48
|
-
if (!
|
|
128
|
+
if (!fs.existsSync(filePath)) {
|
|
49
129
|
return filePath;
|
|
50
130
|
}
|
|
51
131
|
counter++;
|
|
52
132
|
}
|
|
53
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
|
+
}
|
|
54
141
|
function deleteFile(filePath) {
|
|
55
|
-
if (
|
|
56
|
-
|
|
142
|
+
if (fs.existsSync(filePath)) {
|
|
143
|
+
fs.unlinkSync(filePath);
|
|
57
144
|
}
|
|
58
145
|
}
|
|
59
146
|
function deleteTempDiff() {
|
|
60
147
|
deleteFile(tempDiffPath);
|
|
61
148
|
}
|
|
62
149
|
function createReportDirectory() {
|
|
63
|
-
if (!
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
function getNowString() {
|
|
68
|
-
const
|
|
69
|
-
const YYYY = now.getFullYear();
|
|
70
|
-
const MM = String(now.getMonth() + 1).padStart(2, "0");
|
|
71
|
-
const DD = String(now.getDate()).padStart(2, "0");
|
|
72
|
-
const HH = String(now.getHours()).padStart(2, "0");
|
|
73
|
-
const mm = String(now.getMinutes()).padStart(2, "0");
|
|
74
|
-
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);
|
|
75
156
|
return `${YYYY}-${MM}-${DD}_${HH}-${mm}-${ss}`;
|
|
76
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
|
+
}
|
|
77
253
|
function getGitDiffFilter() {
|
|
78
254
|
const includeExtensions = ["*.ts", "*.tsx", "*.js", "*.jsx"];
|
|
79
255
|
const excludePatterns = ignoreList.map((item) => `:(exclude)${item}`);
|
|
@@ -85,6 +261,7 @@ function getGitDiffFilter() {
|
|
|
85
261
|
function openReport(reportPath) {
|
|
86
262
|
const resolvedPath = path.resolve(reportPath);
|
|
87
263
|
const { platform } = process;
|
|
264
|
+
helperTrace("open-report:start", resolvedPath);
|
|
88
265
|
const openWithChrome = () => {
|
|
89
266
|
if (platform === "darwin") {
|
|
90
267
|
execSync(`open -a "Google Chrome" "${resolvedPath}"`, { stdio: "ignore" });
|
|
@@ -109,32 +286,41 @@ function openReport(reportPath) {
|
|
|
109
286
|
};
|
|
110
287
|
try {
|
|
111
288
|
if (openWithChrome()) {
|
|
289
|
+
helperTrace("open-report:chrome:success", platform);
|
|
112
290
|
console.log("\u{1F680} Google Chrome\uC5D0\uC11C \uB9AC\uD3EC\uD2B8\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
113
291
|
return;
|
|
114
292
|
}
|
|
115
|
-
} catch {
|
|
293
|
+
} catch (error) {
|
|
294
|
+
helperTrace("open-report:chrome:failed", getErrorSummary(error));
|
|
116
295
|
}
|
|
117
296
|
try {
|
|
118
297
|
if (openWithDefaultBrowser()) {
|
|
298
|
+
helperTrace("open-report:default-browser:success", platform);
|
|
119
299
|
console.log("\u{1F680} \uAE30\uBCF8 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB9AC\uD3EC\uD2B8\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
120
300
|
return;
|
|
121
301
|
}
|
|
122
|
-
} catch (
|
|
123
|
-
|
|
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);
|
|
124
305
|
return;
|
|
125
306
|
}
|
|
307
|
+
helperTrace("open-report:unsupported-platform", platform);
|
|
126
308
|
console.error(`\u26A0\uFE0F \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD50C\uB7AB\uD3FC\uC785\uB2C8\uB2E4: ${platform}`);
|
|
127
309
|
}
|
|
128
310
|
function getDiffArgs() {
|
|
129
311
|
const args4 = process.argv.slice(2);
|
|
130
312
|
const commitIndex = args4.indexOf("--commit");
|
|
131
313
|
const { includeParams, excludeParams } = getGitDiffFilter();
|
|
314
|
+
helperTrace("diff-args:resolve:start", `args=${JSON.stringify(args4)}`);
|
|
132
315
|
let diffArgs = "";
|
|
133
316
|
if (commitIndex !== -1) {
|
|
134
317
|
const commitHash = args4[commitIndex + 1];
|
|
135
318
|
if (!commitHash) {
|
|
136
|
-
|
|
137
|
-
|
|
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
|
+
});
|
|
138
324
|
}
|
|
139
325
|
const nextArg = args4[commitIndex + 2];
|
|
140
326
|
let n = 0;
|
|
@@ -144,21 +330,37 @@ function getDiffArgs() {
|
|
|
144
330
|
n = 0;
|
|
145
331
|
}
|
|
146
332
|
}
|
|
333
|
+
helperTrace("diff-args:commit-mode", `${commitHash}~${n + 1} ${commitHash}`);
|
|
147
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...`);
|
|
148
335
|
diffArgs = `${commitHash}~${n + 1} ${commitHash}`;
|
|
149
336
|
} else {
|
|
150
337
|
try {
|
|
338
|
+
helperTrace("diff-args:unstaged-check:start");
|
|
151
339
|
const check = execSync(`git diff --name-only -- ${includeParams} ${excludeParams}`).toString();
|
|
152
340
|
if (!check.trim()) {
|
|
341
|
+
helperTrace("diff-args:unstaged-check:empty", "use HEAD~1 HEAD");
|
|
153
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...");
|
|
154
343
|
diffArgs = "HEAD~1 HEAD";
|
|
344
|
+
} else {
|
|
345
|
+
helperTrace("diff-args:unstaged-check:has-changes", `length=${check.length}`);
|
|
155
346
|
}
|
|
156
|
-
} catch {
|
|
347
|
+
} catch (error) {
|
|
348
|
+
helperTrace("diff-args:unstaged-check:failed", getErrorSummary(error));
|
|
157
349
|
}
|
|
158
350
|
}
|
|
351
|
+
helperTrace("diff-args:resolve:done", diffArgs || "(default)");
|
|
159
352
|
return diffArgs;
|
|
160
353
|
}
|
|
161
354
|
async function showSelectionAIService() {
|
|
355
|
+
const selectedServiceFromArgs = parseServiceFromArgs();
|
|
356
|
+
if (selectedServiceFromArgs) {
|
|
357
|
+
helperTrace("show-selection:from-args", selectedServiceFromArgs);
|
|
358
|
+
console.log(`
|
|
359
|
+
\u2705 \x1B[32m${selectedServiceFromArgs}\x1B[0m \uC11C\uBE44\uC2A4\uAC00 \uC120\uD0DD\uB418\uC5C8\uC2B5\uB2C8\uB2E4. (--service)
|
|
360
|
+
`);
|
|
361
|
+
return selectedServiceFromArgs;
|
|
362
|
+
}
|
|
363
|
+
helperTrace("show-selection:interactive:start");
|
|
162
364
|
let selectedIndex = 0;
|
|
163
365
|
const rl = readline.createInterface({
|
|
164
366
|
input: process.stdin,
|
|
@@ -172,6 +374,7 @@ async function showSelectionAIService() {
|
|
|
172
374
|
readline.moveCursor(process.stdout, 0, -(AIServices.length + 1));
|
|
173
375
|
}
|
|
174
376
|
firstRender = false;
|
|
377
|
+
helperTrace("show-selection:interactive:render", AIServices[selectedIndex] || "unknown");
|
|
175
378
|
readline.clearScreenDown(process.stdout);
|
|
176
379
|
process.stdout.write(
|
|
177
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"
|
|
@@ -191,6 +394,7 @@ async function showSelectionAIService() {
|
|
|
191
394
|
const onData = (data) => {
|
|
192
395
|
const key = data.toString();
|
|
193
396
|
if (key === "") {
|
|
397
|
+
helperTrace("show-selection:interactive:ctrl-c");
|
|
194
398
|
process.stdout.write("\x1B[?25h");
|
|
195
399
|
process.exit(0);
|
|
196
400
|
}
|
|
@@ -211,6 +415,7 @@ async function showSelectionAIService() {
|
|
|
211
415
|
`);
|
|
212
416
|
const result = AIServices[selectedIndex];
|
|
213
417
|
if (result) {
|
|
418
|
+
helperTrace("show-selection:interactive:confirmed", result);
|
|
214
419
|
resolve(result);
|
|
215
420
|
}
|
|
216
421
|
}
|
|
@@ -222,40 +427,150 @@ async function showSelectionAIService() {
|
|
|
222
427
|
}
|
|
223
428
|
var args = process.argv.slice(2);
|
|
224
429
|
var trace = createTraceLogger("claude-commander", args);
|
|
225
|
-
var
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
430
|
+
var ALLOWED_REASONING_EFFORTS = ["minimal", "low", "medium", "high"];
|
|
431
|
+
function shellQuote(value) {
|
|
432
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
433
|
+
}
|
|
434
|
+
function getArgValue(flag) {
|
|
435
|
+
const index = args.indexOf(flag);
|
|
436
|
+
if (index === -1 || !args[index + 1]) {
|
|
437
|
+
return "";
|
|
438
|
+
}
|
|
439
|
+
return args[index + 1];
|
|
440
|
+
}
|
|
441
|
+
function toUnique(values) {
|
|
442
|
+
const seen = /* @__PURE__ */ new Set();
|
|
443
|
+
return values.filter((value) => {
|
|
444
|
+
if (!value || seen.has(value)) {
|
|
445
|
+
return false;
|
|
446
|
+
}
|
|
447
|
+
seen.add(value);
|
|
448
|
+
return true;
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
function normalizeEffort(level) {
|
|
452
|
+
if (level === "minimal") {
|
|
453
|
+
return "low";
|
|
454
|
+
}
|
|
455
|
+
return level;
|
|
456
|
+
}
|
|
457
|
+
function resolveReasoningEffort() {
|
|
458
|
+
const customReasoningEffort = getArgValue("--reasoning-effort") || getArgValue("--effort");
|
|
459
|
+
if (customReasoningEffort) {
|
|
460
|
+
if (ALLOWED_REASONING_EFFORTS.includes(customReasoningEffort)) {
|
|
461
|
+
const normalized = normalizeEffort(customReasoningEffort);
|
|
462
|
+
trace("reasoning:custom", `${customReasoningEffort} -> ${normalized}`);
|
|
463
|
+
if (customReasoningEffort === "minimal") {
|
|
464
|
+
console.warn("\u26A0\uFE0F Claude\uB294 minimal\uC744 \uC9C1\uC811 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC544 low\uB85C \uB9E4\uD551\uD569\uB2C8\uB2E4.");
|
|
465
|
+
}
|
|
466
|
+
return normalized;
|
|
244
467
|
}
|
|
468
|
+
console.warn(
|
|
469
|
+
`\u26A0\uFE0F \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 reasoning effort(${customReasoningEffort})\uC785\uB2C8\uB2E4. allowed: ${ALLOWED_REASONING_EFFORTS.join(
|
|
470
|
+
", "
|
|
471
|
+
)}`
|
|
472
|
+
);
|
|
473
|
+
}
|
|
474
|
+
if (args.includes("--flash")) {
|
|
475
|
+
trace("reasoning:flash-default", "low");
|
|
476
|
+
return "low";
|
|
477
|
+
}
|
|
478
|
+
if (args.includes("--review")) {
|
|
479
|
+
trace("reasoning:review-default", "high");
|
|
480
|
+
return "high";
|
|
481
|
+
}
|
|
482
|
+
trace("reasoning:default", "medium");
|
|
483
|
+
return "medium";
|
|
484
|
+
}
|
|
485
|
+
function resolvePrimaryAlias() {
|
|
486
|
+
if (args.includes("--review")) {
|
|
487
|
+
trace("model:mode-alias", "opus");
|
|
488
|
+
return "opus";
|
|
489
|
+
}
|
|
490
|
+
if (args.includes("--flash")) {
|
|
491
|
+
trace("model:mode-alias", "haiku");
|
|
492
|
+
return "haiku";
|
|
493
|
+
}
|
|
494
|
+
trace("model:default-alias", "sonnet");
|
|
495
|
+
return "sonnet";
|
|
496
|
+
}
|
|
497
|
+
function getAliasFallbacks(primaryAlias) {
|
|
498
|
+
if (primaryAlias === "opus") {
|
|
499
|
+
return ["opus", "sonnet", "haiku"];
|
|
500
|
+
}
|
|
501
|
+
if (primaryAlias === "haiku") {
|
|
502
|
+
return ["haiku", "sonnet"];
|
|
245
503
|
}
|
|
504
|
+
return [primaryAlias, "sonnet", "haiku"];
|
|
505
|
+
}
|
|
506
|
+
function buildClaudeExecCommand(options) {
|
|
507
|
+
const { tempDiffPath: tempDiffPath2, prompt, systemPromptFiles, effort, model, fallbackModel } = options;
|
|
508
|
+
const modelOption = model ? `--model ${shellQuote(model)}` : "";
|
|
509
|
+
const fallbackOption = model && fallbackModel ? `--fallback-model ${shellQuote(fallbackModel)}` : "";
|
|
510
|
+
const effortOption = `--effort ${shellQuote(effort)}`;
|
|
511
|
+
const appendedPromptFiles = systemPromptFiles.map((path2) => `--append-system-prompt-file ${shellQuote(path2)}`).join(" ");
|
|
512
|
+
return `cat ${shellQuote(tempDiffPath2)} | claude ${[
|
|
513
|
+
modelOption,
|
|
514
|
+
fallbackOption,
|
|
515
|
+
effortOption,
|
|
516
|
+
appendedPromptFiles,
|
|
517
|
+
"-p",
|
|
518
|
+
shellQuote(prompt)
|
|
519
|
+
].filter(Boolean).join(" ")}`;
|
|
520
|
+
}
|
|
521
|
+
var createClaudeCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
522
|
+
trace("createClaudeCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
|
|
523
|
+
const customModel = getArgValue("--model");
|
|
524
|
+
const effort = resolveReasoningEffort();
|
|
525
|
+
const primaryAlias = resolvePrimaryAlias();
|
|
526
|
+
const aliasFallbacks = toUnique(getAliasFallbacks(primaryAlias));
|
|
246
527
|
const rules = [
|
|
247
528
|
{ path: rulesPath, display: "\uB8F0\uC14B" },
|
|
248
529
|
{ path: namingRulesPath, display: "\uB124\uC774\uBC0D \uADDC\uCE59" },
|
|
249
530
|
{ path: codingConventionRulesPath, display: "\uCF54\uB529 \uCEE8\uBCA4\uC158" }
|
|
250
531
|
];
|
|
251
|
-
const
|
|
252
|
-
trace(
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
const
|
|
257
|
-
trace("
|
|
258
|
-
|
|
532
|
+
const existingRuleFiles = rules.filter((rule) => fs.existsSync(rule.path)).map((rule) => rule.path);
|
|
533
|
+
trace("rules:loaded", `count=${existingRuleFiles.length}`);
|
|
534
|
+
const reviewFormExists = fs.existsSync(reviewFormPath2);
|
|
535
|
+
trace("reviewForm:status", reviewFormExists ? "exists" : "missing");
|
|
536
|
+
const systemPromptFiles = reviewFormExists ? [...existingRuleFiles, reviewFormPath2] : existingRuleFiles;
|
|
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}`);
|
|
540
|
+
const modelCandidates = toUnique(customModel ? [customModel, ...aliasFallbacks] : aliasFallbacks);
|
|
541
|
+
trace("model:candidates", modelCandidates.join(", "));
|
|
542
|
+
trace("command:candidates:count", String(modelCandidates.length + 1));
|
|
543
|
+
if (customModel) {
|
|
544
|
+
console.warn(
|
|
545
|
+
`\u26A0\uFE0F \uCEE4\uC2A4\uD140 \uBAA8\uB378(${customModel})\uC744 \uC6B0\uC120 \uC2DC\uB3C4\uD558\uACE0 \uC2E4\uD328\uD558\uBA74 alias(${aliasFallbacks.join(
|
|
546
|
+
" -> "
|
|
547
|
+
)}) \uBC0F \uAE30\uBCF8 \uBAA8\uB378 \uC21C\uC73C\uB85C \uD3F4\uBC31\uD569\uB2C8\uB2E4.`
|
|
548
|
+
);
|
|
549
|
+
} else {
|
|
550
|
+
console.warn(
|
|
551
|
+
`\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.`
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
const commandCandidates = modelCandidates.map((model, index) => {
|
|
555
|
+
const fallbackModel = modelCandidates[index + 1];
|
|
556
|
+
return buildClaudeExecCommand({
|
|
557
|
+
tempDiffPath: tempDiffPath2,
|
|
558
|
+
prompt,
|
|
559
|
+
systemPromptFiles,
|
|
560
|
+
effort,
|
|
561
|
+
model,
|
|
562
|
+
fallbackModel
|
|
563
|
+
});
|
|
564
|
+
});
|
|
565
|
+
const command = [
|
|
566
|
+
...commandCandidates,
|
|
567
|
+
buildClaudeExecCommand({
|
|
568
|
+
tempDiffPath: tempDiffPath2,
|
|
569
|
+
prompt,
|
|
570
|
+
systemPromptFiles,
|
|
571
|
+
effort
|
|
572
|
+
})
|
|
573
|
+
].join(" || ");
|
|
259
574
|
trace("command:created");
|
|
260
575
|
if (args.includes("--test")) {
|
|
261
576
|
const safeCommand = command.replace(/"/g, '\\"');
|
|
@@ -265,6 +580,7 @@ var createClaudeCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
|
265
580
|
\uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
|
|
266
581
|
${safeCommand}"`;
|
|
267
582
|
}
|
|
583
|
+
trace("command:mode", "execute");
|
|
268
584
|
trace("createClaudeCommand:end");
|
|
269
585
|
return command;
|
|
270
586
|
};
|
|
@@ -275,54 +591,79 @@ function checkClaudeCliInstalled() {
|
|
|
275
591
|
trace2("version-check:run", "claude --version");
|
|
276
592
|
execSync("claude --version", { stdio: "ignore" });
|
|
277
593
|
trace2("version-check:ok");
|
|
278
|
-
} catch {
|
|
279
|
-
trace2("version-check:failed",
|
|
594
|
+
} catch (error) {
|
|
595
|
+
trace2("version-check:failed", getErrorSummary(error));
|
|
596
|
+
trace2("install:start", "@anthropic-ai/claude-code");
|
|
280
597
|
console.log(
|
|
281
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"
|
|
282
599
|
);
|
|
283
600
|
try {
|
|
284
601
|
execSync("npm install -g @anthropic-ai/claude-code", { stdio: "inherit" });
|
|
285
|
-
trace2("install:ok", "
|
|
602
|
+
trace2("install:ok", "login-required");
|
|
286
603
|
console.log("\u2705 claude-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
287
604
|
console.log("\u26A0\uFE0F claude-cli \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
288
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.');
|
|
289
606
|
process.exit(1);
|
|
290
607
|
} catch (installError) {
|
|
291
|
-
trace2("install:failed");
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
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
|
+
});
|
|
295
613
|
}
|
|
296
614
|
}
|
|
297
615
|
trace2("checkClaudeCliInstalled:end");
|
|
298
616
|
}
|
|
299
617
|
var args2 = process.argv.slice(2);
|
|
300
618
|
var trace3 = createTraceLogger("codex-commander", args2);
|
|
301
|
-
var
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
modelOption = "--model gpt-5-mini";
|
|
319
|
-
trace3("model:default", modelOption);
|
|
619
|
+
var ALLOWED_REASONING_EFFORTS2 = ["minimal", "low", "medium", "high"];
|
|
620
|
+
function shellQuote2(value) {
|
|
621
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
622
|
+
}
|
|
623
|
+
function getArgValue2(flag) {
|
|
624
|
+
const index = args2.indexOf(flag);
|
|
625
|
+
if (index === -1 || !args2[index + 1]) {
|
|
626
|
+
return "";
|
|
627
|
+
}
|
|
628
|
+
return args2[index + 1];
|
|
629
|
+
}
|
|
630
|
+
function resolveReasoningEffort2() {
|
|
631
|
+
const customReasoningEffort = getArgValue2("--reasoning-effort");
|
|
632
|
+
if (customReasoningEffort) {
|
|
633
|
+
if (ALLOWED_REASONING_EFFORTS2.includes(customReasoningEffort)) {
|
|
634
|
+
trace3("reasoning:custom", customReasoningEffort);
|
|
635
|
+
return customReasoningEffort;
|
|
320
636
|
}
|
|
637
|
+
console.warn(
|
|
638
|
+
`\u26A0\uFE0F \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 reasoning effort(${customReasoningEffort})\uC785\uB2C8\uB2E4. allowed: ${ALLOWED_REASONING_EFFORTS2.join(
|
|
639
|
+
", "
|
|
640
|
+
)}`
|
|
641
|
+
);
|
|
321
642
|
}
|
|
322
|
-
|
|
643
|
+
if (args2.includes("--flash")) {
|
|
644
|
+
trace3("reasoning:flash-default", "minimal");
|
|
645
|
+
return "minimal";
|
|
646
|
+
}
|
|
647
|
+
if (args2.includes("--review")) {
|
|
648
|
+
trace3("reasoning:review-default", "high");
|
|
649
|
+
return "high";
|
|
650
|
+
}
|
|
651
|
+
trace3("reasoning:default", "medium");
|
|
652
|
+
return "medium";
|
|
653
|
+
}
|
|
654
|
+
function buildCodexExecCommand(prompt, reasoningEffort, model) {
|
|
655
|
+
const modelOption = model ? `--model ${shellQuote2(model)}` : "";
|
|
656
|
+
const reasoningOption = `-c ${shellQuote2(`model_reasoning_effort="${reasoningEffort}"`)}`;
|
|
657
|
+
return `codex exec ${[modelOption, reasoningOption, shellQuote2(prompt)].filter(Boolean).join(" ")}`;
|
|
658
|
+
}
|
|
659
|
+
var createCodexCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
660
|
+
trace3("createCodexCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
|
|
661
|
+
const customModel = getArgValue2("--model");
|
|
662
|
+
const reasoningEffort = resolveReasoningEffort2();
|
|
663
|
+
const rules = [rulesPath, namingRulesPath, codingConventionRulesPath].filter((filePath) => fs.existsSync(filePath)).map((filePath) => `- ${filePath}`).join("\n");
|
|
323
664
|
const rulesCount = rules ? rules.split("\n").length : 0;
|
|
324
665
|
trace3("rules:loaded", `count=${rulesCount}`);
|
|
325
|
-
const hasReviewForm =
|
|
666
|
+
const hasReviewForm = fs.existsSync(reviewFormPath2);
|
|
326
667
|
const reviewFormLine = hasReviewForm ? `- ${reviewFormPath2}` : "";
|
|
327
668
|
trace3("reviewForm:status", reviewFormLine ? "exists" : "missing");
|
|
328
669
|
const prompt = `\uC544\uB798 \uD30C\uC77C\uB4E4\uC744 \uCC38\uACE0\uD574\uC11C \uCF54\uB4DC \uB9AC\uBDF0\uB97C \uC9C4\uD589\uD574\uC918.
|
|
@@ -334,7 +675,23 @@ ${reviewFormLine || "- (\uC5C6\uC74C)"}
|
|
|
334
675
|
- ${tempDiffPath2}
|
|
335
676
|
|
|
336
677
|
\uBC18\uB4DC\uC2DC \uB9AC\uBDF0 \uC591\uC2DD\uC5D0 \uB9DE\uCDB0 \uC791\uC131\uD574\uC918.`;
|
|
337
|
-
|
|
678
|
+
trace3("prompt:prepared", `length=${prompt.length}`);
|
|
679
|
+
let command = "";
|
|
680
|
+
if (customModel) {
|
|
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.");
|
|
682
|
+
trace3("model:custom", customModel);
|
|
683
|
+
command = buildCodexExecCommand(prompt, reasoningEffort, customModel);
|
|
684
|
+
} else {
|
|
685
|
+
const preferredModelAlias = "gpt-5";
|
|
686
|
+
const aliasCommand = buildCodexExecCommand(prompt, reasoningEffort, preferredModelAlias);
|
|
687
|
+
const fallbackCommand = buildCodexExecCommand(prompt, reasoningEffort);
|
|
688
|
+
console.warn(
|
|
689
|
+
`\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.`
|
|
690
|
+
);
|
|
691
|
+
trace3("model:alias-first", preferredModelAlias);
|
|
692
|
+
trace3("model:fallback", "account-default");
|
|
693
|
+
command = `${aliasCommand} || ${fallbackCommand}`;
|
|
694
|
+
}
|
|
338
695
|
trace3("command:created");
|
|
339
696
|
if (args2.includes("--test")) {
|
|
340
697
|
const safeCommand = command.replace(/"/g, '\\"');
|
|
@@ -344,6 +701,7 @@ ${reviewFormLine || "- (\uC5C6\uC74C)"}
|
|
|
344
701
|
\uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
|
|
345
702
|
${safeCommand}"`;
|
|
346
703
|
}
|
|
704
|
+
trace3("command:mode", "execute");
|
|
347
705
|
trace3("createCodexCommand:end");
|
|
348
706
|
return command;
|
|
349
707
|
};
|
|
@@ -354,57 +712,156 @@ function checkCodexCliInstalled() {
|
|
|
354
712
|
trace4("version-check:run", "codex --version");
|
|
355
713
|
execSync("codex --version", { stdio: "ignore" });
|
|
356
714
|
trace4("version-check:ok");
|
|
357
|
-
} catch {
|
|
358
|
-
trace4("version-check:failed",
|
|
715
|
+
} catch (error) {
|
|
716
|
+
trace4("version-check:failed", getErrorSummary(error));
|
|
717
|
+
trace4("install:start", "@openai/codex");
|
|
359
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");
|
|
360
719
|
try {
|
|
361
720
|
execSync("npm install -g @openai/codex", { stdio: "inherit" });
|
|
362
|
-
trace4("install:ok", "
|
|
721
|
+
trace4("install:ok", "login-required");
|
|
363
722
|
console.log("\u2705 codex-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
364
723
|
console.log("\u26A0\uFE0F codex-cli \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
365
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.');
|
|
366
725
|
process.exit(1);
|
|
367
726
|
} catch (installError) {
|
|
368
|
-
trace4("install:failed");
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
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
|
+
});
|
|
372
732
|
}
|
|
373
733
|
}
|
|
374
734
|
trace4("checkCodexCliInstalled:end");
|
|
375
735
|
}
|
|
376
736
|
var args3 = process.argv.slice(2);
|
|
377
737
|
var trace5 = createTraceLogger("gemini-commander", args3);
|
|
378
|
-
var
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
738
|
+
var ALLOWED_REASONING_EFFORTS3 = ["minimal", "low", "medium", "high"];
|
|
739
|
+
function shellQuote3(value) {
|
|
740
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
741
|
+
}
|
|
742
|
+
function getArgValue3(flag) {
|
|
743
|
+
const index = args3.indexOf(flag);
|
|
744
|
+
if (index === -1 || !args3[index + 1]) {
|
|
745
|
+
return "";
|
|
746
|
+
}
|
|
747
|
+
return args3[index + 1];
|
|
748
|
+
}
|
|
749
|
+
function toUnique2(values) {
|
|
750
|
+
const seen = /* @__PURE__ */ new Set();
|
|
751
|
+
return values.filter((value) => {
|
|
752
|
+
if (!value || seen.has(value)) {
|
|
753
|
+
return false;
|
|
754
|
+
}
|
|
755
|
+
seen.add(value);
|
|
756
|
+
return true;
|
|
757
|
+
});
|
|
758
|
+
}
|
|
759
|
+
function resolveReasoningEffort3() {
|
|
760
|
+
const customReasoningEffort = getArgValue3("--reasoning-effort");
|
|
761
|
+
if (customReasoningEffort) {
|
|
762
|
+
if (ALLOWED_REASONING_EFFORTS3.includes(customReasoningEffort)) {
|
|
763
|
+
trace5("reasoning:custom", customReasoningEffort);
|
|
764
|
+
return customReasoningEffort;
|
|
397
765
|
}
|
|
766
|
+
console.warn(
|
|
767
|
+
`\u26A0\uFE0F \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 reasoning effort(${customReasoningEffort})\uC785\uB2C8\uB2E4. allowed: ${ALLOWED_REASONING_EFFORTS3.join(
|
|
768
|
+
", "
|
|
769
|
+
)}`
|
|
770
|
+
);
|
|
771
|
+
}
|
|
772
|
+
if (args3.includes("--flash")) {
|
|
773
|
+
trace5("reasoning:flash-default", "minimal");
|
|
774
|
+
return "minimal";
|
|
775
|
+
}
|
|
776
|
+
if (args3.includes("--review")) {
|
|
777
|
+
trace5("reasoning:review-default", "high");
|
|
778
|
+
return "high";
|
|
779
|
+
}
|
|
780
|
+
trace5("reasoning:default", "medium");
|
|
781
|
+
return "medium";
|
|
782
|
+
}
|
|
783
|
+
function resolvePrimaryAlias2(reasoningEffort) {
|
|
784
|
+
if (args3.includes("--review")) {
|
|
785
|
+
trace5("model:mode-alias", "pro");
|
|
786
|
+
return "pro";
|
|
787
|
+
}
|
|
788
|
+
if (args3.includes("--flash")) {
|
|
789
|
+
trace5("model:mode-alias", "flash");
|
|
790
|
+
return "flash";
|
|
791
|
+
}
|
|
792
|
+
if (reasoningEffort === "high") {
|
|
793
|
+
trace5("model:reasoning-alias", "pro");
|
|
794
|
+
return "pro";
|
|
398
795
|
}
|
|
796
|
+
if (reasoningEffort === "minimal" || reasoningEffort === "low") {
|
|
797
|
+
trace5("model:reasoning-alias", "flash");
|
|
798
|
+
return "flash";
|
|
799
|
+
}
|
|
800
|
+
trace5("model:default-alias", "auto");
|
|
801
|
+
return "auto";
|
|
802
|
+
}
|
|
803
|
+
function getAliasFallbacks2(primaryAlias) {
|
|
804
|
+
if (primaryAlias === "pro") {
|
|
805
|
+
return ["pro", "flash", "auto"];
|
|
806
|
+
}
|
|
807
|
+
if (primaryAlias === "flash") {
|
|
808
|
+
return ["flash", "auto", "pro"];
|
|
809
|
+
}
|
|
810
|
+
return [primaryAlias, "auto", "flash", "pro"];
|
|
811
|
+
}
|
|
812
|
+
function getReasoningInstruction(reasoningEffort) {
|
|
813
|
+
if (reasoningEffort === "high") {
|
|
814
|
+
return "high (\uAE4A\uC774 \uC788\uB294 \uBD84\uC11D, \uC7A0\uC7AC\uC801 \uB9AC\uC2A4\uD06C\uAE4C\uC9C0 \uC810\uAC80)";
|
|
815
|
+
}
|
|
816
|
+
if (reasoningEffort === "medium") {
|
|
817
|
+
return "medium (\uADE0\uD615 \uC7A1\uD78C \uBD84\uC11D\uACFC \uD575\uC2EC \uC774\uC288 \uC911\uC2EC)";
|
|
818
|
+
}
|
|
819
|
+
if (reasoningEffort === "low") {
|
|
820
|
+
return "low (\uD575\uC2EC \uACB0\uD568 \uC704\uC8FC\uB85C \uAC04\uACB0\uD558\uAC8C \uBD84\uC11D)";
|
|
821
|
+
}
|
|
822
|
+
return "minimal (\uCE58\uBA85\uB3C4 \uB192\uC740 \uC774\uC288\uB9CC \uB9E4\uC6B0 \uAC04\uACB0\uD558\uAC8C \uBD84\uC11D)";
|
|
823
|
+
}
|
|
824
|
+
function buildGeminiExecCommand(prompt, model) {
|
|
825
|
+
const modelOption = model ? `--model ${shellQuote3(model)}` : "";
|
|
826
|
+
return `gemini ${[modelOption, "-p", shellQuote3(prompt)].filter(Boolean).join(" ")}`;
|
|
827
|
+
}
|
|
828
|
+
var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
829
|
+
trace5("createGeminiCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
|
|
830
|
+
const customModel = getArgValue3("--model");
|
|
831
|
+
const reasoningEffort = resolveReasoningEffort3();
|
|
832
|
+
const primaryAlias = resolvePrimaryAlias2(reasoningEffort);
|
|
833
|
+
const aliasFallbacks = toUnique2(getAliasFallbacks2(primaryAlias));
|
|
399
834
|
const rules = [
|
|
400
835
|
{ path: rulesPath, display: "\uB8F0\uC14B" },
|
|
401
836
|
{ path: namingRulesPath, display: "\uB124\uC774\uBC0D \uADDC\uCE59" },
|
|
402
837
|
{ path: codingConventionRulesPath, display: "\uCF54\uB529 \uCEE8\uBCA4\uC158" }
|
|
403
838
|
];
|
|
404
|
-
const validRules = rules.filter((rule) =>
|
|
839
|
+
const validRules = rules.filter((rule) => fs.existsSync(rule.path)).map((rule) => `@${rule.path}`).join(", ");
|
|
405
840
|
const rulesCount = validRules ? validRules.split(",").length : 0;
|
|
406
841
|
trace5("rules:loaded", `count=${rulesCount}`);
|
|
407
|
-
const
|
|
842
|
+
const reviewFormRef = fs.existsSync(reviewFormPath2) ? `@${reviewFormPath2}` : "(\uC5C6\uC74C)";
|
|
843
|
+
trace5("reviewForm:status", reviewFormRef === "(\uC5C6\uC74C)" ? "missing" : "exists");
|
|
844
|
+
const reasoningInstruction = getReasoningInstruction(reasoningEffort);
|
|
845
|
+
const prompt = `\uB2E4\uC74C \uADDC\uCE59\uB4E4\uC744 \uCC38\uACE0\uD574\uC11C(${validRules || "(\uC5C6\uC74C)"}) \uC774 diff(@${tempDiffPath2})\uB97C \uB9AC\uBDF0\uD574\uC918.
|
|
846
|
+
\uB9AC\uBDF0 \uC591\uC2DD\uC740 ${reviewFormRef} \uC5D0 \uB9DE\uCDB0\uC11C \uC791\uC131\uD574\uC918.
|
|
847
|
+
\uCD94\uB860 \uAC15\uB3C4 \uC9C0\uCE68: ${reasoningInstruction}`;
|
|
848
|
+
trace5("prompt:prepared", `length=${prompt.length}`);
|
|
849
|
+
const modelCandidates = toUnique2(customModel ? [customModel, ...aliasFallbacks] : aliasFallbacks);
|
|
850
|
+
trace5("model:candidates", modelCandidates.join(", "));
|
|
851
|
+
trace5("command:candidates:count", String(modelCandidates.length + 1));
|
|
852
|
+
if (customModel) {
|
|
853
|
+
console.warn(
|
|
854
|
+
`\u26A0\uFE0F \uCEE4\uC2A4\uD140 \uBAA8\uB378(${customModel})\uC744 \uC6B0\uC120 \uC2DC\uB3C4\uD558\uACE0 \uC2E4\uD328\uD558\uBA74 alias(${aliasFallbacks.join(
|
|
855
|
+
" -> "
|
|
856
|
+
)}) \uBC0F \uAE30\uBCF8 \uBAA8\uB378 \uC21C\uC73C\uB85C \uD3F4\uBC31\uD569\uB2C8\uB2E4.`
|
|
857
|
+
);
|
|
858
|
+
} else {
|
|
859
|
+
console.warn(
|
|
860
|
+
`\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.`
|
|
861
|
+
);
|
|
862
|
+
}
|
|
863
|
+
const commandCandidates = modelCandidates.map((model) => buildGeminiExecCommand(prompt, model));
|
|
864
|
+
const command = [...commandCandidates, buildGeminiExecCommand(prompt)].join(" || ");
|
|
408
865
|
trace5("command:created");
|
|
409
866
|
if (args3.includes("--test")) {
|
|
410
867
|
const safeCommand = command.replace(/"/g, '\\"');
|
|
@@ -414,6 +871,7 @@ var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
|
414
871
|
\uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
|
|
415
872
|
${safeCommand}"`;
|
|
416
873
|
}
|
|
874
|
+
trace5("command:mode", "execute");
|
|
417
875
|
trace5("createGeminiCommand:end");
|
|
418
876
|
return command;
|
|
419
877
|
};
|
|
@@ -424,21 +882,23 @@ function checkGeminiCliInstalled() {
|
|
|
424
882
|
trace6("version-check:run", "gemini --version");
|
|
425
883
|
execSync("gemini --version", { stdio: "ignore" });
|
|
426
884
|
trace6("version-check:ok");
|
|
427
|
-
} catch {
|
|
428
|
-
trace6("version-check:failed",
|
|
885
|
+
} catch (error) {
|
|
886
|
+
trace6("version-check:failed", getErrorSummary(error));
|
|
887
|
+
trace6("install:start", "@google/gemini-cli");
|
|
429
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");
|
|
430
889
|
try {
|
|
431
890
|
execSync("npm install -g @google/gemini-cli", { stdio: "inherit" });
|
|
432
|
-
trace6("install:ok", "
|
|
891
|
+
trace6("install:ok", "login-required");
|
|
433
892
|
console.log("\u2705 gemini-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
434
893
|
console.log("\u26A0\uFE0F Gemini API \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
435
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.');
|
|
436
895
|
process.exit(1);
|
|
437
896
|
} catch (installError) {
|
|
438
|
-
trace6("install:failed");
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
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
|
+
});
|
|
442
902
|
}
|
|
443
903
|
}
|
|
444
904
|
trace6("checkGeminiCliInstalled:end");
|
|
@@ -448,30 +908,34 @@ function checkGeminiCliInstalled() {
|
|
|
448
908
|
var execAsync = util.promisify(exec);
|
|
449
909
|
async function main() {
|
|
450
910
|
const args4 = process.argv.slice(2);
|
|
911
|
+
clearTraceMessages();
|
|
451
912
|
const isTest = isTestMode(args4);
|
|
452
913
|
const trace7 = createTraceLogger("review-one-by-one", args4);
|
|
453
914
|
trace7("main:start", `args=${JSON.stringify(args4)}`);
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
switch (service) {
|
|
458
|
-
case "gemini":
|
|
459
|
-
trace7("install-check:start", "service=gemini");
|
|
460
|
-
checkGeminiCliInstalled();
|
|
461
|
-
trace7("install-check:done", "service=gemini");
|
|
462
|
-
break;
|
|
463
|
-
case "claude":
|
|
464
|
-
trace7("install-check:start", "service=claude");
|
|
465
|
-
checkClaudeCliInstalled();
|
|
466
|
-
trace7("install-check:done", "service=claude");
|
|
467
|
-
break;
|
|
468
|
-
case "codex":
|
|
469
|
-
trace7("install-check:start", "service=codex");
|
|
470
|
-
checkCodexCliInstalled();
|
|
471
|
-
trace7("install-check:done", "service=codex");
|
|
472
|
-
break;
|
|
473
|
-
}
|
|
915
|
+
let service = "";
|
|
916
|
+
let savedDiffPath = "";
|
|
917
|
+
let savedReportPath = "";
|
|
474
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
|
+
}
|
|
475
939
|
trace7("review-flow:start");
|
|
476
940
|
console.log("\u{1F680} AI Code Review\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4...");
|
|
477
941
|
trace7("report-dir:create:start");
|
|
@@ -479,6 +943,7 @@ async function main() {
|
|
|
479
943
|
trace7("report-dir:create:done");
|
|
480
944
|
const { includeParams, excludeParams } = getGitDiffFilter();
|
|
481
945
|
trace7("diff-filter:loaded", `include=${includeParams} | exclude=${excludeParams}`);
|
|
946
|
+
trace7("diff-args:build:start");
|
|
482
947
|
const diffArgs = getDiffArgs();
|
|
483
948
|
trace7("diff-args:build:done", `diffArgs=${diffArgs || "(default)"}`);
|
|
484
949
|
const filesCommand = `git diff --name-only ${diffArgs} -- ${includeParams} ${excludeParams}`;
|
|
@@ -498,26 +963,26 @@ async function main() {
|
|
|
498
963
|
trace7("full-diff:done", `length=${fullDiff.length}`);
|
|
499
964
|
trace7("timestamp:created", nowStr);
|
|
500
965
|
trace7("temp-diff:write:start", tempDiffPath);
|
|
501
|
-
|
|
966
|
+
fs.writeFileSync(tempDiffPath, fullDiff);
|
|
502
967
|
trace7("temp-diff:write:done");
|
|
503
968
|
trace7("saved-diff:copy:start");
|
|
504
|
-
|
|
505
|
-
|
|
969
|
+
savedDiffPath = getNextFilePath(REPORT_DIR, `${nowStr}-diff`, ".txt");
|
|
970
|
+
fs.copyFileSync(tempDiffPath, savedDiffPath);
|
|
506
971
|
trace7("saved-diff:copy:done", savedDiffPath);
|
|
507
|
-
|
|
972
|
+
savedReportPath = getNextFilePath(REPORT_DIR, nowStr, ".md");
|
|
508
973
|
trace7("saved-report:path", savedReportPath);
|
|
509
974
|
const promises = fileList.map(async (file) => {
|
|
975
|
+
const tempOneFileDiffPath = `temp_diff_${file.replace(/\//g, "_")}.txt`;
|
|
976
|
+
let command = "";
|
|
510
977
|
try {
|
|
511
978
|
trace7("file-review:start", file);
|
|
512
979
|
console.log(`\u{1F50D} Reviewing: ${file}...`);
|
|
513
980
|
trace7("file-diff:run", file);
|
|
514
981
|
const fileDiff = execSync(`git diff ${diffArgs} -- "${file}"`).toString();
|
|
515
982
|
trace7("file-diff:done", `${file} | length=${fileDiff.length}`);
|
|
516
|
-
const tempOneFileDiffPath = `temp_diff_${file.replace(/\//g, "_")}.txt`;
|
|
517
983
|
trace7("file-temp-diff:write:start", tempOneFileDiffPath);
|
|
518
|
-
|
|
984
|
+
fs.writeFileSync(tempOneFileDiffPath, fileDiff);
|
|
519
985
|
trace7("file-temp-diff:write:done", tempOneFileDiffPath);
|
|
520
|
-
let command = "";
|
|
521
986
|
trace7("file-command:create:start", file);
|
|
522
987
|
switch (service) {
|
|
523
988
|
case "gemini":
|
|
@@ -530,7 +995,7 @@ async function main() {
|
|
|
530
995
|
command = createCodexCommand(tempOneFileDiffPath, reviewFormOneByOnePath);
|
|
531
996
|
break;
|
|
532
997
|
}
|
|
533
|
-
trace7("file-command:create:done", file);
|
|
998
|
+
trace7("file-command:create:done", `${file} | commandLength=${command.length}`);
|
|
534
999
|
trace7("file-command:exec:start", file);
|
|
535
1000
|
const { stdout } = await execAsync(command, { maxBuffer: 1024 * 1024 * 20 });
|
|
536
1001
|
const result = stdout.toString();
|
|
@@ -544,11 +1009,11 @@ ${result}
|
|
|
544
1009
|
`;
|
|
545
1010
|
console.log(tempReport);
|
|
546
1011
|
trace7("file-report:append:start", file);
|
|
547
|
-
|
|
1012
|
+
fs.appendFileSync(savedReportPath, tempReport);
|
|
548
1013
|
trace7("file-report:append:done", file);
|
|
549
1014
|
if (isTest) {
|
|
550
1015
|
trace7("file-test-command:append:start", file);
|
|
551
|
-
|
|
1016
|
+
fs.appendFileSync(savedReportPath, `
|
|
552
1017
|
|
|
553
1018
|
## \uC0AC\uC6A9\uB41C \uBA85\uB839\uC5B4
|
|
554
1019
|
|
|
@@ -557,26 +1022,51 @@ ${command}`);
|
|
|
557
1022
|
}
|
|
558
1023
|
trace7("file-review:end", file);
|
|
559
1024
|
} catch (err) {
|
|
560
|
-
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
|
+
});
|
|
561
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
|
+
}
|
|
562
1053
|
const errorReport = `### File: ${file}
|
|
563
1054
|
\u274C Review Failed
|
|
564
1055
|
\`\`\`
|
|
565
|
-
${err}
|
|
1056
|
+
${getErrorSummary(err)}
|
|
566
1057
|
\`\`\`
|
|
567
1058
|
|
|
568
1059
|
`;
|
|
569
|
-
|
|
1060
|
+
fs.appendFileSync(savedReportPath, errorReport);
|
|
570
1061
|
try {
|
|
571
|
-
|
|
572
|
-
if (fs5.existsSync(tempOneFileDiffPath)) {
|
|
1062
|
+
if (fs.existsSync(tempOneFileDiffPath)) {
|
|
573
1063
|
trace7("file-temp-diff:delete:start(catch)", tempOneFileDiffPath);
|
|
574
1064
|
deleteFile(tempOneFileDiffPath);
|
|
575
1065
|
trace7("file-temp-diff:delete:done(catch)", tempOneFileDiffPath);
|
|
576
1066
|
}
|
|
577
|
-
} catch (
|
|
578
|
-
trace7("file-temp-diff:delete:failed(catch)", file);
|
|
579
|
-
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);
|
|
580
1070
|
}
|
|
581
1071
|
}
|
|
582
1072
|
});
|
|
@@ -595,12 +1085,44 @@ ${err}
|
|
|
595
1085
|
trace7("cleanup-temp-diff:done");
|
|
596
1086
|
trace7("review-flow:end");
|
|
597
1087
|
} catch (error) {
|
|
598
|
-
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
|
+
});
|
|
599
1121
|
console.error("\u274C \uB9AC\uBDF0 \uB3C4\uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
|
|
600
1122
|
console.error(error);
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
1123
|
+
if (errorReportPath) {
|
|
1124
|
+
console.error(`\u{1F4C4} \uC5D0\uB7EC \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${errorReportPath}`);
|
|
1125
|
+
}
|
|
604
1126
|
process.exit(1);
|
|
605
1127
|
}
|
|
606
1128
|
}
|