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
|
@@ -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");
|
|
@@ -40,15 +42,94 @@ var ignoreList = [
|
|
|
40
42
|
function isTestMode(args4 = process.argv.slice(2)) {
|
|
41
43
|
return args4.includes("--test");
|
|
42
44
|
}
|
|
45
|
+
function clearTraceMessages() {
|
|
46
|
+
traceMessages.length = 0;
|
|
47
|
+
}
|
|
48
|
+
function getTraceMessages() {
|
|
49
|
+
return [...traceMessages];
|
|
50
|
+
}
|
|
43
51
|
function createTraceLogger(scope, args4 = process.argv.slice(2)) {
|
|
44
52
|
const enabled = isTestMode(args4);
|
|
45
53
|
return (step, detail) => {
|
|
54
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
55
|
+
const message = `[${timestamp}][TRACE][${scope}] ${step}${detail ? ` | ${detail}` : ""}`;
|
|
56
|
+
traceMessages.push(message);
|
|
46
57
|
if (!enabled) {
|
|
47
58
|
return;
|
|
48
59
|
}
|
|
49
|
-
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")
|
|
50
72
|
};
|
|
51
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)
|
|
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;
|
|
132
|
+
}
|
|
52
133
|
function getNextFilePath(dir, baseName, extension) {
|
|
53
134
|
let counter = 1;
|
|
54
135
|
while (true) {
|
|
@@ -59,6 +140,13 @@ function getNextFilePath(dir, baseName, extension) {
|
|
|
59
140
|
counter++;
|
|
60
141
|
}
|
|
61
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
|
+
}
|
|
62
150
|
function deleteFile(filePath) {
|
|
63
151
|
if (fs__default.default.existsSync(filePath)) {
|
|
64
152
|
fs__default.default.unlinkSync(filePath);
|
|
@@ -72,16 +160,105 @@ function createReportDirectory() {
|
|
|
72
160
|
fs__default.default.mkdirSync(REPORT_DIR, { recursive: true });
|
|
73
161
|
}
|
|
74
162
|
}
|
|
75
|
-
function getNowString() {
|
|
76
|
-
const
|
|
77
|
-
const YYYY = now.getFullYear();
|
|
78
|
-
const MM = String(now.getMonth() + 1).padStart(2, "0");
|
|
79
|
-
const DD = String(now.getDate()).padStart(2, "0");
|
|
80
|
-
const HH = String(now.getHours()).padStart(2, "0");
|
|
81
|
-
const mm = String(now.getMinutes()).padStart(2, "0");
|
|
82
|
-
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);
|
|
83
165
|
return `${YYYY}-${MM}-${DD}_${HH}-${mm}-${ss}`;
|
|
84
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
|
+
}
|
|
85
262
|
function getGitDiffFilter() {
|
|
86
263
|
const includeExtensions = ["*.ts", "*.tsx", "*.js", "*.jsx"];
|
|
87
264
|
const excludePatterns = ignoreList.map((item) => `:(exclude)${item}`);
|
|
@@ -93,6 +270,7 @@ function getGitDiffFilter() {
|
|
|
93
270
|
function openReport(reportPath) {
|
|
94
271
|
const resolvedPath = path__default.default.resolve(reportPath);
|
|
95
272
|
const { platform } = process;
|
|
273
|
+
helperTrace("open-report:start", resolvedPath);
|
|
96
274
|
const openWithChrome = () => {
|
|
97
275
|
if (platform === "darwin") {
|
|
98
276
|
child_process.execSync(`open -a "Google Chrome" "${resolvedPath}"`, { stdio: "ignore" });
|
|
@@ -117,32 +295,41 @@ function openReport(reportPath) {
|
|
|
117
295
|
};
|
|
118
296
|
try {
|
|
119
297
|
if (openWithChrome()) {
|
|
298
|
+
helperTrace("open-report:chrome:success", platform);
|
|
120
299
|
console.log("\u{1F680} Google Chrome\uC5D0\uC11C \uB9AC\uD3EC\uD2B8\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
121
300
|
return;
|
|
122
301
|
}
|
|
123
|
-
} catch {
|
|
302
|
+
} catch (error) {
|
|
303
|
+
helperTrace("open-report:chrome:failed", getErrorSummary(error));
|
|
124
304
|
}
|
|
125
305
|
try {
|
|
126
306
|
if (openWithDefaultBrowser()) {
|
|
307
|
+
helperTrace("open-report:default-browser:success", platform);
|
|
127
308
|
console.log("\u{1F680} \uAE30\uBCF8 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB9AC\uD3EC\uD2B8\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
128
309
|
return;
|
|
129
310
|
}
|
|
130
|
-
} catch (
|
|
131
|
-
|
|
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);
|
|
132
314
|
return;
|
|
133
315
|
}
|
|
316
|
+
helperTrace("open-report:unsupported-platform", platform);
|
|
134
317
|
console.error(`\u26A0\uFE0F \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD50C\uB7AB\uD3FC\uC785\uB2C8\uB2E4: ${platform}`);
|
|
135
318
|
}
|
|
136
319
|
function getDiffArgs() {
|
|
137
320
|
const args4 = process.argv.slice(2);
|
|
138
321
|
const commitIndex = args4.indexOf("--commit");
|
|
139
322
|
const { includeParams, excludeParams } = getGitDiffFilter();
|
|
323
|
+
helperTrace("diff-args:resolve:start", `args=${JSON.stringify(args4)}`);
|
|
140
324
|
let diffArgs = "";
|
|
141
325
|
if (commitIndex !== -1) {
|
|
142
326
|
const commitHash = args4[commitIndex + 1];
|
|
143
327
|
if (!commitHash) {
|
|
144
|
-
|
|
145
|
-
|
|
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
|
+
});
|
|
146
333
|
}
|
|
147
334
|
const nextArg = args4[commitIndex + 2];
|
|
148
335
|
let n = 0;
|
|
@@ -152,21 +339,37 @@ function getDiffArgs() {
|
|
|
152
339
|
n = 0;
|
|
153
340
|
}
|
|
154
341
|
}
|
|
342
|
+
helperTrace("diff-args:commit-mode", `${commitHash}~${n + 1} ${commitHash}`);
|
|
155
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...`);
|
|
156
344
|
diffArgs = `${commitHash}~${n + 1} ${commitHash}`;
|
|
157
345
|
} else {
|
|
158
346
|
try {
|
|
347
|
+
helperTrace("diff-args:unstaged-check:start");
|
|
159
348
|
const check = child_process.execSync(`git diff --name-only -- ${includeParams} ${excludeParams}`).toString();
|
|
160
349
|
if (!check.trim()) {
|
|
350
|
+
helperTrace("diff-args:unstaged-check:empty", "use HEAD~1 HEAD");
|
|
161
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...");
|
|
162
352
|
diffArgs = "HEAD~1 HEAD";
|
|
353
|
+
} else {
|
|
354
|
+
helperTrace("diff-args:unstaged-check:has-changes", `length=${check.length}`);
|
|
163
355
|
}
|
|
164
|
-
} catch {
|
|
356
|
+
} catch (error) {
|
|
357
|
+
helperTrace("diff-args:unstaged-check:failed", getErrorSummary(error));
|
|
165
358
|
}
|
|
166
359
|
}
|
|
360
|
+
helperTrace("diff-args:resolve:done", diffArgs || "(default)");
|
|
167
361
|
return diffArgs;
|
|
168
362
|
}
|
|
169
363
|
async function showSelectionAIService() {
|
|
364
|
+
const selectedServiceFromArgs = parseServiceFromArgs();
|
|
365
|
+
if (selectedServiceFromArgs) {
|
|
366
|
+
helperTrace("show-selection:from-args", selectedServiceFromArgs);
|
|
367
|
+
console.log(`
|
|
368
|
+
\u2705 \x1B[32m${selectedServiceFromArgs}\x1B[0m \uC11C\uBE44\uC2A4\uAC00 \uC120\uD0DD\uB418\uC5C8\uC2B5\uB2C8\uB2E4. (--service)
|
|
369
|
+
`);
|
|
370
|
+
return selectedServiceFromArgs;
|
|
371
|
+
}
|
|
372
|
+
helperTrace("show-selection:interactive:start");
|
|
170
373
|
let selectedIndex = 0;
|
|
171
374
|
const rl = readline__default.default.createInterface({
|
|
172
375
|
input: process.stdin,
|
|
@@ -180,6 +383,7 @@ async function showSelectionAIService() {
|
|
|
180
383
|
readline__default.default.moveCursor(process.stdout, 0, -(AIServices.length + 1));
|
|
181
384
|
}
|
|
182
385
|
firstRender = false;
|
|
386
|
+
helperTrace("show-selection:interactive:render", AIServices[selectedIndex] || "unknown");
|
|
183
387
|
readline__default.default.clearScreenDown(process.stdout);
|
|
184
388
|
process.stdout.write(
|
|
185
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"
|
|
@@ -199,6 +403,7 @@ async function showSelectionAIService() {
|
|
|
199
403
|
const onData = (data) => {
|
|
200
404
|
const key = data.toString();
|
|
201
405
|
if (key === "") {
|
|
406
|
+
helperTrace("show-selection:interactive:ctrl-c");
|
|
202
407
|
process.stdout.write("\x1B[?25h");
|
|
203
408
|
process.exit(0);
|
|
204
409
|
}
|
|
@@ -219,6 +424,7 @@ async function showSelectionAIService() {
|
|
|
219
424
|
`);
|
|
220
425
|
const result = AIServices[selectedIndex];
|
|
221
426
|
if (result) {
|
|
427
|
+
helperTrace("show-selection:interactive:confirmed", result);
|
|
222
428
|
resolve(result);
|
|
223
429
|
}
|
|
224
430
|
}
|
|
@@ -230,40 +436,150 @@ async function showSelectionAIService() {
|
|
|
230
436
|
}
|
|
231
437
|
var args = process.argv.slice(2);
|
|
232
438
|
var trace = createTraceLogger("claude-commander", args);
|
|
233
|
-
var
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
console.warn("\u26A0\uFE0F \uBAA8\uB378\uC774 \uC9C0\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uAE30\uBCF8 \uBAA8\uB378\uC778 sonnet\uC744 \uC0AC\uC6A9\uD569\uB2C8\uB2E4.");
|
|
250
|
-
modelOption = "--model sonnet";
|
|
251
|
-
trace("model:default", modelOption);
|
|
439
|
+
var ALLOWED_REASONING_EFFORTS = ["minimal", "low", "medium", "high"];
|
|
440
|
+
function shellQuote(value) {
|
|
441
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
442
|
+
}
|
|
443
|
+
function getArgValue(flag) {
|
|
444
|
+
const index = args.indexOf(flag);
|
|
445
|
+
if (index === -1 || !args[index + 1]) {
|
|
446
|
+
return "";
|
|
447
|
+
}
|
|
448
|
+
return args[index + 1];
|
|
449
|
+
}
|
|
450
|
+
function toUnique(values) {
|
|
451
|
+
const seen = /* @__PURE__ */ new Set();
|
|
452
|
+
return values.filter((value) => {
|
|
453
|
+
if (!value || seen.has(value)) {
|
|
454
|
+
return false;
|
|
252
455
|
}
|
|
456
|
+
seen.add(value);
|
|
457
|
+
return true;
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
function normalizeEffort(level) {
|
|
461
|
+
if (level === "minimal") {
|
|
462
|
+
return "low";
|
|
253
463
|
}
|
|
464
|
+
return level;
|
|
465
|
+
}
|
|
466
|
+
function resolveReasoningEffort() {
|
|
467
|
+
const customReasoningEffort = getArgValue("--reasoning-effort") || getArgValue("--effort");
|
|
468
|
+
if (customReasoningEffort) {
|
|
469
|
+
if (ALLOWED_REASONING_EFFORTS.includes(customReasoningEffort)) {
|
|
470
|
+
const normalized = normalizeEffort(customReasoningEffort);
|
|
471
|
+
trace("reasoning:custom", `${customReasoningEffort} -> ${normalized}`);
|
|
472
|
+
if (customReasoningEffort === "minimal") {
|
|
473
|
+
console.warn("\u26A0\uFE0F Claude\uB294 minimal\uC744 \uC9C1\uC811 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC544 low\uB85C \uB9E4\uD551\uD569\uB2C8\uB2E4.");
|
|
474
|
+
}
|
|
475
|
+
return normalized;
|
|
476
|
+
}
|
|
477
|
+
console.warn(
|
|
478
|
+
`\u26A0\uFE0F \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 reasoning effort(${customReasoningEffort})\uC785\uB2C8\uB2E4. allowed: ${ALLOWED_REASONING_EFFORTS.join(
|
|
479
|
+
", "
|
|
480
|
+
)}`
|
|
481
|
+
);
|
|
482
|
+
}
|
|
483
|
+
if (args.includes("--flash")) {
|
|
484
|
+
trace("reasoning:flash-default", "low");
|
|
485
|
+
return "low";
|
|
486
|
+
}
|
|
487
|
+
if (args.includes("--review")) {
|
|
488
|
+
trace("reasoning:review-default", "high");
|
|
489
|
+
return "high";
|
|
490
|
+
}
|
|
491
|
+
trace("reasoning:default", "medium");
|
|
492
|
+
return "medium";
|
|
493
|
+
}
|
|
494
|
+
function resolvePrimaryAlias() {
|
|
495
|
+
if (args.includes("--review")) {
|
|
496
|
+
trace("model:mode-alias", "opus");
|
|
497
|
+
return "opus";
|
|
498
|
+
}
|
|
499
|
+
if (args.includes("--flash")) {
|
|
500
|
+
trace("model:mode-alias", "haiku");
|
|
501
|
+
return "haiku";
|
|
502
|
+
}
|
|
503
|
+
trace("model:default-alias", "sonnet");
|
|
504
|
+
return "sonnet";
|
|
505
|
+
}
|
|
506
|
+
function getAliasFallbacks(primaryAlias) {
|
|
507
|
+
if (primaryAlias === "opus") {
|
|
508
|
+
return ["opus", "sonnet", "haiku"];
|
|
509
|
+
}
|
|
510
|
+
if (primaryAlias === "haiku") {
|
|
511
|
+
return ["haiku", "sonnet"];
|
|
512
|
+
}
|
|
513
|
+
return [primaryAlias, "sonnet", "haiku"];
|
|
514
|
+
}
|
|
515
|
+
function buildClaudeExecCommand(options) {
|
|
516
|
+
const { tempDiffPath: tempDiffPath2, prompt, systemPromptFiles, effort, model, fallbackModel } = options;
|
|
517
|
+
const modelOption = model ? `--model ${shellQuote(model)}` : "";
|
|
518
|
+
const fallbackOption = model && fallbackModel ? `--fallback-model ${shellQuote(fallbackModel)}` : "";
|
|
519
|
+
const effortOption = `--effort ${shellQuote(effort)}`;
|
|
520
|
+
const appendedPromptFiles = systemPromptFiles.map((path2) => `--append-system-prompt-file ${shellQuote(path2)}`).join(" ");
|
|
521
|
+
return `cat ${shellQuote(tempDiffPath2)} | claude ${[
|
|
522
|
+
modelOption,
|
|
523
|
+
fallbackOption,
|
|
524
|
+
effortOption,
|
|
525
|
+
appendedPromptFiles,
|
|
526
|
+
"-p",
|
|
527
|
+
shellQuote(prompt)
|
|
528
|
+
].filter(Boolean).join(" ")}`;
|
|
529
|
+
}
|
|
530
|
+
var createClaudeCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
531
|
+
trace("createClaudeCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
|
|
532
|
+
const customModel = getArgValue("--model");
|
|
533
|
+
const effort = resolveReasoningEffort();
|
|
534
|
+
const primaryAlias = resolvePrimaryAlias();
|
|
535
|
+
const aliasFallbacks = toUnique(getAliasFallbacks(primaryAlias));
|
|
254
536
|
const rules = [
|
|
255
537
|
{ path: rulesPath, display: "\uB8F0\uC14B" },
|
|
256
538
|
{ path: namingRulesPath, display: "\uB124\uC774\uBC0D \uADDC\uCE59" },
|
|
257
539
|
{ path: codingConventionRulesPath, display: "\uCF54\uB529 \uCEE8\uBCA4\uC158" }
|
|
258
540
|
];
|
|
259
|
-
const
|
|
260
|
-
trace(
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
const
|
|
265
|
-
trace("
|
|
266
|
-
|
|
541
|
+
const existingRuleFiles = rules.filter((rule) => fs__default.default.existsSync(rule.path)).map((rule) => rule.path);
|
|
542
|
+
trace("rules:loaded", `count=${existingRuleFiles.length}`);
|
|
543
|
+
const reviewFormExists = fs__default.default.existsSync(reviewFormPath2);
|
|
544
|
+
trace("reviewForm:status", reviewFormExists ? "exists" : "missing");
|
|
545
|
+
const systemPromptFiles = reviewFormExists ? [...existingRuleFiles, reviewFormPath2] : existingRuleFiles;
|
|
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}`);
|
|
549
|
+
const modelCandidates = toUnique(customModel ? [customModel, ...aliasFallbacks] : aliasFallbacks);
|
|
550
|
+
trace("model:candidates", modelCandidates.join(", "));
|
|
551
|
+
trace("command:candidates:count", String(modelCandidates.length + 1));
|
|
552
|
+
if (customModel) {
|
|
553
|
+
console.warn(
|
|
554
|
+
`\u26A0\uFE0F \uCEE4\uC2A4\uD140 \uBAA8\uB378(${customModel})\uC744 \uC6B0\uC120 \uC2DC\uB3C4\uD558\uACE0 \uC2E4\uD328\uD558\uBA74 alias(${aliasFallbacks.join(
|
|
555
|
+
" -> "
|
|
556
|
+
)}) \uBC0F \uAE30\uBCF8 \uBAA8\uB378 \uC21C\uC73C\uB85C \uD3F4\uBC31\uD569\uB2C8\uB2E4.`
|
|
557
|
+
);
|
|
558
|
+
} else {
|
|
559
|
+
console.warn(
|
|
560
|
+
`\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.`
|
|
561
|
+
);
|
|
562
|
+
}
|
|
563
|
+
const commandCandidates = modelCandidates.map((model, index) => {
|
|
564
|
+
const fallbackModel = modelCandidates[index + 1];
|
|
565
|
+
return buildClaudeExecCommand({
|
|
566
|
+
tempDiffPath: tempDiffPath2,
|
|
567
|
+
prompt,
|
|
568
|
+
systemPromptFiles,
|
|
569
|
+
effort,
|
|
570
|
+
model,
|
|
571
|
+
fallbackModel
|
|
572
|
+
});
|
|
573
|
+
});
|
|
574
|
+
const command = [
|
|
575
|
+
...commandCandidates,
|
|
576
|
+
buildClaudeExecCommand({
|
|
577
|
+
tempDiffPath: tempDiffPath2,
|
|
578
|
+
prompt,
|
|
579
|
+
systemPromptFiles,
|
|
580
|
+
effort
|
|
581
|
+
})
|
|
582
|
+
].join(" || ");
|
|
267
583
|
trace("command:created");
|
|
268
584
|
if (args.includes("--test")) {
|
|
269
585
|
const safeCommand = command.replace(/"/g, '\\"');
|
|
@@ -273,6 +589,7 @@ var createClaudeCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
|
273
589
|
\uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
|
|
274
590
|
${safeCommand}"`;
|
|
275
591
|
}
|
|
592
|
+
trace("command:mode", "execute");
|
|
276
593
|
trace("createClaudeCommand:end");
|
|
277
594
|
return command;
|
|
278
595
|
};
|
|
@@ -283,50 +600,75 @@ function checkClaudeCliInstalled() {
|
|
|
283
600
|
trace2("version-check:run", "claude --version");
|
|
284
601
|
child_process.execSync("claude --version", { stdio: "ignore" });
|
|
285
602
|
trace2("version-check:ok");
|
|
286
|
-
} catch {
|
|
287
|
-
trace2("version-check:failed",
|
|
603
|
+
} catch (error) {
|
|
604
|
+
trace2("version-check:failed", getErrorSummary(error));
|
|
605
|
+
trace2("install:start", "@anthropic-ai/claude-code");
|
|
288
606
|
console.log(
|
|
289
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"
|
|
290
608
|
);
|
|
291
609
|
try {
|
|
292
610
|
child_process.execSync("npm install -g @anthropic-ai/claude-code", { stdio: "inherit" });
|
|
293
|
-
trace2("install:ok", "
|
|
611
|
+
trace2("install:ok", "login-required");
|
|
294
612
|
console.log("\u2705 claude-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
295
613
|
console.log("\u26A0\uFE0F claude-cli \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
296
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.');
|
|
297
615
|
process.exit(1);
|
|
298
616
|
} catch (installError) {
|
|
299
|
-
trace2("install:failed");
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
+
});
|
|
303
622
|
}
|
|
304
623
|
}
|
|
305
624
|
trace2("checkClaudeCliInstalled:end");
|
|
306
625
|
}
|
|
307
626
|
var args2 = process.argv.slice(2);
|
|
308
627
|
var trace3 = createTraceLogger("codex-commander", args2);
|
|
309
|
-
var
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
modelOption = "--model gpt-5-mini";
|
|
327
|
-
trace3("model:default", modelOption);
|
|
628
|
+
var ALLOWED_REASONING_EFFORTS2 = ["minimal", "low", "medium", "high"];
|
|
629
|
+
function shellQuote2(value) {
|
|
630
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
631
|
+
}
|
|
632
|
+
function getArgValue2(flag) {
|
|
633
|
+
const index = args2.indexOf(flag);
|
|
634
|
+
if (index === -1 || !args2[index + 1]) {
|
|
635
|
+
return "";
|
|
636
|
+
}
|
|
637
|
+
return args2[index + 1];
|
|
638
|
+
}
|
|
639
|
+
function resolveReasoningEffort2() {
|
|
640
|
+
const customReasoningEffort = getArgValue2("--reasoning-effort");
|
|
641
|
+
if (customReasoningEffort) {
|
|
642
|
+
if (ALLOWED_REASONING_EFFORTS2.includes(customReasoningEffort)) {
|
|
643
|
+
trace3("reasoning:custom", customReasoningEffort);
|
|
644
|
+
return customReasoningEffort;
|
|
328
645
|
}
|
|
646
|
+
console.warn(
|
|
647
|
+
`\u26A0\uFE0F \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 reasoning effort(${customReasoningEffort})\uC785\uB2C8\uB2E4. allowed: ${ALLOWED_REASONING_EFFORTS2.join(
|
|
648
|
+
", "
|
|
649
|
+
)}`
|
|
650
|
+
);
|
|
329
651
|
}
|
|
652
|
+
if (args2.includes("--flash")) {
|
|
653
|
+
trace3("reasoning:flash-default", "minimal");
|
|
654
|
+
return "minimal";
|
|
655
|
+
}
|
|
656
|
+
if (args2.includes("--review")) {
|
|
657
|
+
trace3("reasoning:review-default", "high");
|
|
658
|
+
return "high";
|
|
659
|
+
}
|
|
660
|
+
trace3("reasoning:default", "medium");
|
|
661
|
+
return "medium";
|
|
662
|
+
}
|
|
663
|
+
function buildCodexExecCommand(prompt, reasoningEffort, model) {
|
|
664
|
+
const modelOption = model ? `--model ${shellQuote2(model)}` : "";
|
|
665
|
+
const reasoningOption = `-c ${shellQuote2(`model_reasoning_effort="${reasoningEffort}"`)}`;
|
|
666
|
+
return `codex exec ${[modelOption, reasoningOption, shellQuote2(prompt)].filter(Boolean).join(" ")}`;
|
|
667
|
+
}
|
|
668
|
+
var createCodexCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
669
|
+
trace3("createCodexCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
|
|
670
|
+
const customModel = getArgValue2("--model");
|
|
671
|
+
const reasoningEffort = resolveReasoningEffort2();
|
|
330
672
|
const rules = [rulesPath, namingRulesPath, codingConventionRulesPath].filter((filePath) => fs__default.default.existsSync(filePath)).map((filePath) => `- ${filePath}`).join("\n");
|
|
331
673
|
const rulesCount = rules ? rules.split("\n").length : 0;
|
|
332
674
|
trace3("rules:loaded", `count=${rulesCount}`);
|
|
@@ -342,7 +684,23 @@ ${reviewFormLine || "- (\uC5C6\uC74C)"}
|
|
|
342
684
|
- ${tempDiffPath2}
|
|
343
685
|
|
|
344
686
|
\uBC18\uB4DC\uC2DC \uB9AC\uBDF0 \uC591\uC2DD\uC5D0 \uB9DE\uCDB0 \uC791\uC131\uD574\uC918.`;
|
|
345
|
-
|
|
687
|
+
trace3("prompt:prepared", `length=${prompt.length}`);
|
|
688
|
+
let command = "";
|
|
689
|
+
if (customModel) {
|
|
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.");
|
|
691
|
+
trace3("model:custom", customModel);
|
|
692
|
+
command = buildCodexExecCommand(prompt, reasoningEffort, customModel);
|
|
693
|
+
} else {
|
|
694
|
+
const preferredModelAlias = "gpt-5";
|
|
695
|
+
const aliasCommand = buildCodexExecCommand(prompt, reasoningEffort, preferredModelAlias);
|
|
696
|
+
const fallbackCommand = buildCodexExecCommand(prompt, reasoningEffort);
|
|
697
|
+
console.warn(
|
|
698
|
+
`\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.`
|
|
699
|
+
);
|
|
700
|
+
trace3("model:alias-first", preferredModelAlias);
|
|
701
|
+
trace3("model:fallback", "account-default");
|
|
702
|
+
command = `${aliasCommand} || ${fallbackCommand}`;
|
|
703
|
+
}
|
|
346
704
|
trace3("command:created");
|
|
347
705
|
if (args2.includes("--test")) {
|
|
348
706
|
const safeCommand = command.replace(/"/g, '\\"');
|
|
@@ -352,6 +710,7 @@ ${reviewFormLine || "- (\uC5C6\uC74C)"}
|
|
|
352
710
|
\uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
|
|
353
711
|
${safeCommand}"`;
|
|
354
712
|
}
|
|
713
|
+
trace3("command:mode", "execute");
|
|
355
714
|
trace3("createCodexCommand:end");
|
|
356
715
|
return command;
|
|
357
716
|
};
|
|
@@ -362,48 +721,125 @@ function checkCodexCliInstalled() {
|
|
|
362
721
|
trace4("version-check:run", "codex --version");
|
|
363
722
|
child_process.execSync("codex --version", { stdio: "ignore" });
|
|
364
723
|
trace4("version-check:ok");
|
|
365
|
-
} catch {
|
|
366
|
-
trace4("version-check:failed",
|
|
724
|
+
} catch (error) {
|
|
725
|
+
trace4("version-check:failed", getErrorSummary(error));
|
|
726
|
+
trace4("install:start", "@openai/codex");
|
|
367
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");
|
|
368
728
|
try {
|
|
369
729
|
child_process.execSync("npm install -g @openai/codex", { stdio: "inherit" });
|
|
370
|
-
trace4("install:ok", "
|
|
730
|
+
trace4("install:ok", "login-required");
|
|
371
731
|
console.log("\u2705 codex-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
372
732
|
console.log("\u26A0\uFE0F codex-cli \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
373
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.');
|
|
374
734
|
process.exit(1);
|
|
375
735
|
} catch (installError) {
|
|
376
|
-
trace4("install:failed");
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
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
|
+
});
|
|
380
741
|
}
|
|
381
742
|
}
|
|
382
743
|
trace4("checkCodexCliInstalled:end");
|
|
383
744
|
}
|
|
384
745
|
var args3 = process.argv.slice(2);
|
|
385
746
|
var trace5 = createTraceLogger("gemini-commander", args3);
|
|
386
|
-
var
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
747
|
+
var ALLOWED_REASONING_EFFORTS3 = ["minimal", "low", "medium", "high"];
|
|
748
|
+
function shellQuote3(value) {
|
|
749
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
750
|
+
}
|
|
751
|
+
function getArgValue3(flag) {
|
|
752
|
+
const index = args3.indexOf(flag);
|
|
753
|
+
if (index === -1 || !args3[index + 1]) {
|
|
754
|
+
return "";
|
|
755
|
+
}
|
|
756
|
+
return args3[index + 1];
|
|
757
|
+
}
|
|
758
|
+
function toUnique2(values) {
|
|
759
|
+
const seen = /* @__PURE__ */ new Set();
|
|
760
|
+
return values.filter((value) => {
|
|
761
|
+
if (!value || seen.has(value)) {
|
|
762
|
+
return false;
|
|
763
|
+
}
|
|
764
|
+
seen.add(value);
|
|
765
|
+
return true;
|
|
766
|
+
});
|
|
767
|
+
}
|
|
768
|
+
function resolveReasoningEffort3() {
|
|
769
|
+
const customReasoningEffort = getArgValue3("--reasoning-effort");
|
|
770
|
+
if (customReasoningEffort) {
|
|
771
|
+
if (ALLOWED_REASONING_EFFORTS3.includes(customReasoningEffort)) {
|
|
772
|
+
trace5("reasoning:custom", customReasoningEffort);
|
|
773
|
+
return customReasoningEffort;
|
|
405
774
|
}
|
|
775
|
+
console.warn(
|
|
776
|
+
`\u26A0\uFE0F \uC9C0\uC6D0\uB418\uC9C0 \uC54A\uB294 reasoning effort(${customReasoningEffort})\uC785\uB2C8\uB2E4. allowed: ${ALLOWED_REASONING_EFFORTS3.join(
|
|
777
|
+
", "
|
|
778
|
+
)}`
|
|
779
|
+
);
|
|
780
|
+
}
|
|
781
|
+
if (args3.includes("--flash")) {
|
|
782
|
+
trace5("reasoning:flash-default", "minimal");
|
|
783
|
+
return "minimal";
|
|
784
|
+
}
|
|
785
|
+
if (args3.includes("--review")) {
|
|
786
|
+
trace5("reasoning:review-default", "high");
|
|
787
|
+
return "high";
|
|
406
788
|
}
|
|
789
|
+
trace5("reasoning:default", "medium");
|
|
790
|
+
return "medium";
|
|
791
|
+
}
|
|
792
|
+
function resolvePrimaryAlias2(reasoningEffort) {
|
|
793
|
+
if (args3.includes("--review")) {
|
|
794
|
+
trace5("model:mode-alias", "pro");
|
|
795
|
+
return "pro";
|
|
796
|
+
}
|
|
797
|
+
if (args3.includes("--flash")) {
|
|
798
|
+
trace5("model:mode-alias", "flash");
|
|
799
|
+
return "flash";
|
|
800
|
+
}
|
|
801
|
+
if (reasoningEffort === "high") {
|
|
802
|
+
trace5("model:reasoning-alias", "pro");
|
|
803
|
+
return "pro";
|
|
804
|
+
}
|
|
805
|
+
if (reasoningEffort === "minimal" || reasoningEffort === "low") {
|
|
806
|
+
trace5("model:reasoning-alias", "flash");
|
|
807
|
+
return "flash";
|
|
808
|
+
}
|
|
809
|
+
trace5("model:default-alias", "auto");
|
|
810
|
+
return "auto";
|
|
811
|
+
}
|
|
812
|
+
function getAliasFallbacks2(primaryAlias) {
|
|
813
|
+
if (primaryAlias === "pro") {
|
|
814
|
+
return ["pro", "flash", "auto"];
|
|
815
|
+
}
|
|
816
|
+
if (primaryAlias === "flash") {
|
|
817
|
+
return ["flash", "auto", "pro"];
|
|
818
|
+
}
|
|
819
|
+
return [primaryAlias, "auto", "flash", "pro"];
|
|
820
|
+
}
|
|
821
|
+
function getReasoningInstruction(reasoningEffort) {
|
|
822
|
+
if (reasoningEffort === "high") {
|
|
823
|
+
return "high (\uAE4A\uC774 \uC788\uB294 \uBD84\uC11D, \uC7A0\uC7AC\uC801 \uB9AC\uC2A4\uD06C\uAE4C\uC9C0 \uC810\uAC80)";
|
|
824
|
+
}
|
|
825
|
+
if (reasoningEffort === "medium") {
|
|
826
|
+
return "medium (\uADE0\uD615 \uC7A1\uD78C \uBD84\uC11D\uACFC \uD575\uC2EC \uC774\uC288 \uC911\uC2EC)";
|
|
827
|
+
}
|
|
828
|
+
if (reasoningEffort === "low") {
|
|
829
|
+
return "low (\uD575\uC2EC \uACB0\uD568 \uC704\uC8FC\uB85C \uAC04\uACB0\uD558\uAC8C \uBD84\uC11D)";
|
|
830
|
+
}
|
|
831
|
+
return "minimal (\uCE58\uBA85\uB3C4 \uB192\uC740 \uC774\uC288\uB9CC \uB9E4\uC6B0 \uAC04\uACB0\uD558\uAC8C \uBD84\uC11D)";
|
|
832
|
+
}
|
|
833
|
+
function buildGeminiExecCommand(prompt, model) {
|
|
834
|
+
const modelOption = model ? `--model ${shellQuote3(model)}` : "";
|
|
835
|
+
return `gemini ${[modelOption, "-p", shellQuote3(prompt)].filter(Boolean).join(" ")}`;
|
|
836
|
+
}
|
|
837
|
+
var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
838
|
+
trace5("createGeminiCommand:start", `tempDiffPath=${tempDiffPath2}, reviewFormPath=${reviewFormPath2}`);
|
|
839
|
+
const customModel = getArgValue3("--model");
|
|
840
|
+
const reasoningEffort = resolveReasoningEffort3();
|
|
841
|
+
const primaryAlias = resolvePrimaryAlias2(reasoningEffort);
|
|
842
|
+
const aliasFallbacks = toUnique2(getAliasFallbacks2(primaryAlias));
|
|
407
843
|
const rules = [
|
|
408
844
|
{ path: rulesPath, display: "\uB8F0\uC14B" },
|
|
409
845
|
{ path: namingRulesPath, display: "\uB124\uC774\uBC0D \uADDC\uCE59" },
|
|
@@ -412,7 +848,29 @@ var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
|
412
848
|
const validRules = rules.filter((rule) => fs__default.default.existsSync(rule.path)).map((rule) => `@${rule.path}`).join(", ");
|
|
413
849
|
const rulesCount = validRules ? validRules.split(",").length : 0;
|
|
414
850
|
trace5("rules:loaded", `count=${rulesCount}`);
|
|
415
|
-
const
|
|
851
|
+
const reviewFormRef = fs__default.default.existsSync(reviewFormPath2) ? `@${reviewFormPath2}` : "(\uC5C6\uC74C)";
|
|
852
|
+
trace5("reviewForm:status", reviewFormRef === "(\uC5C6\uC74C)" ? "missing" : "exists");
|
|
853
|
+
const reasoningInstruction = getReasoningInstruction(reasoningEffort);
|
|
854
|
+
const prompt = `\uB2E4\uC74C \uADDC\uCE59\uB4E4\uC744 \uCC38\uACE0\uD574\uC11C(${validRules || "(\uC5C6\uC74C)"}) \uC774 diff(@${tempDiffPath2})\uB97C \uB9AC\uBDF0\uD574\uC918.
|
|
855
|
+
\uB9AC\uBDF0 \uC591\uC2DD\uC740 ${reviewFormRef} \uC5D0 \uB9DE\uCDB0\uC11C \uC791\uC131\uD574\uC918.
|
|
856
|
+
\uCD94\uB860 \uAC15\uB3C4 \uC9C0\uCE68: ${reasoningInstruction}`;
|
|
857
|
+
trace5("prompt:prepared", `length=${prompt.length}`);
|
|
858
|
+
const modelCandidates = toUnique2(customModel ? [customModel, ...aliasFallbacks] : aliasFallbacks);
|
|
859
|
+
trace5("model:candidates", modelCandidates.join(", "));
|
|
860
|
+
trace5("command:candidates:count", String(modelCandidates.length + 1));
|
|
861
|
+
if (customModel) {
|
|
862
|
+
console.warn(
|
|
863
|
+
`\u26A0\uFE0F \uCEE4\uC2A4\uD140 \uBAA8\uB378(${customModel})\uC744 \uC6B0\uC120 \uC2DC\uB3C4\uD558\uACE0 \uC2E4\uD328\uD558\uBA74 alias(${aliasFallbacks.join(
|
|
864
|
+
" -> "
|
|
865
|
+
)}) \uBC0F \uAE30\uBCF8 \uBAA8\uB378 \uC21C\uC73C\uB85C \uD3F4\uBC31\uD569\uB2C8\uB2E4.`
|
|
866
|
+
);
|
|
867
|
+
} else {
|
|
868
|
+
console.warn(
|
|
869
|
+
`\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.`
|
|
870
|
+
);
|
|
871
|
+
}
|
|
872
|
+
const commandCandidates = modelCandidates.map((model) => buildGeminiExecCommand(prompt, model));
|
|
873
|
+
const command = [...commandCandidates, buildGeminiExecCommand(prompt)].join(" || ");
|
|
416
874
|
trace5("command:created");
|
|
417
875
|
if (args3.includes("--test")) {
|
|
418
876
|
const safeCommand = command.replace(/"/g, '\\"');
|
|
@@ -422,6 +880,7 @@ var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
|
422
880
|
\uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
|
|
423
881
|
${safeCommand}"`;
|
|
424
882
|
}
|
|
883
|
+
trace5("command:mode", "execute");
|
|
425
884
|
trace5("createGeminiCommand:end");
|
|
426
885
|
return command;
|
|
427
886
|
};
|
|
@@ -432,21 +891,23 @@ function checkGeminiCliInstalled() {
|
|
|
432
891
|
trace6("version-check:run", "gemini --version");
|
|
433
892
|
child_process.execSync("gemini --version", { stdio: "ignore" });
|
|
434
893
|
trace6("version-check:ok");
|
|
435
|
-
} catch {
|
|
436
|
-
trace6("version-check:failed",
|
|
894
|
+
} catch (error) {
|
|
895
|
+
trace6("version-check:failed", getErrorSummary(error));
|
|
896
|
+
trace6("install:start", "@google/gemini-cli");
|
|
437
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");
|
|
438
898
|
try {
|
|
439
899
|
child_process.execSync("npm install -g @google/gemini-cli", { stdio: "inherit" });
|
|
440
|
-
trace6("install:ok", "
|
|
900
|
+
trace6("install:ok", "login-required");
|
|
441
901
|
console.log("\u2705 gemini-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
442
902
|
console.log("\u26A0\uFE0F Gemini API \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
443
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.');
|
|
444
904
|
process.exit(1);
|
|
445
905
|
} catch (installError) {
|
|
446
|
-
trace6("install:failed");
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
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
|
+
});
|
|
450
911
|
}
|
|
451
912
|
}
|
|
452
913
|
trace6("checkGeminiCliInstalled:end");
|
|
@@ -455,30 +916,35 @@ function checkGeminiCliInstalled() {
|
|
|
455
916
|
// src/pr-review/review.ts
|
|
456
917
|
async function main() {
|
|
457
918
|
const args4 = process.argv.slice(2);
|
|
919
|
+
clearTraceMessages();
|
|
458
920
|
const isTest = isTestMode(args4);
|
|
459
921
|
const trace7 = createTraceLogger("review", args4);
|
|
460
922
|
trace7("main:start", `args=${JSON.stringify(args4)}`);
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
case "gemini":
|
|
466
|
-
trace7("install-check:start", "service=gemini");
|
|
467
|
-
checkGeminiCliInstalled();
|
|
468
|
-
trace7("install-check:done", "service=gemini");
|
|
469
|
-
break;
|
|
470
|
-
case "claude":
|
|
471
|
-
trace7("install-check:start", "service=claude");
|
|
472
|
-
checkClaudeCliInstalled();
|
|
473
|
-
trace7("install-check:done", "service=claude");
|
|
474
|
-
break;
|
|
475
|
-
case "codex":
|
|
476
|
-
trace7("install-check:start", "service=codex");
|
|
477
|
-
checkCodexCliInstalled();
|
|
478
|
-
trace7("install-check:done", "service=codex");
|
|
479
|
-
break;
|
|
480
|
-
}
|
|
923
|
+
let command = "";
|
|
924
|
+
let savedDiffPath = "";
|
|
925
|
+
let savedReportPath = "";
|
|
926
|
+
let service = "";
|
|
481
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
|
+
}
|
|
482
948
|
trace7("review-flow:start");
|
|
483
949
|
console.log("\u{1F680} AI Code Review\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4...");
|
|
484
950
|
const nowStr = getNowString();
|
|
@@ -496,8 +962,8 @@ async function main() {
|
|
|
496
962
|
trace7("git-diff:run");
|
|
497
963
|
diff = child_process.execSync(`git diff ${diffArgs} -- ${includeParams} ${excludeParams}`).toString();
|
|
498
964
|
trace7("git-diff:done", `length=${diff.length}`);
|
|
499
|
-
} catch {
|
|
500
|
-
trace7("git-diff:error",
|
|
965
|
+
} catch (error) {
|
|
966
|
+
trace7("git-diff:error", getErrorSummary(error));
|
|
501
967
|
}
|
|
502
968
|
if (!diff.trim() && !isTest) {
|
|
503
969
|
trace7("empty-diff:exit");
|
|
@@ -509,10 +975,9 @@ async function main() {
|
|
|
509
975
|
fs__default.default.writeFileSync(tempDiffPath, diff);
|
|
510
976
|
trace7("temp-diff:write:done");
|
|
511
977
|
trace7("saved-diff:copy:start");
|
|
512
|
-
|
|
978
|
+
savedDiffPath = getNextFilePath(REPORT_DIR, `${nowStr}-diff`, ".txt");
|
|
513
979
|
fs__default.default.copyFileSync(tempDiffPath, savedDiffPath);
|
|
514
980
|
trace7("saved-diff:copy:done", savedDiffPath);
|
|
515
|
-
let command = "";
|
|
516
981
|
trace7("command:create:start", `service=${service}`);
|
|
517
982
|
switch (service) {
|
|
518
983
|
case "gemini":
|
|
@@ -531,7 +996,7 @@ async function main() {
|
|
|
531
996
|
trace7("command:exec:done", `resultLength=${result.length}`);
|
|
532
997
|
console.log(result);
|
|
533
998
|
trace7("report:write:start");
|
|
534
|
-
|
|
999
|
+
savedReportPath = getNextFilePath(REPORT_DIR, nowStr, ".md");
|
|
535
1000
|
fs__default.default.writeFileSync(savedReportPath, result);
|
|
536
1001
|
trace7("report:write:done", savedReportPath);
|
|
537
1002
|
if (isTest) {
|
|
@@ -555,12 +1020,45 @@ ${command}`);
|
|
|
555
1020
|
trace7("cleanup-temp-diff:done");
|
|
556
1021
|
trace7("review-flow:end");
|
|
557
1022
|
} catch (error) {
|
|
558
|
-
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
|
+
});
|
|
559
1057
|
console.error("\u274C \uB9AC\uBDF0 \uB3C4\uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
|
|
560
1058
|
console.error(error);
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
1059
|
+
if (errorReportPath) {
|
|
1060
|
+
console.error(`\u{1F4C4} \uC5D0\uB7EC \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${errorReportPath}`);
|
|
1061
|
+
}
|
|
564
1062
|
process.exit(1);
|
|
565
1063
|
}
|
|
566
1064
|
}
|