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
|
@@ -6,6 +6,7 @@ var fs = require('fs');
|
|
|
6
6
|
var path = require('path');
|
|
7
7
|
var readline = require('readline');
|
|
8
8
|
var url = require('url');
|
|
9
|
+
var util = require('util');
|
|
9
10
|
|
|
10
11
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
11
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -15,6 +16,7 @@ var path__default = /*#__PURE__*/_interopDefault(path);
|
|
|
15
16
|
var readline__default = /*#__PURE__*/_interopDefault(readline);
|
|
16
17
|
|
|
17
18
|
var __dirname$1 = path__default.default.dirname(url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('review.cjs', document.baseURI).href))));
|
|
19
|
+
var traceMessages = [];
|
|
18
20
|
var rulesPath = path__default.default.resolve(__dirname$1, "../../src/common/rules/review-rules.md");
|
|
19
21
|
var namingRulesPath = path__default.default.resolve(__dirname$1, "../../src/common/rules/naming-rule.md");
|
|
20
22
|
var codingConventionRulesPath = path__default.default.resolve(__dirname$1, "../../src/common/rules/coding-convention.md");
|
|
@@ -37,32 +39,96 @@ var ignoreList = [
|
|
|
37
39
|
".review-report/"
|
|
38
40
|
// 생성되는 리포트 폴더도 제외
|
|
39
41
|
];
|
|
40
|
-
function parseServiceFromArgs(args4 = process.argv.slice(2)) {
|
|
41
|
-
const serviceIndex = args4.indexOf("--service");
|
|
42
|
-
const rawService = serviceIndex !== -1 ? args4[serviceIndex + 1] : "";
|
|
43
|
-
if (!rawService) {
|
|
44
|
-
return "";
|
|
45
|
-
}
|
|
46
|
-
const normalizedService = rawService.toLowerCase();
|
|
47
|
-
if (AIServices.includes(normalizedService)) {
|
|
48
|
-
return normalizedService;
|
|
49
|
-
}
|
|
50
|
-
console.error(
|
|
51
|
-
`\u274C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uC11C\uBE44\uC2A4\uC785\uB2C8\uB2E4: ${rawService}. \uC0AC\uC6A9 \uAC00\uB2A5 \uAC12: ${AIServices.join(", ")} (\uC608: --service codex)`
|
|
52
|
-
);
|
|
53
|
-
process.exit(1);
|
|
54
|
-
}
|
|
55
42
|
function isTestMode(args4 = process.argv.slice(2)) {
|
|
56
43
|
return args4.includes("--test");
|
|
57
44
|
}
|
|
45
|
+
function clearTraceMessages() {
|
|
46
|
+
traceMessages.length = 0;
|
|
47
|
+
}
|
|
48
|
+
function getTraceMessages() {
|
|
49
|
+
return [...traceMessages];
|
|
50
|
+
}
|
|
58
51
|
function createTraceLogger(scope, args4 = process.argv.slice(2)) {
|
|
59
52
|
const enabled = isTestMode(args4);
|
|
60
53
|
return (step, detail) => {
|
|
54
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
55
|
+
const message = `[${timestamp}][TRACE][${scope}] ${step}${detail ? ` | ${detail}` : ""}`;
|
|
56
|
+
traceMessages.push(message);
|
|
61
57
|
if (!enabled) {
|
|
62
58
|
return;
|
|
63
59
|
}
|
|
64
|
-
console.log(
|
|
60
|
+
console.log(message);
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
var helperTrace = createTraceLogger("helper");
|
|
64
|
+
function getTimestampParts(now = /* @__PURE__ */ new Date()) {
|
|
65
|
+
return {
|
|
66
|
+
YYYY: now.getFullYear(),
|
|
67
|
+
MM: String(now.getMonth() + 1).padStart(2, "0"),
|
|
68
|
+
DD: String(now.getDate()).padStart(2, "0"),
|
|
69
|
+
HH: String(now.getHours()).padStart(2, "0"),
|
|
70
|
+
mm: String(now.getMinutes()).padStart(2, "0"),
|
|
71
|
+
ss: String(now.getSeconds()).padStart(2, "0")
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function getHumanReadableNowString(now = /* @__PURE__ */ new Date()) {
|
|
75
|
+
const { YYYY, MM, DD, HH, mm, ss } = getTimestampParts(now);
|
|
76
|
+
return `${YYYY}-${MM}-${DD} ${HH}:${mm}:${ss}`;
|
|
77
|
+
}
|
|
78
|
+
function stringifyUnknown(value) {
|
|
79
|
+
if (value === void 0 || value === null) {
|
|
80
|
+
return "";
|
|
81
|
+
}
|
|
82
|
+
if (typeof value === "string") {
|
|
83
|
+
return value;
|
|
84
|
+
}
|
|
85
|
+
if (Buffer.isBuffer(value)) {
|
|
86
|
+
return value.toString();
|
|
87
|
+
}
|
|
88
|
+
if (value instanceof Error) {
|
|
89
|
+
return value.stack || value.message;
|
|
90
|
+
}
|
|
91
|
+
return util.inspect(value, { depth: 5, breakLength: 120 });
|
|
92
|
+
}
|
|
93
|
+
function getErrorSummary(error) {
|
|
94
|
+
if (error instanceof Error) {
|
|
95
|
+
return `${error.name}: ${error.message}`;
|
|
96
|
+
}
|
|
97
|
+
return stringifyUnknown(error) || "Unknown error";
|
|
98
|
+
}
|
|
99
|
+
function serializeError(error) {
|
|
100
|
+
const serialized = {
|
|
101
|
+
summary: getErrorSummary(error)
|
|
65
102
|
};
|
|
103
|
+
if (error instanceof Error) {
|
|
104
|
+
serialized.name = error.name;
|
|
105
|
+
serialized.message = error.message;
|
|
106
|
+
serialized.stack = error.stack;
|
|
107
|
+
} else {
|
|
108
|
+
serialized.value = stringifyUnknown(error);
|
|
109
|
+
}
|
|
110
|
+
if (error && typeof error === "object") {
|
|
111
|
+
const errorLike = error;
|
|
112
|
+
const extraKeys = ["code", "errno", "syscall", "path", "cmd", "status", "signal", "spawnargs"];
|
|
113
|
+
extraKeys.forEach((key) => {
|
|
114
|
+
if (errorLike[key] !== void 0) {
|
|
115
|
+
serialized[key] = errorLike[key];
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
const stdout = stringifyUnknown(errorLike.stdout);
|
|
119
|
+
if (stdout) {
|
|
120
|
+
serialized.stdout = stdout;
|
|
121
|
+
}
|
|
122
|
+
const stderr = stringifyUnknown(errorLike.stderr);
|
|
123
|
+
if (stderr) {
|
|
124
|
+
serialized.stderr = stderr;
|
|
125
|
+
}
|
|
126
|
+
const cause = stringifyUnknown(errorLike.cause);
|
|
127
|
+
if (cause) {
|
|
128
|
+
serialized.cause = cause;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return serialized;
|
|
66
132
|
}
|
|
67
133
|
function getNextFilePath(dir, baseName, extension) {
|
|
68
134
|
let counter = 1;
|
|
@@ -74,6 +140,13 @@ function getNextFilePath(dir, baseName, extension) {
|
|
|
74
140
|
counter++;
|
|
75
141
|
}
|
|
76
142
|
}
|
|
143
|
+
function getAvailableFilePath(dir, baseName, extension) {
|
|
144
|
+
const firstFilePath = path__default.default.join(dir, `${baseName}${extension}`);
|
|
145
|
+
if (!fs__default.default.existsSync(firstFilePath)) {
|
|
146
|
+
return firstFilePath;
|
|
147
|
+
}
|
|
148
|
+
return getNextFilePath(dir, baseName, extension);
|
|
149
|
+
}
|
|
77
150
|
function deleteFile(filePath) {
|
|
78
151
|
if (fs__default.default.existsSync(filePath)) {
|
|
79
152
|
fs__default.default.unlinkSync(filePath);
|
|
@@ -87,16 +160,105 @@ function createReportDirectory() {
|
|
|
87
160
|
fs__default.default.mkdirSync(REPORT_DIR, { recursive: true });
|
|
88
161
|
}
|
|
89
162
|
}
|
|
90
|
-
function getNowString() {
|
|
91
|
-
const
|
|
92
|
-
const YYYY = now.getFullYear();
|
|
93
|
-
const MM = String(now.getMonth() + 1).padStart(2, "0");
|
|
94
|
-
const DD = String(now.getDate()).padStart(2, "0");
|
|
95
|
-
const HH = String(now.getHours()).padStart(2, "0");
|
|
96
|
-
const mm = String(now.getMinutes()).padStart(2, "0");
|
|
97
|
-
const ss = String(now.getSeconds()).padStart(2, "0");
|
|
163
|
+
function getNowString(now = /* @__PURE__ */ new Date()) {
|
|
164
|
+
const { YYYY, MM, DD, HH, mm, ss } = getTimestampParts(now);
|
|
98
165
|
return `${YYYY}-${MM}-${DD}_${HH}-${mm}-${ss}`;
|
|
99
166
|
}
|
|
167
|
+
function getErrorLogTimestamp(now = /* @__PURE__ */ new Date()) {
|
|
168
|
+
const { YYYY, MM, DD, HH, mm, ss } = getTimestampParts(now);
|
|
169
|
+
return `${YYYY}-${MM}-${DD}-${HH}\uC2DC-${mm}\uBD84-${ss}\uCD08`;
|
|
170
|
+
}
|
|
171
|
+
function writeErrorReport(error, options = {}) {
|
|
172
|
+
try {
|
|
173
|
+
const now = /* @__PURE__ */ new Date();
|
|
174
|
+
helperTrace("error-report:write:start", options.scope || "unknown");
|
|
175
|
+
createReportDirectory();
|
|
176
|
+
const reportPath = getAvailableFilePath(REPORT_DIR, `error-log-${getErrorLogTimestamp(now)}`, ".md");
|
|
177
|
+
const serializedError = serializeError(error);
|
|
178
|
+
const traceSnapshot = options.traceMessages ?? getTraceMessages();
|
|
179
|
+
const extraSections = options.extraSections || [];
|
|
180
|
+
const report = `# Error Log
|
|
181
|
+
|
|
182
|
+
- \uBC1C\uC0DD \uC2DC\uAC01: ${getHumanReadableNowString(now)}
|
|
183
|
+
- Scope: \`${options.scope || "unknown"}\`
|
|
184
|
+
- \uC791\uC5C5 \uACBD\uB85C: \`${process.cwd()}\`
|
|
185
|
+
- \uC2E4\uD589 \uC778\uC790: \`${JSON.stringify(options.args ?? process.argv.slice(2))}\`
|
|
186
|
+
- \uC2E4\uD589 \uD658\uACBD: \`${process.platform} ${process.arch} / Node ${process.version}\`
|
|
187
|
+
|
|
188
|
+
## Summary
|
|
189
|
+
|
|
190
|
+
${options.title || serializedError.summary || "Unknown error"}
|
|
191
|
+
|
|
192
|
+
## Error
|
|
193
|
+
|
|
194
|
+
\`\`\`json
|
|
195
|
+
${JSON.stringify(serializedError, null, 2)}
|
|
196
|
+
\`\`\`
|
|
197
|
+
|
|
198
|
+
## Trace
|
|
199
|
+
|
|
200
|
+
\`\`\`json
|
|
201
|
+
${JSON.stringify(traceSnapshot, null, 2)}
|
|
202
|
+
\`\`\`${extraSections.length ? `
|
|
203
|
+
${extraSections.map((section) => `
|
|
204
|
+
## ${section.heading}
|
|
205
|
+
|
|
206
|
+
${section.markdown}`).join("\n")}
|
|
207
|
+
` : "\n"}
|
|
208
|
+
`;
|
|
209
|
+
fs__default.default.writeFileSync(reportPath, report);
|
|
210
|
+
helperTrace("error-report:write:done", reportPath);
|
|
211
|
+
return reportPath;
|
|
212
|
+
} catch (writeError) {
|
|
213
|
+
console.error("\u26A0\uFE0F \uC5D0\uB7EC \uB85C\uADF8 \uD30C\uC77C \uC0DD\uC131\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
|
|
214
|
+
console.error(writeError);
|
|
215
|
+
return "";
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
function exitWithError(message, options = {}) {
|
|
219
|
+
const reportPath = writeErrorReport(options.error || new Error(message), {
|
|
220
|
+
...options,
|
|
221
|
+
title: message
|
|
222
|
+
});
|
|
223
|
+
console.error(message);
|
|
224
|
+
if (options.error) {
|
|
225
|
+
console.error(options.error);
|
|
226
|
+
}
|
|
227
|
+
if (reportPath) {
|
|
228
|
+
console.error(`\u{1F4C4} \uC5D0\uB7EC \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${reportPath}`);
|
|
229
|
+
}
|
|
230
|
+
process.exit(1);
|
|
231
|
+
}
|
|
232
|
+
function parseServiceFromArgs(args4 = process.argv.slice(2)) {
|
|
233
|
+
helperTrace("parse-service:start", `args=${JSON.stringify(args4)}`);
|
|
234
|
+
const serviceIndex = args4.indexOf("--service");
|
|
235
|
+
const rawService = serviceIndex !== -1 ? args4[serviceIndex + 1] : "";
|
|
236
|
+
if (!rawService) {
|
|
237
|
+
helperTrace("parse-service:empty");
|
|
238
|
+
return "";
|
|
239
|
+
}
|
|
240
|
+
const normalizedService = rawService.toLowerCase();
|
|
241
|
+
if (AIServices.includes(normalizedService)) {
|
|
242
|
+
helperTrace("parse-service:resolved", normalizedService);
|
|
243
|
+
return normalizedService;
|
|
244
|
+
}
|
|
245
|
+
helperTrace("parse-service:invalid", rawService);
|
|
246
|
+
exitWithError(
|
|
247
|
+
`\u274C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uC11C\uBE44\uC2A4\uC785\uB2C8\uB2E4: ${rawService}. \uC0AC\uC6A9 \uAC00\uB2A5 \uAC12: ${AIServices.join(", ")} (\uC608: --service codex)`,
|
|
248
|
+
{
|
|
249
|
+
scope: "helper:parseServiceFromArgs",
|
|
250
|
+
args: args4,
|
|
251
|
+
extraSections: [
|
|
252
|
+
{
|
|
253
|
+
heading: "Allowed Services",
|
|
254
|
+
markdown: `\`\`\`json
|
|
255
|
+
${JSON.stringify(AIServices, null, 2)}
|
|
256
|
+
\`\`\``
|
|
257
|
+
}
|
|
258
|
+
]
|
|
259
|
+
}
|
|
260
|
+
);
|
|
261
|
+
}
|
|
100
262
|
function getGitDiffFilter() {
|
|
101
263
|
const includeExtensions = ["*.ts", "*.tsx", "*.js", "*.jsx"];
|
|
102
264
|
const excludePatterns = ignoreList.map((item) => `:(exclude)${item}`);
|
|
@@ -108,6 +270,7 @@ function getGitDiffFilter() {
|
|
|
108
270
|
function openReport(reportPath) {
|
|
109
271
|
const resolvedPath = path__default.default.resolve(reportPath);
|
|
110
272
|
const { platform } = process;
|
|
273
|
+
helperTrace("open-report:start", resolvedPath);
|
|
111
274
|
const openWithChrome = () => {
|
|
112
275
|
if (platform === "darwin") {
|
|
113
276
|
child_process.execSync(`open -a "Google Chrome" "${resolvedPath}"`, { stdio: "ignore" });
|
|
@@ -132,32 +295,41 @@ function openReport(reportPath) {
|
|
|
132
295
|
};
|
|
133
296
|
try {
|
|
134
297
|
if (openWithChrome()) {
|
|
298
|
+
helperTrace("open-report:chrome:success", platform);
|
|
135
299
|
console.log("\u{1F680} Google Chrome\uC5D0\uC11C \uB9AC\uD3EC\uD2B8\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
136
300
|
return;
|
|
137
301
|
}
|
|
138
|
-
} catch {
|
|
302
|
+
} catch (error) {
|
|
303
|
+
helperTrace("open-report:chrome:failed", getErrorSummary(error));
|
|
139
304
|
}
|
|
140
305
|
try {
|
|
141
306
|
if (openWithDefaultBrowser()) {
|
|
307
|
+
helperTrace("open-report:default-browser:success", platform);
|
|
142
308
|
console.log("\u{1F680} \uAE30\uBCF8 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB9AC\uD3EC\uD2B8\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
143
309
|
return;
|
|
144
310
|
}
|
|
145
|
-
} catch (
|
|
146
|
-
|
|
311
|
+
} catch (error) {
|
|
312
|
+
helperTrace("open-report:default-browser:failed", getErrorSummary(error));
|
|
313
|
+
console.error("\u26A0\uFE0F \uBE0C\uB77C\uC6B0\uC800 \uC5F4\uAE30 \uC2E4\uD328:", error);
|
|
147
314
|
return;
|
|
148
315
|
}
|
|
316
|
+
helperTrace("open-report:unsupported-platform", platform);
|
|
149
317
|
console.error(`\u26A0\uFE0F \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD50C\uB7AB\uD3FC\uC785\uB2C8\uB2E4: ${platform}`);
|
|
150
318
|
}
|
|
151
319
|
function getDiffArgs() {
|
|
152
320
|
const args4 = process.argv.slice(2);
|
|
153
321
|
const commitIndex = args4.indexOf("--commit");
|
|
154
322
|
const { includeParams, excludeParams } = getGitDiffFilter();
|
|
323
|
+
helperTrace("diff-args:resolve:start", `args=${JSON.stringify(args4)}`);
|
|
155
324
|
let diffArgs = "";
|
|
156
325
|
if (commitIndex !== -1) {
|
|
157
326
|
const commitHash = args4[commitIndex + 1];
|
|
158
327
|
if (!commitHash) {
|
|
159
|
-
|
|
160
|
-
|
|
328
|
+
helperTrace("diff-args:commit-hash-missing");
|
|
329
|
+
exitWithError("\u274C \uCEE4\uBC0B \uD574\uC2DC\uAC00 \uC81C\uACF5\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.", {
|
|
330
|
+
scope: "helper:getDiffArgs",
|
|
331
|
+
args: args4
|
|
332
|
+
});
|
|
161
333
|
}
|
|
162
334
|
const nextArg = args4[commitIndex + 2];
|
|
163
335
|
let n = 0;
|
|
@@ -167,28 +339,37 @@ function getDiffArgs() {
|
|
|
167
339
|
n = 0;
|
|
168
340
|
}
|
|
169
341
|
}
|
|
342
|
+
helperTrace("diff-args:commit-mode", `${commitHash}~${n + 1} ${commitHash}`);
|
|
170
343
|
console.log(`\u2139\uFE0F \uCEE4\uBC0B '${commitHash}' ${n > 0 ? ` \uD3EC\uD568 \uCD1D ${n + 1}\uAC1C\uC758 \uCEE4\uBC0B` : ""}\uC744 \uB9AC\uBDF0\uD569\uB2C8\uB2E4...`);
|
|
171
344
|
diffArgs = `${commitHash}~${n + 1} ${commitHash}`;
|
|
172
345
|
} else {
|
|
173
346
|
try {
|
|
347
|
+
helperTrace("diff-args:unstaged-check:start");
|
|
174
348
|
const check = child_process.execSync(`git diff --name-only -- ${includeParams} ${excludeParams}`).toString();
|
|
175
349
|
if (!check.trim()) {
|
|
350
|
+
helperTrace("diff-args:unstaged-check:empty", "use HEAD~1 HEAD");
|
|
176
351
|
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...");
|
|
177
352
|
diffArgs = "HEAD~1 HEAD";
|
|
353
|
+
} else {
|
|
354
|
+
helperTrace("diff-args:unstaged-check:has-changes", `length=${check.length}`);
|
|
178
355
|
}
|
|
179
|
-
} catch {
|
|
356
|
+
} catch (error) {
|
|
357
|
+
helperTrace("diff-args:unstaged-check:failed", getErrorSummary(error));
|
|
180
358
|
}
|
|
181
359
|
}
|
|
360
|
+
helperTrace("diff-args:resolve:done", diffArgs || "(default)");
|
|
182
361
|
return diffArgs;
|
|
183
362
|
}
|
|
184
363
|
async function showSelectionAIService() {
|
|
185
364
|
const selectedServiceFromArgs = parseServiceFromArgs();
|
|
186
365
|
if (selectedServiceFromArgs) {
|
|
366
|
+
helperTrace("show-selection:from-args", selectedServiceFromArgs);
|
|
187
367
|
console.log(`
|
|
188
368
|
\u2705 \x1B[32m${selectedServiceFromArgs}\x1B[0m \uC11C\uBE44\uC2A4\uAC00 \uC120\uD0DD\uB418\uC5C8\uC2B5\uB2C8\uB2E4. (--service)
|
|
189
369
|
`);
|
|
190
370
|
return selectedServiceFromArgs;
|
|
191
371
|
}
|
|
372
|
+
helperTrace("show-selection:interactive:start");
|
|
192
373
|
let selectedIndex = 0;
|
|
193
374
|
const rl = readline__default.default.createInterface({
|
|
194
375
|
input: process.stdin,
|
|
@@ -202,6 +383,7 @@ async function showSelectionAIService() {
|
|
|
202
383
|
readline__default.default.moveCursor(process.stdout, 0, -(AIServices.length + 1));
|
|
203
384
|
}
|
|
204
385
|
firstRender = false;
|
|
386
|
+
helperTrace("show-selection:interactive:render", AIServices[selectedIndex] || "unknown");
|
|
205
387
|
readline__default.default.clearScreenDown(process.stdout);
|
|
206
388
|
process.stdout.write(
|
|
207
389
|
"\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"
|
|
@@ -221,6 +403,7 @@ async function showSelectionAIService() {
|
|
|
221
403
|
const onData = (data) => {
|
|
222
404
|
const key = data.toString();
|
|
223
405
|
if (key === "") {
|
|
406
|
+
helperTrace("show-selection:interactive:ctrl-c");
|
|
224
407
|
process.stdout.write("\x1B[?25h");
|
|
225
408
|
process.exit(0);
|
|
226
409
|
}
|
|
@@ -241,6 +424,7 @@ async function showSelectionAIService() {
|
|
|
241
424
|
`);
|
|
242
425
|
const result = AIServices[selectedIndex];
|
|
243
426
|
if (result) {
|
|
427
|
+
helperTrace("show-selection:interactive:confirmed", result);
|
|
244
428
|
resolve(result);
|
|
245
429
|
}
|
|
246
430
|
}
|
|
@@ -360,8 +544,11 @@ var createClaudeCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
|
360
544
|
trace("reviewForm:status", reviewFormExists ? "exists" : "missing");
|
|
361
545
|
const systemPromptFiles = reviewFormExists ? [...existingRuleFiles, reviewFormPath2] : existingRuleFiles;
|
|
362
546
|
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.";
|
|
547
|
+
trace("prompt:prepared", `length=${prompt.length}`);
|
|
548
|
+
trace("system-prompt-files", `count=${systemPromptFiles.length}`);
|
|
363
549
|
const modelCandidates = toUnique(customModel ? [customModel, ...aliasFallbacks] : aliasFallbacks);
|
|
364
550
|
trace("model:candidates", modelCandidates.join(", "));
|
|
551
|
+
trace("command:candidates:count", String(modelCandidates.length + 1));
|
|
365
552
|
if (customModel) {
|
|
366
553
|
console.warn(
|
|
367
554
|
`\u26A0\uFE0F \uCEE4\uC2A4\uD140 \uBAA8\uB378(${customModel})\uC744 \uC6B0\uC120 \uC2DC\uB3C4\uD558\uACE0 \uC2E4\uD328\uD558\uBA74 alias(${aliasFallbacks.join(
|
|
@@ -402,6 +589,7 @@ var createClaudeCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
|
402
589
|
\uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
|
|
403
590
|
${safeCommand}"`;
|
|
404
591
|
}
|
|
592
|
+
trace("command:mode", "execute");
|
|
405
593
|
trace("createClaudeCommand:end");
|
|
406
594
|
return command;
|
|
407
595
|
};
|
|
@@ -412,23 +600,25 @@ function checkClaudeCliInstalled() {
|
|
|
412
600
|
trace2("version-check:run", "claude --version");
|
|
413
601
|
child_process.execSync("claude --version", { stdio: "ignore" });
|
|
414
602
|
trace2("version-check:ok");
|
|
415
|
-
} catch {
|
|
416
|
-
trace2("version-check:failed",
|
|
603
|
+
} catch (error) {
|
|
604
|
+
trace2("version-check:failed", getErrorSummary(error));
|
|
605
|
+
trace2("install:start", "@anthropic-ai/claude-code");
|
|
417
606
|
console.log(
|
|
418
607
|
"\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"
|
|
419
608
|
);
|
|
420
609
|
try {
|
|
421
610
|
child_process.execSync("npm install -g @anthropic-ai/claude-code", { stdio: "inherit" });
|
|
422
|
-
trace2("install:ok", "
|
|
611
|
+
trace2("install:ok", "login-required");
|
|
423
612
|
console.log("\u2705 claude-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
424
613
|
console.log("\u26A0\uFE0F claude-cli \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
425
614
|
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.');
|
|
426
615
|
process.exit(1);
|
|
427
616
|
} catch (installError) {
|
|
428
|
-
trace2("install:failed");
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
617
|
+
trace2("install:failed", getErrorSummary(installError));
|
|
618
|
+
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).", {
|
|
619
|
+
scope: "installation-claude",
|
|
620
|
+
error: installError
|
|
621
|
+
});
|
|
432
622
|
}
|
|
433
623
|
}
|
|
434
624
|
trace2("checkClaudeCliInstalled:end");
|
|
@@ -494,6 +684,7 @@ ${reviewFormLine || "- (\uC5C6\uC74C)"}
|
|
|
494
684
|
- ${tempDiffPath2}
|
|
495
685
|
|
|
496
686
|
\uBC18\uB4DC\uC2DC \uB9AC\uBDF0 \uC591\uC2DD\uC5D0 \uB9DE\uCDB0 \uC791\uC131\uD574\uC918.`;
|
|
687
|
+
trace3("prompt:prepared", `length=${prompt.length}`);
|
|
497
688
|
let command = "";
|
|
498
689
|
if (customModel) {
|
|
499
690
|
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.");
|
|
@@ -519,6 +710,7 @@ ${reviewFormLine || "- (\uC5C6\uC74C)"}
|
|
|
519
710
|
\uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
|
|
520
711
|
${safeCommand}"`;
|
|
521
712
|
}
|
|
713
|
+
trace3("command:mode", "execute");
|
|
522
714
|
trace3("createCodexCommand:end");
|
|
523
715
|
return command;
|
|
524
716
|
};
|
|
@@ -529,21 +721,23 @@ function checkCodexCliInstalled() {
|
|
|
529
721
|
trace4("version-check:run", "codex --version");
|
|
530
722
|
child_process.execSync("codex --version", { stdio: "ignore" });
|
|
531
723
|
trace4("version-check:ok");
|
|
532
|
-
} catch {
|
|
533
|
-
trace4("version-check:failed",
|
|
724
|
+
} catch (error) {
|
|
725
|
+
trace4("version-check:failed", getErrorSummary(error));
|
|
726
|
+
trace4("install:start", "@openai/codex");
|
|
534
727
|
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");
|
|
535
728
|
try {
|
|
536
729
|
child_process.execSync("npm install -g @openai/codex", { stdio: "inherit" });
|
|
537
|
-
trace4("install:ok", "
|
|
730
|
+
trace4("install:ok", "login-required");
|
|
538
731
|
console.log("\u2705 codex-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
539
732
|
console.log("\u26A0\uFE0F codex-cli \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
540
733
|
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.');
|
|
541
734
|
process.exit(1);
|
|
542
735
|
} catch (installError) {
|
|
543
|
-
trace4("install:failed");
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
736
|
+
trace4("install:failed", getErrorSummary(installError));
|
|
737
|
+
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).", {
|
|
738
|
+
scope: "installation-codex",
|
|
739
|
+
error: installError
|
|
740
|
+
});
|
|
547
741
|
}
|
|
548
742
|
}
|
|
549
743
|
trace4("checkCodexCliInstalled:end");
|
|
@@ -660,8 +854,10 @@ var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
|
660
854
|
const prompt = `\uB2E4\uC74C \uADDC\uCE59\uB4E4\uC744 \uCC38\uACE0\uD574\uC11C(${validRules || "(\uC5C6\uC74C)"}) \uC774 diff(@${tempDiffPath2})\uB97C \uB9AC\uBDF0\uD574\uC918.
|
|
661
855
|
\uB9AC\uBDF0 \uC591\uC2DD\uC740 ${reviewFormRef} \uC5D0 \uB9DE\uCDB0\uC11C \uC791\uC131\uD574\uC918.
|
|
662
856
|
\uCD94\uB860 \uAC15\uB3C4 \uC9C0\uCE68: ${reasoningInstruction}`;
|
|
857
|
+
trace5("prompt:prepared", `length=${prompt.length}`);
|
|
663
858
|
const modelCandidates = toUnique2(customModel ? [customModel, ...aliasFallbacks] : aliasFallbacks);
|
|
664
859
|
trace5("model:candidates", modelCandidates.join(", "));
|
|
860
|
+
trace5("command:candidates:count", String(modelCandidates.length + 1));
|
|
665
861
|
if (customModel) {
|
|
666
862
|
console.warn(
|
|
667
863
|
`\u26A0\uFE0F \uCEE4\uC2A4\uD140 \uBAA8\uB378(${customModel})\uC744 \uC6B0\uC120 \uC2DC\uB3C4\uD558\uACE0 \uC2E4\uD328\uD558\uBA74 alias(${aliasFallbacks.join(
|
|
@@ -684,6 +880,7 @@ var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
|
684
880
|
\uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
|
|
685
881
|
${safeCommand}"`;
|
|
686
882
|
}
|
|
883
|
+
trace5("command:mode", "execute");
|
|
687
884
|
trace5("createGeminiCommand:end");
|
|
688
885
|
return command;
|
|
689
886
|
};
|
|
@@ -694,21 +891,23 @@ function checkGeminiCliInstalled() {
|
|
|
694
891
|
trace6("version-check:run", "gemini --version");
|
|
695
892
|
child_process.execSync("gemini --version", { stdio: "ignore" });
|
|
696
893
|
trace6("version-check:ok");
|
|
697
|
-
} catch {
|
|
698
|
-
trace6("version-check:failed",
|
|
894
|
+
} catch (error) {
|
|
895
|
+
trace6("version-check:failed", getErrorSummary(error));
|
|
896
|
+
trace6("install:start", "@google/gemini-cli");
|
|
699
897
|
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");
|
|
700
898
|
try {
|
|
701
899
|
child_process.execSync("npm install -g @google/gemini-cli", { stdio: "inherit" });
|
|
702
|
-
trace6("install:ok", "
|
|
900
|
+
trace6("install:ok", "login-required");
|
|
703
901
|
console.log("\u2705 gemini-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
704
902
|
console.log("\u26A0\uFE0F Gemini API \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
705
903
|
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.');
|
|
706
904
|
process.exit(1);
|
|
707
905
|
} catch (installError) {
|
|
708
|
-
trace6("install:failed");
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
906
|
+
trace6("install:failed", getErrorSummary(installError));
|
|
907
|
+
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).", {
|
|
908
|
+
scope: "installation-gemini",
|
|
909
|
+
error: installError
|
|
910
|
+
});
|
|
712
911
|
}
|
|
713
912
|
}
|
|
714
913
|
trace6("checkGeminiCliInstalled:end");
|
|
@@ -717,30 +916,35 @@ function checkGeminiCliInstalled() {
|
|
|
717
916
|
// src/pr-review/review.ts
|
|
718
917
|
async function main() {
|
|
719
918
|
const args4 = process.argv.slice(2);
|
|
919
|
+
clearTraceMessages();
|
|
720
920
|
const isTest = isTestMode(args4);
|
|
721
921
|
const trace7 = createTraceLogger("review", args4);
|
|
722
922
|
trace7("main:start", `args=${JSON.stringify(args4)}`);
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
case "gemini":
|
|
728
|
-
trace7("install-check:start", "service=gemini");
|
|
729
|
-
checkGeminiCliInstalled();
|
|
730
|
-
trace7("install-check:done", "service=gemini");
|
|
731
|
-
break;
|
|
732
|
-
case "claude":
|
|
733
|
-
trace7("install-check:start", "service=claude");
|
|
734
|
-
checkClaudeCliInstalled();
|
|
735
|
-
trace7("install-check:done", "service=claude");
|
|
736
|
-
break;
|
|
737
|
-
case "codex":
|
|
738
|
-
trace7("install-check:start", "service=codex");
|
|
739
|
-
checkCodexCliInstalled();
|
|
740
|
-
trace7("install-check:done", "service=codex");
|
|
741
|
-
break;
|
|
742
|
-
}
|
|
923
|
+
let command = "";
|
|
924
|
+
let savedDiffPath = "";
|
|
925
|
+
let savedReportPath = "";
|
|
926
|
+
let service = "";
|
|
743
927
|
try {
|
|
928
|
+
trace7("service-selection:start");
|
|
929
|
+
service = await showSelectionAIService();
|
|
930
|
+
trace7("service-selection:done", `service=${service}`);
|
|
931
|
+
switch (service) {
|
|
932
|
+
case "gemini":
|
|
933
|
+
trace7("install-check:start", "service=gemini");
|
|
934
|
+
checkGeminiCliInstalled();
|
|
935
|
+
trace7("install-check:done", "service=gemini");
|
|
936
|
+
break;
|
|
937
|
+
case "claude":
|
|
938
|
+
trace7("install-check:start", "service=claude");
|
|
939
|
+
checkClaudeCliInstalled();
|
|
940
|
+
trace7("install-check:done", "service=claude");
|
|
941
|
+
break;
|
|
942
|
+
case "codex":
|
|
943
|
+
trace7("install-check:start", "service=codex");
|
|
944
|
+
checkCodexCliInstalled();
|
|
945
|
+
trace7("install-check:done", "service=codex");
|
|
946
|
+
break;
|
|
947
|
+
}
|
|
744
948
|
trace7("review-flow:start");
|
|
745
949
|
console.log("\u{1F680} AI Code Review\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4...");
|
|
746
950
|
const nowStr = getNowString();
|
|
@@ -758,8 +962,8 @@ async function main() {
|
|
|
758
962
|
trace7("git-diff:run");
|
|
759
963
|
diff = child_process.execSync(`git diff ${diffArgs} -- ${includeParams} ${excludeParams}`).toString();
|
|
760
964
|
trace7("git-diff:done", `length=${diff.length}`);
|
|
761
|
-
} catch {
|
|
762
|
-
trace7("git-diff:error",
|
|
965
|
+
} catch (error) {
|
|
966
|
+
trace7("git-diff:error", getErrorSummary(error));
|
|
763
967
|
}
|
|
764
968
|
if (!diff.trim() && !isTest) {
|
|
765
969
|
trace7("empty-diff:exit");
|
|
@@ -771,10 +975,9 @@ async function main() {
|
|
|
771
975
|
fs__default.default.writeFileSync(tempDiffPath, diff);
|
|
772
976
|
trace7("temp-diff:write:done");
|
|
773
977
|
trace7("saved-diff:copy:start");
|
|
774
|
-
|
|
978
|
+
savedDiffPath = getNextFilePath(REPORT_DIR, `${nowStr}-diff`, ".txt");
|
|
775
979
|
fs__default.default.copyFileSync(tempDiffPath, savedDiffPath);
|
|
776
980
|
trace7("saved-diff:copy:done", savedDiffPath);
|
|
777
|
-
let command = "";
|
|
778
981
|
trace7("command:create:start", `service=${service}`);
|
|
779
982
|
switch (service) {
|
|
780
983
|
case "gemini":
|
|
@@ -793,7 +996,7 @@ async function main() {
|
|
|
793
996
|
trace7("command:exec:done", `resultLength=${result.length}`);
|
|
794
997
|
console.log(result);
|
|
795
998
|
trace7("report:write:start");
|
|
796
|
-
|
|
999
|
+
savedReportPath = getNextFilePath(REPORT_DIR, nowStr, ".md");
|
|
797
1000
|
fs__default.default.writeFileSync(savedReportPath, result);
|
|
798
1001
|
trace7("report:write:done", savedReportPath);
|
|
799
1002
|
if (isTest) {
|
|
@@ -817,12 +1020,45 @@ ${command}`);
|
|
|
817
1020
|
trace7("cleanup-temp-diff:done");
|
|
818
1021
|
trace7("review-flow:end");
|
|
819
1022
|
} catch (error) {
|
|
820
|
-
trace7("review-flow:catch");
|
|
1023
|
+
trace7("review-flow:catch", getErrorSummary(error));
|
|
1024
|
+
let errorReportPath = "";
|
|
1025
|
+
trace7("cleanup-temp-diff:start(catch)");
|
|
1026
|
+
try {
|
|
1027
|
+
deleteTempDiff();
|
|
1028
|
+
trace7("cleanup-temp-diff:done(catch)");
|
|
1029
|
+
} catch (cleanupError) {
|
|
1030
|
+
trace7("cleanup-temp-diff:failed(catch)", getErrorSummary(cleanupError));
|
|
1031
|
+
console.error("\u26A0\uFE0F \uC784\uC2DC diff \uC815\uB9AC \uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
|
|
1032
|
+
console.error(cleanupError);
|
|
1033
|
+
}
|
|
1034
|
+
trace7("error-report:prepare", `service=${service}`);
|
|
1035
|
+
errorReportPath = writeErrorReport(error, {
|
|
1036
|
+
scope: "review",
|
|
1037
|
+
args: args4,
|
|
1038
|
+
extraSections: [
|
|
1039
|
+
{
|
|
1040
|
+
heading: "Execution Context",
|
|
1041
|
+
markdown: `\`\`\`json
|
|
1042
|
+
${JSON.stringify(
|
|
1043
|
+
{
|
|
1044
|
+
service,
|
|
1045
|
+
command: command || null,
|
|
1046
|
+
tempDiffPath,
|
|
1047
|
+
savedDiffPath: savedDiffPath || null,
|
|
1048
|
+
savedReportPath: savedReportPath || null
|
|
1049
|
+
},
|
|
1050
|
+
null,
|
|
1051
|
+
2
|
|
1052
|
+
)}
|
|
1053
|
+
\`\`\``
|
|
1054
|
+
}
|
|
1055
|
+
]
|
|
1056
|
+
});
|
|
821
1057
|
console.error("\u274C \uB9AC\uBDF0 \uB3C4\uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
|
|
822
1058
|
console.error(error);
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
1059
|
+
if (errorReportPath) {
|
|
1060
|
+
console.error(`\u{1F4C4} \uC5D0\uB7EC \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${errorReportPath}`);
|
|
1061
|
+
}
|
|
826
1062
|
process.exit(1);
|
|
827
1063
|
}
|
|
828
1064
|
}
|