sales-frontend-gemini-cli 0.4.1 → 0.4.3
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 +674 -68
- package/dist/common/helper.cjs.map +1 -1
- package/dist/common/helper.d.cts +106 -4
- package/dist/common/helper.d.ts +106 -4
- package/dist/common/helper.js +659 -70
- package/dist/common/helper.js.map +1 -1
- package/dist/common/types.d.cts +24 -1
- package/dist/common/types.d.ts +24 -1
- package/dist/pr-review/claude/claude-commander.cjs +58 -10
- package/dist/pr-review/claude/claude-commander.cjs.map +1 -1
- package/dist/pr-review/claude/claude-commander.js +58 -10
- package/dist/pr-review/claude/claude-commander.js.map +1 -1
- package/dist/pr-review/claude/installation-claude.cjs +219 -13
- package/dist/pr-review/claude/installation-claude.cjs.map +1 -1
- package/dist/pr-review/claude/installation-claude.js +218 -13
- package/dist/pr-review/claude/installation-claude.js.map +1 -1
- package/dist/pr-review/codex/codex-commander.cjs +55 -9
- package/dist/pr-review/codex/codex-commander.cjs.map +1 -1
- package/dist/pr-review/codex/codex-commander.js +55 -9
- package/dist/pr-review/codex/codex-commander.js.map +1 -1
- package/dist/pr-review/codex/installation-codex.cjs +219 -13
- package/dist/pr-review/codex/installation-codex.cjs.map +1 -1
- package/dist/pr-review/codex/installation-codex.js +218 -13
- package/dist/pr-review/codex/installation-codex.js.map +1 -1
- package/dist/pr-review/gemini/gemini-commander.cjs +82 -16
- package/dist/pr-review/gemini/gemini-commander.cjs.map +1 -1
- package/dist/pr-review/gemini/gemini-commander.js +82 -16
- package/dist/pr-review/gemini/gemini-commander.js.map +1 -1
- package/dist/pr-review/gemini/installation-gemini.cjs +219 -13
- package/dist/pr-review/gemini/installation-gemini.cjs.map +1 -1
- package/dist/pr-review/gemini/installation-gemini.js +218 -13
- package/dist/pr-review/gemini/installation-gemini.js.map +1 -1
- package/dist/pr-review/review-one-by-one.cjs +838 -184
- package/dist/pr-review/review-one-by-one.cjs.map +1 -1
- package/dist/pr-review/review-one-by-one.js +839 -185
- package/dist/pr-review/review-one-by-one.js.map +1 -1
- package/dist/pr-review/review.cjs +815 -156
- package/dist/pr-review/review.cjs.map +1 -1
- package/dist/pr-review/review.js +815 -156
- package/dist/pr-review/review.js.map +1 -1
- package/package.json +4 -7
- package/src/common/rules/coding-convention.md +393 -0
- package/src/common/rules/coding-convention.pdf +0 -0
- package/src/common/rules/naming-rule.md +347 -0
- package/src/common/rules/naming-rule.pdf +0 -0
package/dist/common/helper.cjs
CHANGED
|
@@ -5,6 +5,7 @@ var fs = require('fs');
|
|
|
5
5
|
var path = require('path');
|
|
6
6
|
var readline = require('readline');
|
|
7
7
|
var url = require('url');
|
|
8
|
+
var util = require('util');
|
|
8
9
|
|
|
9
10
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
10
11
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -15,14 +16,53 @@ var readline__default = /*#__PURE__*/_interopDefault(readline);
|
|
|
15
16
|
|
|
16
17
|
// src/common/helper.ts
|
|
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('helper.cjs', document.baseURI).href))));
|
|
18
|
-
var
|
|
19
|
-
var
|
|
20
|
-
var
|
|
21
|
-
|
|
22
|
-
|
|
19
|
+
var traceMessages = [];
|
|
20
|
+
var GEMINI_CLI_PACKAGE_NAME = "sales-frontend-gemini-cli";
|
|
21
|
+
var cachedPackageRootPath = "";
|
|
22
|
+
function isGeminiCliPackageRoot(directory) {
|
|
23
|
+
const packageJsonPath = path__default.default.join(directory, "package.json");
|
|
24
|
+
if (!fs__default.default.existsSync(packageJsonPath)) {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const packageJson = JSON.parse(fs__default.default.readFileSync(packageJsonPath, "utf8"));
|
|
29
|
+
return packageJson.name === GEMINI_CLI_PACKAGE_NAME;
|
|
30
|
+
} catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function resolveGeminiCliPackageRoot(startDirectory = __dirname$1) {
|
|
35
|
+
if (cachedPackageRootPath) {
|
|
36
|
+
return cachedPackageRootPath;
|
|
37
|
+
}
|
|
38
|
+
let currentDirectory = startDirectory;
|
|
39
|
+
while (true) {
|
|
40
|
+
if (isGeminiCliPackageRoot(currentDirectory)) {
|
|
41
|
+
cachedPackageRootPath = currentDirectory;
|
|
42
|
+
return cachedPackageRootPath;
|
|
43
|
+
}
|
|
44
|
+
const parentDirectory = path__default.default.dirname(currentDirectory);
|
|
45
|
+
if (parentDirectory === currentDirectory) {
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
currentDirectory = parentDirectory;
|
|
49
|
+
}
|
|
50
|
+
cachedPackageRootPath = path__default.default.resolve(startDirectory, "../..");
|
|
51
|
+
return cachedPackageRootPath;
|
|
52
|
+
}
|
|
53
|
+
function resolvePackageAssetPath(relativeFilePath) {
|
|
54
|
+
return path__default.default.resolve(resolveGeminiCliPackageRoot(), relativeFilePath);
|
|
55
|
+
}
|
|
56
|
+
var rulesPath = resolvePackageAssetPath("src/common/rules/review-rules.md");
|
|
57
|
+
var namingRulesPath = resolvePackageAssetPath("src/common/rules/naming-rule.md");
|
|
58
|
+
var codingConventionRulesPath = resolvePackageAssetPath("src/common/rules/coding-convention.md");
|
|
59
|
+
var reviewFormPath = resolvePackageAssetPath("src/common/form/review-form.md");
|
|
60
|
+
var reviewFormOneByOnePath = resolvePackageAssetPath("src/common/form/review-form-one-by-one.md");
|
|
23
61
|
var REPORT_DIR = ".review-report";
|
|
24
62
|
var tempDiffPath = "temp_diff.txt";
|
|
25
63
|
var AIServices = ["gemini", "claude", "codex"];
|
|
64
|
+
var COMMIT_FETCH_LIMIT = 20;
|
|
65
|
+
var COMMIT_SELECTION_WINDOW = 8;
|
|
26
66
|
var ignoreList = [
|
|
27
67
|
"package.json",
|
|
28
68
|
"*.yml",
|
|
@@ -37,33 +77,276 @@ var ignoreList = [
|
|
|
37
77
|
".review-report/"
|
|
38
78
|
// 생성되는 리포트 폴더도 제외
|
|
39
79
|
];
|
|
40
|
-
function
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
80
|
+
function isTestMode(args = process.argv.slice(2)) {
|
|
81
|
+
return args.includes("--test");
|
|
82
|
+
}
|
|
83
|
+
function clearTraceMessages() {
|
|
84
|
+
traceMessages.length = 0;
|
|
85
|
+
}
|
|
86
|
+
function getTraceMessages() {
|
|
87
|
+
return [...traceMessages];
|
|
88
|
+
}
|
|
89
|
+
var ANSI = {
|
|
90
|
+
bold: "\x1B[1m",
|
|
91
|
+
cyan: "\x1B[36m",
|
|
92
|
+
dim: "\x1B[2m",
|
|
93
|
+
green: "\x1B[32m",
|
|
94
|
+
reset: "\x1B[0m",
|
|
95
|
+
yellow: "\x1B[33m"
|
|
96
|
+
};
|
|
97
|
+
var ANSI_PATTERN = new RegExp(`${String.fromCharCode(27)}\\[[0-9;]*m`, "g");
|
|
98
|
+
var COMBINING_MARK_PATTERN = /\p{Mark}/u;
|
|
99
|
+
var GRAPHEME_SEGMENTER = typeof Intl !== "undefined" && "Segmenter" in Intl ? new Intl.Segmenter("ko", { granularity: "grapheme" }) : null;
|
|
100
|
+
function getGitDiffPathspecs() {
|
|
101
|
+
return {
|
|
102
|
+
excludePatterns: ignoreList.map((item) => `:(exclude)${item}`),
|
|
103
|
+
includePatterns: ["*.ts", "*.tsx", "*.js", "*.jsx"]
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function segmentGraphemes(value) {
|
|
107
|
+
if (!GRAPHEME_SEGMENTER) {
|
|
108
|
+
return [...value];
|
|
109
|
+
}
|
|
110
|
+
return [...GRAPHEME_SEGMENTER.segment(value)].map(({ segment }) => segment);
|
|
111
|
+
}
|
|
112
|
+
function isWideCodePoint(codePoint) {
|
|
113
|
+
return codePoint >= 4352 && (codePoint <= 4447 || codePoint === 9001 || codePoint === 9002 || codePoint >= 11904 && codePoint <= 12871 && codePoint !== 12351 || codePoint >= 12880 && codePoint <= 19903 || codePoint >= 19968 && codePoint <= 42182 || codePoint >= 43360 && codePoint <= 43388 || codePoint >= 44032 && codePoint <= 55203 || codePoint >= 63744 && codePoint <= 64255 || codePoint >= 65040 && codePoint <= 65049 || codePoint >= 65072 && codePoint <= 65131 || codePoint >= 65281 && codePoint <= 65376 || codePoint >= 65504 && codePoint <= 65510 || codePoint >= 127488 && codePoint <= 127569 || codePoint >= 131072 && codePoint <= 262141);
|
|
114
|
+
}
|
|
115
|
+
function isEmojiCodePoint(codePoint) {
|
|
116
|
+
return codePoint >= 127462 && codePoint <= 127487 || codePoint >= 127744 && codePoint <= 129791 || codePoint >= 9728 && codePoint <= 10175;
|
|
117
|
+
}
|
|
118
|
+
function getGraphemeWidth(grapheme) {
|
|
119
|
+
let width = 0;
|
|
120
|
+
for (const character of grapheme) {
|
|
121
|
+
const codePoint = character.codePointAt(0);
|
|
122
|
+
if (!codePoint || COMBINING_MARK_PATTERN.test(character) || codePoint === 8205) {
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (codePoint >= 65024 && codePoint <= 65039 || codePoint >= 917760 && codePoint <= 917999) {
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (isWideCodePoint(codePoint) || isEmojiCodePoint(codePoint)) {
|
|
129
|
+
width = Math.max(width, 2);
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
width = Math.max(width, 1);
|
|
133
|
+
}
|
|
134
|
+
return width;
|
|
135
|
+
}
|
|
136
|
+
function tokenizePlainText(value) {
|
|
137
|
+
return segmentGraphemes(value).map((segment) => ({
|
|
138
|
+
value: segment,
|
|
139
|
+
visibleWidth: getGraphemeWidth(segment)
|
|
140
|
+
}));
|
|
141
|
+
}
|
|
142
|
+
function tokenizeVisibleText(value) {
|
|
143
|
+
const tokens = [];
|
|
144
|
+
let lastIndex = 0;
|
|
145
|
+
for (const match of value.matchAll(ANSI_PATTERN)) {
|
|
146
|
+
const index = match.index ?? 0;
|
|
147
|
+
if (index > lastIndex) {
|
|
148
|
+
tokens.push(...tokenizePlainText(value.slice(lastIndex, index)));
|
|
149
|
+
}
|
|
150
|
+
tokens.push({
|
|
151
|
+
value: match[0],
|
|
152
|
+
visibleWidth: 0
|
|
153
|
+
});
|
|
154
|
+
lastIndex = index + match[0].length;
|
|
155
|
+
}
|
|
156
|
+
if (lastIndex < value.length) {
|
|
157
|
+
tokens.push(...tokenizePlainText(value.slice(lastIndex)));
|
|
158
|
+
}
|
|
159
|
+
return tokens;
|
|
160
|
+
}
|
|
161
|
+
function truncateLineForTerminal(value, maxWidth) {
|
|
162
|
+
if (maxWidth <= 0) {
|
|
44
163
|
return "";
|
|
45
164
|
}
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
165
|
+
const tokens = tokenizeVisibleText(value);
|
|
166
|
+
const totalWidth = tokens.reduce((sum, token) => sum + token.visibleWidth, 0);
|
|
167
|
+
if (totalWidth <= maxWidth) {
|
|
168
|
+
return value;
|
|
49
169
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
);
|
|
53
|
-
|
|
170
|
+
const ellipsis = "...";
|
|
171
|
+
const ellipsisWidth = 3;
|
|
172
|
+
const targetWidth = Math.max(0, maxWidth - ellipsisWidth);
|
|
173
|
+
let usedWidth = 0;
|
|
174
|
+
let result = "";
|
|
175
|
+
for (const token of tokens) {
|
|
176
|
+
if (token.visibleWidth === 0) {
|
|
177
|
+
result += token.value;
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
if (usedWidth + token.visibleWidth > targetWidth) {
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
result += token.value;
|
|
184
|
+
usedWidth += token.visibleWidth;
|
|
185
|
+
}
|
|
186
|
+
return `${result}${ellipsis}${ANSI.reset}`;
|
|
54
187
|
}
|
|
55
|
-
function
|
|
56
|
-
|
|
188
|
+
function fitLinesToTerminal(lines) {
|
|
189
|
+
const maxWidth = Math.max(20, (process.stdout.columns || 120) - 1);
|
|
190
|
+
return lines.map((line) => truncateLineForTerminal(line, maxWidth));
|
|
191
|
+
}
|
|
192
|
+
function runGitCommand(args, options = {}) {
|
|
193
|
+
const { allowFailure = false, trimOutput = true } = options;
|
|
194
|
+
try {
|
|
195
|
+
const output = child_process.execFileSync("git", args, {
|
|
196
|
+
encoding: "utf8",
|
|
197
|
+
maxBuffer: 1024 * 1024 * 20,
|
|
198
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
199
|
+
});
|
|
200
|
+
return trimOutput ? output.trim() : output;
|
|
201
|
+
} catch (error) {
|
|
202
|
+
helperTrace("git-command:failed", `${args.join(" ")} | ${getErrorSummary(error)}`);
|
|
203
|
+
if (allowFailure) {
|
|
204
|
+
return "";
|
|
205
|
+
}
|
|
206
|
+
throw error;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
async function executeShellCommandWithProgress(command, options = {}) {
|
|
210
|
+
const { progressIntervalMs = 1e4, progressMessage = "\u23F3 \uBA85\uB839\uC744 \uC2E4\uD589\uD558\uB294 \uC911\uC785\uB2C8\uB2E4...", streamOutput = false } = options;
|
|
211
|
+
const { spawn } = await import('child_process');
|
|
212
|
+
return new Promise((resolve, reject) => {
|
|
213
|
+
let stdout = "";
|
|
214
|
+
let stderr = "";
|
|
215
|
+
const startedAt = Date.now();
|
|
216
|
+
console.log(progressMessage);
|
|
217
|
+
const child = spawn("/bin/zsh", ["-lc", command], {
|
|
218
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
219
|
+
});
|
|
220
|
+
const progressTimer = setInterval(() => {
|
|
221
|
+
const elapsedSeconds = Math.max(1, Math.floor((Date.now() - startedAt) / 1e3));
|
|
222
|
+
console.log(`${progressMessage} (${elapsedSeconds}s \uACBD\uACFC)`);
|
|
223
|
+
}, progressIntervalMs);
|
|
224
|
+
child.stdout.on("data", (chunk) => {
|
|
225
|
+
const text = chunk.toString();
|
|
226
|
+
stdout += text;
|
|
227
|
+
if (streamOutput) {
|
|
228
|
+
process.stdout.write(text);
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
child.stderr.on("data", (chunk) => {
|
|
232
|
+
const text = chunk.toString();
|
|
233
|
+
stderr += text;
|
|
234
|
+
if (streamOutput) {
|
|
235
|
+
process.stderr.write(text);
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
child.on("error", (error) => {
|
|
239
|
+
clearInterval(progressTimer);
|
|
240
|
+
reject(error);
|
|
241
|
+
});
|
|
242
|
+
child.on("close", (code, signal) => {
|
|
243
|
+
clearInterval(progressTimer);
|
|
244
|
+
if (code === 0) {
|
|
245
|
+
resolve({
|
|
246
|
+
stderr,
|
|
247
|
+
stdout
|
|
248
|
+
});
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
const exitSummary = signal ? `signal=${signal}` : `code=${String(code ?? "unknown")}`;
|
|
252
|
+
reject(new Error(`\uC258 \uBA85\uB839 \uC2E4\uD589 \uC2E4\uD328 (${exitSummary})${stderr.trim() ? `
|
|
253
|
+
${stderr.trim()}` : ""}`));
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
}
|
|
257
|
+
function formatReviewTargetFiles(files, visibleCount = 5) {
|
|
258
|
+
if (files.length === 0) {
|
|
259
|
+
return "(\uC5C6\uC74C)";
|
|
260
|
+
}
|
|
261
|
+
const visibleFiles = files.slice(0, visibleCount);
|
|
262
|
+
const hiddenCount = Math.max(0, files.length - visibleFiles.length);
|
|
263
|
+
if (hiddenCount === 0) {
|
|
264
|
+
return visibleFiles.join(", ");
|
|
265
|
+
}
|
|
266
|
+
return `${visibleFiles.join(", ")} \uC678 ${hiddenCount}\uAC1C`;
|
|
57
267
|
}
|
|
58
268
|
function createTraceLogger(scope, args = process.argv.slice(2)) {
|
|
59
269
|
const enabled = isTestMode(args);
|
|
60
270
|
return (step, detail) => {
|
|
271
|
+
const timestamp = (/* @__PURE__ */ new Date()).toISOString();
|
|
272
|
+
const message = `[${timestamp}][TRACE][${scope}] ${step}${detail ? ` | ${detail}` : ""}`;
|
|
273
|
+
traceMessages.push(message);
|
|
61
274
|
if (!enabled) {
|
|
62
275
|
return;
|
|
63
276
|
}
|
|
64
|
-
console.log(
|
|
277
|
+
console.log(message);
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
var helperTrace = createTraceLogger("helper");
|
|
281
|
+
function getTimestampParts(now = /* @__PURE__ */ new Date()) {
|
|
282
|
+
return {
|
|
283
|
+
YYYY: now.getFullYear(),
|
|
284
|
+
MM: String(now.getMonth() + 1).padStart(2, "0"),
|
|
285
|
+
DD: String(now.getDate()).padStart(2, "0"),
|
|
286
|
+
HH: String(now.getHours()).padStart(2, "0"),
|
|
287
|
+
mm: String(now.getMinutes()).padStart(2, "0"),
|
|
288
|
+
ss: String(now.getSeconds()).padStart(2, "0")
|
|
65
289
|
};
|
|
66
290
|
}
|
|
291
|
+
function getHumanReadableNowString(now = /* @__PURE__ */ new Date()) {
|
|
292
|
+
const { YYYY, MM, DD, HH, mm, ss } = getTimestampParts(now);
|
|
293
|
+
return `${YYYY}-${MM}-${DD} ${HH}:${mm}:${ss}`;
|
|
294
|
+
}
|
|
295
|
+
function stringifyUnknown(value) {
|
|
296
|
+
if (value === void 0 || value === null) {
|
|
297
|
+
return "";
|
|
298
|
+
}
|
|
299
|
+
if (typeof value === "string") {
|
|
300
|
+
return value;
|
|
301
|
+
}
|
|
302
|
+
if (Buffer.isBuffer(value)) {
|
|
303
|
+
return value.toString();
|
|
304
|
+
}
|
|
305
|
+
if (value instanceof Error) {
|
|
306
|
+
return value.stack || value.message;
|
|
307
|
+
}
|
|
308
|
+
return util.inspect(value, { depth: 5, breakLength: 120 });
|
|
309
|
+
}
|
|
310
|
+
function getErrorSummary(error) {
|
|
311
|
+
if (error instanceof Error) {
|
|
312
|
+
return `${error.name}: ${error.message}`;
|
|
313
|
+
}
|
|
314
|
+
return stringifyUnknown(error) || "Unknown error";
|
|
315
|
+
}
|
|
316
|
+
function serializeError(error) {
|
|
317
|
+
const serialized = {
|
|
318
|
+
summary: getErrorSummary(error)
|
|
319
|
+
};
|
|
320
|
+
if (error instanceof Error) {
|
|
321
|
+
serialized.name = error.name;
|
|
322
|
+
serialized.message = error.message;
|
|
323
|
+
serialized.stack = error.stack;
|
|
324
|
+
} else {
|
|
325
|
+
serialized.value = stringifyUnknown(error);
|
|
326
|
+
}
|
|
327
|
+
if (error && typeof error === "object") {
|
|
328
|
+
const errorLike = error;
|
|
329
|
+
const extraKeys = ["code", "errno", "syscall", "path", "cmd", "status", "signal", "spawnargs"];
|
|
330
|
+
extraKeys.forEach((key) => {
|
|
331
|
+
if (errorLike[key] !== void 0) {
|
|
332
|
+
serialized[key] = errorLike[key];
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
const stdout = stringifyUnknown(errorLike.stdout);
|
|
336
|
+
if (stdout) {
|
|
337
|
+
serialized.stdout = stdout;
|
|
338
|
+
}
|
|
339
|
+
const stderr = stringifyUnknown(errorLike.stderr);
|
|
340
|
+
if (stderr) {
|
|
341
|
+
serialized.stderr = stderr;
|
|
342
|
+
}
|
|
343
|
+
const cause = stringifyUnknown(errorLike.cause);
|
|
344
|
+
if (cause) {
|
|
345
|
+
serialized.cause = cause;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return serialized;
|
|
349
|
+
}
|
|
67
350
|
function getNextFilePath(dir, baseName, extension) {
|
|
68
351
|
let counter = 1;
|
|
69
352
|
while (true) {
|
|
@@ -74,6 +357,13 @@ function getNextFilePath(dir, baseName, extension) {
|
|
|
74
357
|
counter++;
|
|
75
358
|
}
|
|
76
359
|
}
|
|
360
|
+
function getAvailableFilePath(dir, baseName, extension) {
|
|
361
|
+
const firstFilePath = path__default.default.join(dir, `${baseName}${extension}`);
|
|
362
|
+
if (!fs__default.default.existsSync(firstFilePath)) {
|
|
363
|
+
return firstFilePath;
|
|
364
|
+
}
|
|
365
|
+
return getNextFilePath(dir, baseName, extension);
|
|
366
|
+
}
|
|
77
367
|
function deleteFile(filePath) {
|
|
78
368
|
if (fs__default.default.existsSync(filePath)) {
|
|
79
369
|
fs__default.default.unlinkSync(filePath);
|
|
@@ -87,27 +377,194 @@ function createReportDirectory() {
|
|
|
87
377
|
fs__default.default.mkdirSync(REPORT_DIR, { recursive: true });
|
|
88
378
|
}
|
|
89
379
|
}
|
|
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");
|
|
380
|
+
function getNowString(now = /* @__PURE__ */ new Date()) {
|
|
381
|
+
const { YYYY, MM, DD, HH, mm, ss } = getTimestampParts(now);
|
|
98
382
|
return `${YYYY}-${MM}-${DD}_${HH}-${mm}-${ss}`;
|
|
99
383
|
}
|
|
384
|
+
function getErrorLogTimestamp(now = /* @__PURE__ */ new Date()) {
|
|
385
|
+
const { YYYY, MM, DD, HH, mm, ss } = getTimestampParts(now);
|
|
386
|
+
return `${YYYY}-${MM}-${DD}-${HH}\uC2DC-${mm}\uBD84-${ss}\uCD08`;
|
|
387
|
+
}
|
|
388
|
+
function writeErrorReport(error, options = {}) {
|
|
389
|
+
try {
|
|
390
|
+
const now = /* @__PURE__ */ new Date();
|
|
391
|
+
helperTrace("error-report:write:start", options.scope || "unknown");
|
|
392
|
+
createReportDirectory();
|
|
393
|
+
const reportPath = getAvailableFilePath(REPORT_DIR, `error-log-${getErrorLogTimestamp(now)}`, ".md");
|
|
394
|
+
const serializedError = serializeError(error);
|
|
395
|
+
const traceSnapshot = options.traceMessages ?? getTraceMessages();
|
|
396
|
+
const extraSections = options.extraSections || [];
|
|
397
|
+
const report = `# Error Log
|
|
398
|
+
|
|
399
|
+
- \uBC1C\uC0DD \uC2DC\uAC01: ${getHumanReadableNowString(now)}
|
|
400
|
+
- Scope: \`${options.scope || "unknown"}\`
|
|
401
|
+
- \uC791\uC5C5 \uACBD\uB85C: \`${process.cwd()}\`
|
|
402
|
+
- \uC2E4\uD589 \uC778\uC790: \`${JSON.stringify(options.args ?? process.argv.slice(2))}\`
|
|
403
|
+
- \uC2E4\uD589 \uD658\uACBD: \`${process.platform} ${process.arch} / Node ${process.version}\`
|
|
404
|
+
|
|
405
|
+
## Summary
|
|
406
|
+
|
|
407
|
+
${options.title || serializedError.summary || "Unknown error"}
|
|
408
|
+
|
|
409
|
+
## Error
|
|
410
|
+
|
|
411
|
+
\`\`\`json
|
|
412
|
+
${JSON.stringify(serializedError, null, 2)}
|
|
413
|
+
\`\`\`
|
|
414
|
+
|
|
415
|
+
## Trace
|
|
416
|
+
|
|
417
|
+
\`\`\`json
|
|
418
|
+
${JSON.stringify(traceSnapshot, null, 2)}
|
|
419
|
+
\`\`\`${extraSections.length ? `
|
|
420
|
+
${extraSections.map((section) => `
|
|
421
|
+
## ${section.heading}
|
|
422
|
+
|
|
423
|
+
${section.markdown}`).join("\n")}
|
|
424
|
+
` : "\n"}
|
|
425
|
+
`;
|
|
426
|
+
fs__default.default.writeFileSync(reportPath, report);
|
|
427
|
+
helperTrace("error-report:write:done", reportPath);
|
|
428
|
+
return reportPath;
|
|
429
|
+
} catch (writeError) {
|
|
430
|
+
console.error("\u26A0\uFE0F \uC5D0\uB7EC \uB85C\uADF8 \uD30C\uC77C \uC0DD\uC131\uC5D0 \uC2E4\uD328\uD588\uC2B5\uB2C8\uB2E4.");
|
|
431
|
+
console.error(writeError);
|
|
432
|
+
return "";
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
function exitWithError(message, options = {}) {
|
|
436
|
+
const reportPath = writeErrorReport(options.error || new Error(message), {
|
|
437
|
+
...options,
|
|
438
|
+
title: message
|
|
439
|
+
});
|
|
440
|
+
console.error(message);
|
|
441
|
+
if (options.error) {
|
|
442
|
+
console.error(options.error);
|
|
443
|
+
}
|
|
444
|
+
if (reportPath) {
|
|
445
|
+
console.error(`\u{1F4C4} \uC5D0\uB7EC \uB85C\uADF8 \uC800\uC7A5 \uC704\uCE58: ${reportPath}`);
|
|
446
|
+
}
|
|
447
|
+
process.exit(1);
|
|
448
|
+
}
|
|
449
|
+
function parseServiceFromArgs(args = process.argv.slice(2)) {
|
|
450
|
+
helperTrace("parse-service:start", `args=${JSON.stringify(args)}`);
|
|
451
|
+
const serviceIndex = args.indexOf("--service");
|
|
452
|
+
const rawService = serviceIndex !== -1 ? args[serviceIndex + 1] : "";
|
|
453
|
+
if (!rawService) {
|
|
454
|
+
helperTrace("parse-service:empty");
|
|
455
|
+
return "";
|
|
456
|
+
}
|
|
457
|
+
const normalizedService = rawService.toLowerCase();
|
|
458
|
+
if (AIServices.includes(normalizedService)) {
|
|
459
|
+
helperTrace("parse-service:resolved", normalizedService);
|
|
460
|
+
return normalizedService;
|
|
461
|
+
}
|
|
462
|
+
helperTrace("parse-service:invalid", rawService);
|
|
463
|
+
exitWithError(
|
|
464
|
+
`\u274C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uC11C\uBE44\uC2A4\uC785\uB2C8\uB2E4: ${rawService}. \uC0AC\uC6A9 \uAC00\uB2A5 \uAC12: ${AIServices.join(", ")} (\uC608: --service codex)`,
|
|
465
|
+
{
|
|
466
|
+
scope: "helper:parseServiceFromArgs",
|
|
467
|
+
args,
|
|
468
|
+
extraSections: [
|
|
469
|
+
{
|
|
470
|
+
heading: "Allowed Services",
|
|
471
|
+
markdown: `\`\`\`json
|
|
472
|
+
${JSON.stringify(AIServices, null, 2)}
|
|
473
|
+
\`\`\``
|
|
474
|
+
}
|
|
475
|
+
]
|
|
476
|
+
}
|
|
477
|
+
);
|
|
478
|
+
}
|
|
100
479
|
function getGitDiffFilter() {
|
|
101
|
-
const
|
|
102
|
-
const excludePatterns = ignoreList.map((item) => `:(exclude)${item}`);
|
|
480
|
+
const { includePatterns, excludePatterns } = getGitDiffPathspecs();
|
|
103
481
|
const quote = (pattern) => `"${pattern}"`;
|
|
104
|
-
const includeParams =
|
|
482
|
+
const includeParams = includePatterns.map(quote).join(" ");
|
|
105
483
|
const excludeParams = excludePatterns.map(quote).join(" ");
|
|
106
484
|
return { includeParams, excludeParams };
|
|
107
485
|
}
|
|
486
|
+
function truncateCommitSubject(subject) {
|
|
487
|
+
if (subject.length <= 72) {
|
|
488
|
+
return subject;
|
|
489
|
+
}
|
|
490
|
+
return `${subject.slice(0, 69)}...`;
|
|
491
|
+
}
|
|
492
|
+
function getRecentCommitOptions() {
|
|
493
|
+
const output = runGitCommand(
|
|
494
|
+
["log", `-${COMMIT_FETCH_LIMIT}`, "--date=relative", "--pretty=format:%h%x09%an%x09%ar%x09%s"],
|
|
495
|
+
{ allowFailure: true }
|
|
496
|
+
);
|
|
497
|
+
if (!output) {
|
|
498
|
+
return [];
|
|
499
|
+
}
|
|
500
|
+
return output.split("\n").map((line) => {
|
|
501
|
+
const [hash = "", author = "", relativeDate = "", ...subjectParts] = line.split(" ");
|
|
502
|
+
const subject = subjectParts.join(" ").trim();
|
|
503
|
+
return {
|
|
504
|
+
author,
|
|
505
|
+
description: `${author} | ${relativeDate}`,
|
|
506
|
+
hash,
|
|
507
|
+
label: `${hash} | ${truncateCommitSubject(subject)}`,
|
|
508
|
+
relativeDate,
|
|
509
|
+
subject
|
|
510
|
+
};
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
function buildSelectedCommitSummary(commits) {
|
|
514
|
+
return commits.map((commit) => `- ${commit.hash} | ${commit.subject} | ${commit.author} | ${commit.relativeDate}`).join("\n");
|
|
515
|
+
}
|
|
516
|
+
function getReviewPathspecArgs() {
|
|
517
|
+
const { includePatterns, excludePatterns } = getGitDiffPathspecs();
|
|
518
|
+
return [...includePatterns, ...excludePatterns];
|
|
519
|
+
}
|
|
520
|
+
function buildSelectedCommitDiff(commits) {
|
|
521
|
+
const reviewPathspecArgs = getReviewPathspecArgs();
|
|
522
|
+
const sections = commits.map((commit) => {
|
|
523
|
+
const diff = runGitCommand(["show", "--stat", "--patch", "--format=", commit.hash, "--", ...reviewPathspecArgs], {
|
|
524
|
+
allowFailure: true,
|
|
525
|
+
trimOutput: false
|
|
526
|
+
}).trim();
|
|
527
|
+
if (!diff) {
|
|
528
|
+
return "";
|
|
529
|
+
}
|
|
530
|
+
return [`## ${commit.hash} ${commit.subject}`, diff].join("\n\n");
|
|
531
|
+
}).filter(Boolean).join("\n\n");
|
|
532
|
+
if (!sections) {
|
|
533
|
+
return "";
|
|
534
|
+
}
|
|
535
|
+
return ["# \uC120\uD0DD\uD55C \uCEE4\uBC0B", buildSelectedCommitSummary(commits), "", "# \uB9AC\uBDF0 \uB300\uC0C1 diff", sections].join("\n");
|
|
536
|
+
}
|
|
537
|
+
function getSelectedCommitFiles(commits) {
|
|
538
|
+
const reviewPathspecArgs = getReviewPathspecArgs();
|
|
539
|
+
const files = /* @__PURE__ */ new Set();
|
|
540
|
+
commits.forEach((commit) => {
|
|
541
|
+
const output = runGitCommand(["show", "--pretty=format:", "--name-only", commit.hash, "--", ...reviewPathspecArgs], {
|
|
542
|
+
allowFailure: true
|
|
543
|
+
});
|
|
544
|
+
output.split("\n").map((line) => line.trim()).filter(Boolean).forEach((filePath) => files.add(filePath));
|
|
545
|
+
});
|
|
546
|
+
return [...files];
|
|
547
|
+
}
|
|
548
|
+
function buildSelectedFileDiff(commits, filePath) {
|
|
549
|
+
const sections = commits.map((commit) => {
|
|
550
|
+
const diff = runGitCommand(["show", "--stat", "--patch", "--format=", commit.hash, "--", filePath], {
|
|
551
|
+
allowFailure: true,
|
|
552
|
+
trimOutput: false
|
|
553
|
+
}).trim();
|
|
554
|
+
if (!diff) {
|
|
555
|
+
return "";
|
|
556
|
+
}
|
|
557
|
+
return [`## ${commit.hash} ${commit.subject}`, diff].join("\n\n");
|
|
558
|
+
}).filter(Boolean).join("\n\n");
|
|
559
|
+
if (!sections) {
|
|
560
|
+
return "";
|
|
561
|
+
}
|
|
562
|
+
return ["# \uC120\uD0DD\uD55C \uCEE4\uBC0B", buildSelectedCommitSummary(commits), "", `# \uD30C\uC77C: ${filePath}`, sections].join("\n\n");
|
|
563
|
+
}
|
|
108
564
|
function openReport(reportPath) {
|
|
109
565
|
const resolvedPath = path__default.default.resolve(reportPath);
|
|
110
566
|
const { platform } = process;
|
|
567
|
+
helperTrace("open-report:start", resolvedPath);
|
|
111
568
|
const openWithChrome = () => {
|
|
112
569
|
if (platform === "darwin") {
|
|
113
570
|
child_process.execSync(`open -a "Google Chrome" "${resolvedPath}"`, { stdio: "ignore" });
|
|
@@ -132,71 +589,199 @@ function openReport(reportPath) {
|
|
|
132
589
|
};
|
|
133
590
|
try {
|
|
134
591
|
if (openWithChrome()) {
|
|
592
|
+
helperTrace("open-report:chrome:success", platform);
|
|
135
593
|
console.log("\u{1F680} Google Chrome\uC5D0\uC11C \uB9AC\uD3EC\uD2B8\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
136
594
|
return;
|
|
137
595
|
}
|
|
138
|
-
} catch {
|
|
596
|
+
} catch (error) {
|
|
597
|
+
helperTrace("open-report:chrome:failed", getErrorSummary(error));
|
|
139
598
|
}
|
|
140
599
|
try {
|
|
141
600
|
if (openWithDefaultBrowser()) {
|
|
601
|
+
helperTrace("open-report:default-browser:success", platform);
|
|
142
602
|
console.log("\u{1F680} \uAE30\uBCF8 \uBE0C\uB77C\uC6B0\uC800\uC5D0\uC11C \uB9AC\uD3EC\uD2B8\uB97C \uC5F4\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
143
603
|
return;
|
|
144
604
|
}
|
|
145
|
-
} catch (
|
|
146
|
-
|
|
605
|
+
} catch (error) {
|
|
606
|
+
helperTrace("open-report:default-browser:failed", getErrorSummary(error));
|
|
607
|
+
console.error("\u26A0\uFE0F \uBE0C\uB77C\uC6B0\uC800 \uC5F4\uAE30 \uC2E4\uD328:", error);
|
|
147
608
|
return;
|
|
148
609
|
}
|
|
610
|
+
helperTrace("open-report:unsupported-platform", platform);
|
|
149
611
|
console.error(`\u26A0\uFE0F \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD50C\uB7AB\uD3FC\uC785\uB2C8\uB2E4: ${platform}`);
|
|
150
612
|
}
|
|
151
|
-
function
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
613
|
+
function ensureInteractiveSelectionAvailable(scope, message) {
|
|
614
|
+
if (process.stdin.isTTY && process.stdout.isTTY && typeof process.stdin.setRawMode === "function") {
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
helperTrace(`${scope}:tty-missing`);
|
|
618
|
+
exitWithError(message, {
|
|
619
|
+
scope: `helper:${scope}`
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
function renderSelectionBlock(lines, previousLineCount) {
|
|
623
|
+
if (previousLineCount > 0) {
|
|
624
|
+
readline__default.default.moveCursor(process.stdout, 0, -previousLineCount);
|
|
625
|
+
readline__default.default.clearScreenDown(process.stdout);
|
|
626
|
+
}
|
|
627
|
+
const fittedLines = fitLinesToTerminal(lines);
|
|
628
|
+
process.stdout.write(`${fittedLines.join("\n")}
|
|
629
|
+
`);
|
|
630
|
+
return fittedLines.length;
|
|
631
|
+
}
|
|
632
|
+
function getSelectionWindowRange(optionCount, selectedIndex, windowSize) {
|
|
633
|
+
if (optionCount <= windowSize) {
|
|
634
|
+
return {
|
|
635
|
+
end: optionCount,
|
|
636
|
+
start: 0
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
const halfWindow = Math.floor(windowSize / 2);
|
|
640
|
+
const maxStart = optionCount - windowSize;
|
|
641
|
+
const start = Math.max(0, Math.min(selectedIndex - halfWindow, maxStart));
|
|
642
|
+
return {
|
|
643
|
+
end: Math.min(optionCount, start + windowSize),
|
|
644
|
+
start
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
function buildMultiSelectLines(question, options, selectedIndex, toggled, windowSize) {
|
|
648
|
+
const { start, end } = getSelectionWindowRange(options.length, selectedIndex, windowSize);
|
|
649
|
+
const lines = [
|
|
650
|
+
`${ANSI.bold}${question}${ANSI.reset}`,
|
|
651
|
+
`${ANSI.dim}\u2191\u2193 \uC774\uB3D9 | Space \uC120\uD0DD/\uD574\uC81C | Enter \uC644\uB8CC | Esc \uCDE8\uC18C${ANSI.reset}`,
|
|
652
|
+
`${ANSI.dim}\uC120\uD0DD\uB428: ${toggled.size}\uAC1C / \uC804\uCCB4: ${options.length}\uAC1C${ANSI.reset}`
|
|
653
|
+
];
|
|
654
|
+
for (let index = start; index < end; index += 1) {
|
|
655
|
+
const option = options[index];
|
|
656
|
+
if (!option) {
|
|
657
|
+
continue;
|
|
161
658
|
}
|
|
162
|
-
const
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
659
|
+
const cursor = index === selectedIndex ? `${ANSI.cyan}>${ANSI.reset}` : " ";
|
|
660
|
+
const checked = toggled.has(index) ? `${ANSI.green}\u2611${ANSI.reset}` : "\u2610";
|
|
661
|
+
const description = option.description ? ` ${ANSI.dim}${option.description}${ANSI.reset}` : "";
|
|
662
|
+
lines.push(`${cursor} ${checked} ${option.label}${description}`);
|
|
663
|
+
}
|
|
664
|
+
if (options.length > windowSize) {
|
|
665
|
+
lines.push(`${ANSI.dim}\uD45C\uC2DC \uBC94\uC704: ${start + 1}-${end} / ${options.length}${ANSI.reset}`);
|
|
666
|
+
}
|
|
667
|
+
return lines;
|
|
668
|
+
}
|
|
669
|
+
async function showMultiSelect(question, options, windowSize = COMMIT_SELECTION_WINDOW) {
|
|
670
|
+
ensureInteractiveSelectionAvailable("showMultiSelect", "\u274C \uCEE4\uBC0B \uC120\uD0DD \uBAA8\uB2EC\uC740 TTY \uD658\uACBD\uC5D0\uC11C\uB9CC \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.");
|
|
671
|
+
let selectedIndex = 0;
|
|
672
|
+
let renderedLineCount = 0;
|
|
673
|
+
const toggled = /* @__PURE__ */ new Set();
|
|
674
|
+
const rl = readline__default.default.createInterface({
|
|
675
|
+
input: process.stdin,
|
|
676
|
+
output: process.stdout,
|
|
677
|
+
terminal: true
|
|
678
|
+
});
|
|
679
|
+
process.stdout.write("\x1B[?25l");
|
|
680
|
+
const cleanup = () => {
|
|
681
|
+
if (renderedLineCount > 0) {
|
|
682
|
+
readline__default.default.moveCursor(process.stdout, 0, -renderedLineCount);
|
|
683
|
+
readline__default.default.clearScreenDown(process.stdout);
|
|
684
|
+
renderedLineCount = 0;
|
|
169
685
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
686
|
+
process.stdin.removeListener("data", onData);
|
|
687
|
+
process.stdin.setRawMode(false);
|
|
688
|
+
process.stdin.pause();
|
|
689
|
+
rl.close();
|
|
690
|
+
process.stdout.write("\x1B[?25h");
|
|
691
|
+
};
|
|
692
|
+
const render = () => {
|
|
693
|
+
const lines = buildMultiSelectLines(question, options, selectedIndex, toggled, windowSize);
|
|
694
|
+
renderedLineCount = renderSelectionBlock(lines, renderedLineCount);
|
|
695
|
+
};
|
|
696
|
+
const confirmSelection = (resolve) => {
|
|
697
|
+
const values = [...toggled].sort((left, right) => left - right).map((index) => options[index]?.value).filter((value) => value !== void 0);
|
|
698
|
+
cleanup();
|
|
699
|
+
resolve(values);
|
|
700
|
+
};
|
|
701
|
+
const cancelSelection = (resolve) => {
|
|
702
|
+
cleanup();
|
|
703
|
+
resolve([]);
|
|
704
|
+
};
|
|
705
|
+
let onData = (_data) => {
|
|
706
|
+
};
|
|
707
|
+
render();
|
|
708
|
+
return new Promise((resolve) => {
|
|
709
|
+
onData = (data) => {
|
|
710
|
+
const key = data.toString();
|
|
711
|
+
if (key === "") {
|
|
712
|
+
cleanup();
|
|
713
|
+
process.exit(0);
|
|
178
714
|
}
|
|
179
|
-
|
|
180
|
-
|
|
715
|
+
if (key === "\x1B") {
|
|
716
|
+
cancelSelection(resolve);
|
|
717
|
+
return;
|
|
718
|
+
}
|
|
719
|
+
if (key === "\x1B[A") {
|
|
720
|
+
selectedIndex = (selectedIndex - 1 + options.length) % options.length;
|
|
721
|
+
render();
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
if (key === "\x1B[B") {
|
|
725
|
+
selectedIndex = (selectedIndex + 1) % options.length;
|
|
726
|
+
render();
|
|
727
|
+
return;
|
|
728
|
+
}
|
|
729
|
+
if (key === " ") {
|
|
730
|
+
if (toggled.has(selectedIndex)) {
|
|
731
|
+
toggled.delete(selectedIndex);
|
|
732
|
+
} else {
|
|
733
|
+
toggled.add(selectedIndex);
|
|
734
|
+
}
|
|
735
|
+
render();
|
|
736
|
+
return;
|
|
737
|
+
}
|
|
738
|
+
if (key === "\r" || key === "\n") {
|
|
739
|
+
confirmSelection(resolve);
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
process.stdin.setRawMode(true);
|
|
743
|
+
process.stdin.resume();
|
|
744
|
+
process.stdin.on("data", onData);
|
|
745
|
+
});
|
|
746
|
+
}
|
|
747
|
+
async function selectReviewCommits() {
|
|
748
|
+
const commits = getRecentCommitOptions();
|
|
749
|
+
if (commits.length === 0) {
|
|
750
|
+
console.log("\u2139\uFE0F \uB9AC\uBDF0\uD560 \uCD5C\uADFC \uCEE4\uBC0B\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
751
|
+
return [];
|
|
181
752
|
}
|
|
182
|
-
return
|
|
753
|
+
return showMultiSelect(
|
|
754
|
+
"\uB9AC\uBDF0\uD560 \uCEE4\uBC0B\uC744 \uC120\uD0DD\uD574\uC8FC\uC138\uC694.",
|
|
755
|
+
commits.map((commit) => ({
|
|
756
|
+
description: commit.description,
|
|
757
|
+
label: commit.label,
|
|
758
|
+
value: commit
|
|
759
|
+
})),
|
|
760
|
+
COMMIT_SELECTION_WINDOW
|
|
761
|
+
);
|
|
183
762
|
}
|
|
184
763
|
function selectAIService() {
|
|
185
764
|
const service = parseServiceFromArgs();
|
|
186
765
|
if (!service) {
|
|
187
|
-
|
|
188
|
-
|
|
766
|
+
helperTrace("select-service:missing");
|
|
767
|
+
exitWithError("\u274C \uC11C\uBE44\uC2A4\uAC00 \uC120\uD0DD\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.", {
|
|
768
|
+
scope: "helper:selectAIService"
|
|
769
|
+
});
|
|
189
770
|
}
|
|
771
|
+
helperTrace("select-service:done", service);
|
|
190
772
|
return service;
|
|
191
773
|
}
|
|
192
774
|
async function showSelectionAIService() {
|
|
193
775
|
const selectedServiceFromArgs = parseServiceFromArgs();
|
|
194
776
|
if (selectedServiceFromArgs) {
|
|
777
|
+
helperTrace("show-selection:from-args", selectedServiceFromArgs);
|
|
195
778
|
console.log(`
|
|
196
|
-
\u2705
|
|
779
|
+
\u2705 ${ANSI.green}${selectedServiceFromArgs}${ANSI.reset} \uC11C\uBE44\uC2A4\uAC00 \uC120\uD0DD\uB418\uC5C8\uC2B5\uB2C8\uB2E4. (--service)
|
|
197
780
|
`);
|
|
198
781
|
return selectedServiceFromArgs;
|
|
199
782
|
}
|
|
783
|
+
ensureInteractiveSelectionAvailable("showSelectionAIService", "\u274C AI \uC11C\uBE44\uC2A4 \uC120\uD0DD UI\uB294 TTY \uD658\uACBD\uC5D0\uC11C\uB9CC \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.");
|
|
784
|
+
helperTrace("show-selection:interactive:start");
|
|
200
785
|
let selectedIndex = 0;
|
|
201
786
|
const rl = readline__default.default.createInterface({
|
|
202
787
|
input: process.stdin,
|
|
@@ -210,13 +795,15 @@ async function showSelectionAIService() {
|
|
|
210
795
|
readline__default.default.moveCursor(process.stdout, 0, -(AIServices.length + 1));
|
|
211
796
|
}
|
|
212
797
|
firstRender = false;
|
|
798
|
+
helperTrace("show-selection:interactive:render", AIServices[selectedIndex] || "unknown");
|
|
213
799
|
readline__default.default.clearScreenDown(process.stdout);
|
|
214
800
|
process.stdout.write(
|
|
215
|
-
|
|
801
|
+
`\u{1F916} AI \uC11C\uBE44\uC2A4\uB97C \uC120\uD0DD\uD574\uC8FC\uC138\uC694 (${ANSI.yellow}\u2191\u2193 \uBC29\uD5A5\uD0A4${ANSI.reset} \uC774\uB3D9, ${ANSI.yellow}Enter${ANSI.reset} \uC120\uD0DD):
|
|
802
|
+
`
|
|
216
803
|
);
|
|
217
804
|
AIServices.forEach((service, index) => {
|
|
218
805
|
if (index === selectedIndex) {
|
|
219
|
-
process.stdout.write(`
|
|
806
|
+
process.stdout.write(` ${ANSI.cyan}>${ANSI.reset} ${ANSI.cyan}\u25C9${ANSI.reset} ${ANSI.bold}${service}${ANSI.reset}
|
|
220
807
|
`);
|
|
221
808
|
} else {
|
|
222
809
|
process.stdout.write(` \u25EF ${service}
|
|
@@ -229,6 +816,7 @@ async function showSelectionAIService() {
|
|
|
229
816
|
const onData = (data) => {
|
|
230
817
|
const key = data.toString();
|
|
231
818
|
if (key === "") {
|
|
819
|
+
helperTrace("show-selection:interactive:ctrl-c");
|
|
232
820
|
process.stdout.write("\x1B[?25h");
|
|
233
821
|
process.exit(0);
|
|
234
822
|
}
|
|
@@ -245,10 +833,11 @@ async function showSelectionAIService() {
|
|
|
245
833
|
rl.close();
|
|
246
834
|
process.stdout.write("\x1B[?25h");
|
|
247
835
|
console.log(`
|
|
248
|
-
\u2705
|
|
836
|
+
\u2705 ${ANSI.green}${AIServices[selectedIndex]}${ANSI.reset} \uC11C\uBE44\uC2A4\uAC00 \uC120\uD0DD\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
|
|
249
837
|
`);
|
|
250
838
|
const result = AIServices[selectedIndex];
|
|
251
839
|
if (result) {
|
|
840
|
+
helperTrace("show-selection:interactive:confirmed", result);
|
|
252
841
|
resolve(result);
|
|
253
842
|
}
|
|
254
843
|
}
|
|
@@ -260,16 +849,30 @@ async function showSelectionAIService() {
|
|
|
260
849
|
}
|
|
261
850
|
|
|
262
851
|
exports.AIServices = AIServices;
|
|
852
|
+
exports.COMMIT_FETCH_LIMIT = COMMIT_FETCH_LIMIT;
|
|
853
|
+
exports.COMMIT_SELECTION_WINDOW = COMMIT_SELECTION_WINDOW;
|
|
263
854
|
exports.REPORT_DIR = REPORT_DIR;
|
|
855
|
+
exports.buildSelectedCommitDiff = buildSelectedCommitDiff;
|
|
856
|
+
exports.buildSelectedCommitSummary = buildSelectedCommitSummary;
|
|
857
|
+
exports.buildSelectedFileDiff = buildSelectedFileDiff;
|
|
858
|
+
exports.clearTraceMessages = clearTraceMessages;
|
|
264
859
|
exports.codingConventionRulesPath = codingConventionRulesPath;
|
|
265
860
|
exports.createReportDirectory = createReportDirectory;
|
|
266
861
|
exports.createTraceLogger = createTraceLogger;
|
|
267
862
|
exports.deleteFile = deleteFile;
|
|
268
863
|
exports.deleteTempDiff = deleteTempDiff;
|
|
269
|
-
exports.
|
|
864
|
+
exports.executeShellCommandWithProgress = executeShellCommandWithProgress;
|
|
865
|
+
exports.exitWithError = exitWithError;
|
|
866
|
+
exports.formatReviewTargetFiles = formatReviewTargetFiles;
|
|
867
|
+
exports.getAvailableFilePath = getAvailableFilePath;
|
|
868
|
+
exports.getErrorLogTimestamp = getErrorLogTimestamp;
|
|
869
|
+
exports.getErrorSummary = getErrorSummary;
|
|
270
870
|
exports.getGitDiffFilter = getGitDiffFilter;
|
|
271
871
|
exports.getNextFilePath = getNextFilePath;
|
|
272
872
|
exports.getNowString = getNowString;
|
|
873
|
+
exports.getRecentCommitOptions = getRecentCommitOptions;
|
|
874
|
+
exports.getSelectedCommitFiles = getSelectedCommitFiles;
|
|
875
|
+
exports.getTraceMessages = getTraceMessages;
|
|
273
876
|
exports.ignoreList = ignoreList;
|
|
274
877
|
exports.isTestMode = isTestMode;
|
|
275
878
|
exports.namingRulesPath = namingRulesPath;
|
|
@@ -278,7 +881,10 @@ exports.reviewFormOneByOnePath = reviewFormOneByOnePath;
|
|
|
278
881
|
exports.reviewFormPath = reviewFormPath;
|
|
279
882
|
exports.rulesPath = rulesPath;
|
|
280
883
|
exports.selectAIService = selectAIService;
|
|
884
|
+
exports.selectReviewCommits = selectReviewCommits;
|
|
885
|
+
exports.showMultiSelect = showMultiSelect;
|
|
281
886
|
exports.showSelectionAIService = showSelectionAIService;
|
|
282
887
|
exports.tempDiffPath = tempDiffPath;
|
|
888
|
+
exports.writeErrorReport = writeErrorReport;
|
|
283
889
|
//# sourceMappingURL=helper.cjs.map
|
|
284
890
|
//# sourceMappingURL=helper.cjs.map
|