sales-frontend-gemini-cli 0.2.0 → 0.3.0
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/{pr-review → common}/helper.cjs +77 -1
- package/dist/common/helper.cjs.map +1 -0
- package/dist/{pr-review → common}/helper.d.cts +12 -1
- package/dist/{pr-review → common}/helper.d.ts +12 -1
- package/dist/{pr-review → common}/helper.js +74 -2
- package/dist/common/helper.js.map +1 -0
- package/dist/common/types.cjs +4 -0
- package/dist/common/types.cjs.map +1 -0
- package/dist/common/types.d.cts +3 -0
- package/dist/common/types.d.ts +3 -0
- package/dist/common/types.js +3 -0
- package/dist/common/types.js.map +1 -0
- package/dist/pr-review/claude/claude-commander.cjs +59 -0
- package/dist/pr-review/claude/claude-commander.cjs.map +1 -0
- package/dist/pr-review/claude/claude-commander.d.cts +17 -0
- package/dist/pr-review/claude/claude-commander.d.ts +17 -0
- package/dist/pr-review/claude/claude-commander.js +51 -0
- package/dist/pr-review/claude/claude-commander.js.map +1 -0
- package/dist/pr-review/claude/installation-claude.cjs +27 -0
- package/dist/pr-review/claude/installation-claude.cjs.map +1 -0
- package/dist/pr-review/claude/installation-claude.d.cts +3 -0
- package/dist/pr-review/claude/installation-claude.d.ts +3 -0
- package/dist/pr-review/claude/installation-claude.js +25 -0
- package/dist/pr-review/claude/installation-claude.js.map +1 -0
- package/dist/pr-review/{commander.cjs → gemini/gemini-commander.cjs} +7 -7
- package/dist/pr-review/gemini/gemini-commander.cjs.map +1 -0
- package/dist/pr-review/{commander.d.cts → gemini/gemini-commander.d.cts} +2 -2
- package/dist/pr-review/{commander.d.ts → gemini/gemini-commander.d.ts} +2 -2
- package/dist/pr-review/{commander.js → gemini/gemini-commander.js} +6 -6
- package/dist/pr-review/gemini/gemini-commander.js.map +1 -0
- package/dist/{common → pr-review/gemini}/installation-gcloud.cjs +1 -1
- package/dist/pr-review/gemini/installation-gcloud.cjs.map +1 -0
- package/dist/{common → pr-review/gemini}/installation-gcloud.js +1 -1
- package/dist/pr-review/gemini/installation-gcloud.js.map +1 -0
- package/dist/{common → pr-review/gemini}/installation-gemini.cjs +1 -1
- package/dist/pr-review/gemini/installation-gemini.cjs.map +1 -0
- package/dist/{common → pr-review/gemini}/installation-gemini.js +1 -1
- package/dist/pr-review/gemini/installation-gemini.js.map +1 -0
- package/dist/pr-review/{interactive-version → gemini/interactive-version}/index.cjs +2 -2
- package/dist/pr-review/gemini/interactive-version/index.cjs.map +1 -0
- package/dist/pr-review/{interactive-version → gemini/interactive-version}/index.js +2 -2
- package/dist/pr-review/gemini/interactive-version/index.js.map +1 -0
- package/dist/{common → pr-review/gemini}/login.cjs +1 -1
- package/dist/pr-review/gemini/login.cjs.map +1 -0
- package/dist/{common → pr-review/gemini}/login.js +1 -1
- package/dist/pr-review/gemini/login.js.map +1 -0
- package/dist/pr-review/{vertex-version → gemini/vertex-version}/index.cjs +1 -1
- package/dist/pr-review/gemini/vertex-version/index.cjs.map +1 -0
- package/dist/pr-review/{vertex-version → gemini/vertex-version}/index.js +1 -1
- package/dist/pr-review/gemini/vertex-version/index.js.map +1 -0
- package/dist/pr-review/review-one-by-one.cjs +180 -45
- package/dist/pr-review/review-one-by-one.cjs.map +1 -1
- package/dist/pr-review/review-one-by-one.js +178 -44
- package/dist/pr-review/review-one-by-one.js.map +1 -1
- package/dist/pr-review/review.cjs +196 -60
- package/dist/pr-review/review.cjs.map +1 -1
- package/dist/pr-review/review.js +195 -60
- package/dist/pr-review/review.js.map +1 -1
- package/package.json +9 -9
- package/src/common/rules/review-rules.md +49 -0
- package/dist/common/installation-gcloud.cjs.map +0 -1
- package/dist/common/installation-gcloud.js.map +0 -1
- package/dist/common/installation-gemini.cjs.map +0 -1
- package/dist/common/installation-gemini.js.map +0 -1
- package/dist/common/login.cjs.map +0 -1
- package/dist/common/login.js.map +0 -1
- package/dist/pr-review/commander.cjs.map +0 -1
- package/dist/pr-review/commander.js.map +0 -1
- package/dist/pr-review/helper.cjs.map +0 -1
- package/dist/pr-review/helper.js.map +0 -1
- package/dist/pr-review/interactive-version/index.cjs.map +0 -1
- package/dist/pr-review/interactive-version/index.js.map +0 -1
- package/dist/pr-review/vertex-version/index.cjs.map +0 -1
- package/dist/pr-review/vertex-version/index.js.map +0 -1
- package/src/pr-review/rules/review-rules.md +0 -71
- /package/dist/{common → pr-review/gemini}/installation-gcloud.d.cts +0 -0
- /package/dist/{common → pr-review/gemini}/installation-gcloud.d.ts +0 -0
- /package/dist/{common → pr-review/gemini}/installation-gemini.d.cts +0 -0
- /package/dist/{common → pr-review/gemini}/installation-gemini.d.ts +0 -0
- /package/dist/pr-review/{interactive-version → gemini/interactive-version}/index.d.cts +0 -0
- /package/dist/pr-review/{interactive-version → gemini/interactive-version}/index.d.ts +0 -0
- /package/dist/{common → pr-review/gemini}/login.d.cts +0 -0
- /package/dist/{common → pr-review/gemini}/login.d.ts +0 -0
- /package/dist/pr-review/{vertex-version → gemini/vertex-version}/index.d.cts +0 -0
- /package/dist/pr-review/{vertex-version → gemini/vertex-version}/index.d.ts +0 -0
- /package/src/{pr-review → common}/form/review-form-one-by-one.md +0 -0
- /package/src/{pr-review → common}/form/review-form.md +0 -0
package/dist/pr-review/review.js
CHANGED
|
@@ -2,26 +2,9 @@
|
|
|
2
2
|
import { execSync } from 'child_process';
|
|
3
3
|
import fs from 'fs';
|
|
4
4
|
import path from 'path';
|
|
5
|
+
import readline from 'readline';
|
|
5
6
|
import { fileURLToPath } from 'url';
|
|
6
7
|
|
|
7
|
-
function checkGeminiCliInstalled() {
|
|
8
|
-
try {
|
|
9
|
-
execSync("gemini --version", { stdio: "ignore" });
|
|
10
|
-
} catch {
|
|
11
|
-
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");
|
|
12
|
-
try {
|
|
13
|
-
execSync("npm install -g @google/gemini-cli", { stdio: "inherit" });
|
|
14
|
-
console.log("\u2705 gemini-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
15
|
-
console.log("\u26A0\uFE0F Gemini API \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
16
|
-
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.');
|
|
17
|
-
process.exit(1);
|
|
18
|
-
} catch (installError) {
|
|
19
|
-
console.error("\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).");
|
|
20
|
-
console.error(installError);
|
|
21
|
-
process.exit(1);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
8
|
var __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
26
9
|
var rulesPath = path.resolve(__dirname, "../../src/pr-review/rules/review-rules.md");
|
|
27
10
|
var namingRulesPath = path.resolve(__dirname, "../../src/pr-review/rules/naming-rule.md");
|
|
@@ -30,6 +13,7 @@ var reviewFormPath = path.resolve(__dirname, "../../src/pr-review/form/review-fo
|
|
|
30
13
|
path.resolve(__dirname, "../../src/pr-review/form/review-form-one-by-one.md");
|
|
31
14
|
var REPORT_DIR = ".review-report";
|
|
32
15
|
var tempDiffPath = "temp_diff.txt";
|
|
16
|
+
var AIServices = ["gemini", "claude", "codex"];
|
|
33
17
|
var ignoreList = [
|
|
34
18
|
"package.json",
|
|
35
19
|
"*.yml",
|
|
@@ -126,20 +110,130 @@ function getDiffArgs() {
|
|
|
126
110
|
}
|
|
127
111
|
return diffArgs;
|
|
128
112
|
}
|
|
129
|
-
|
|
130
|
-
|
|
113
|
+
async function showSelectionAIService() {
|
|
114
|
+
let selectedIndex = 0;
|
|
115
|
+
const rl = readline.createInterface({
|
|
116
|
+
input: process.stdin,
|
|
117
|
+
output: process.stdout,
|
|
118
|
+
terminal: true
|
|
119
|
+
});
|
|
120
|
+
let firstRender = true;
|
|
121
|
+
process.stdout.write("\x1B[?25l");
|
|
122
|
+
const render = () => {
|
|
123
|
+
if (!firstRender) {
|
|
124
|
+
readline.moveCursor(process.stdout, 0, -(AIServices.length + 1));
|
|
125
|
+
}
|
|
126
|
+
firstRender = false;
|
|
127
|
+
readline.clearScreenDown(process.stdout);
|
|
128
|
+
process.stdout.write("\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");
|
|
129
|
+
AIServices.forEach((service, index) => {
|
|
130
|
+
if (index === selectedIndex) {
|
|
131
|
+
process.stdout.write(` \x1B[36m>\x1B[0m \x1B[36m\u25C9\x1B[0m \x1B[1m${service}\x1B[0m
|
|
132
|
+
`);
|
|
133
|
+
} else {
|
|
134
|
+
process.stdout.write(` \u25EF ${service}
|
|
135
|
+
`);
|
|
136
|
+
}
|
|
137
|
+
});
|
|
138
|
+
};
|
|
139
|
+
render();
|
|
140
|
+
return new Promise((resolve) => {
|
|
141
|
+
const onData = (data) => {
|
|
142
|
+
const key = data.toString();
|
|
143
|
+
if (key === "") {
|
|
144
|
+
process.stdout.write("\x1B[?25h");
|
|
145
|
+
process.exit(0);
|
|
146
|
+
}
|
|
147
|
+
if (key === "\x1B[A") {
|
|
148
|
+
selectedIndex = (selectedIndex - 1 + AIServices.length) % AIServices.length;
|
|
149
|
+
render();
|
|
150
|
+
} else if (key === "\x1B[B") {
|
|
151
|
+
selectedIndex = (selectedIndex + 1) % AIServices.length;
|
|
152
|
+
render();
|
|
153
|
+
} else if (key === "\r" || key === "\n") {
|
|
154
|
+
process.stdin.removeListener("data", onData);
|
|
155
|
+
process.stdin.setRawMode(false);
|
|
156
|
+
process.stdin.pause();
|
|
157
|
+
rl.close();
|
|
158
|
+
process.stdout.write("\x1B[?25h");
|
|
159
|
+
console.log(`
|
|
160
|
+
\u2705 \x1B[32m${AIServices[selectedIndex]}\x1B[0m \uC11C\uBE44\uC2A4\uAC00 \uC120\uD0DD\uB418\uC5C8\uC2B5\uB2C8\uB2E4.
|
|
161
|
+
`);
|
|
162
|
+
const result = AIServices[selectedIndex];
|
|
163
|
+
if (result) {
|
|
164
|
+
resolve(result);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
process.stdin.setRawMode(true);
|
|
169
|
+
process.stdin.resume();
|
|
170
|
+
process.stdin.on("data", onData);
|
|
171
|
+
});
|
|
172
|
+
}
|
|
131
173
|
var args = process.argv.slice(2);
|
|
132
|
-
var
|
|
174
|
+
var createClaudeCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
133
175
|
let modelOption = "";
|
|
134
176
|
if (args.includes("--review")) {
|
|
135
|
-
modelOption = "--model
|
|
177
|
+
modelOption = "--model opus";
|
|
136
178
|
} else if (args.includes("--flash")) {
|
|
137
|
-
modelOption = "--model
|
|
179
|
+
modelOption = "--model haiku";
|
|
138
180
|
} else {
|
|
139
181
|
const modelIndex = args.indexOf("--model");
|
|
140
182
|
if (modelIndex !== -1 && args[modelIndex + 1]) {
|
|
141
183
|
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.");
|
|
142
184
|
modelOption = `--model ${args[modelIndex + 1]}`;
|
|
185
|
+
} else {
|
|
186
|
+
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.");
|
|
187
|
+
modelOption = "--model sonnet";
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
const rules = [
|
|
191
|
+
{ path: rulesPath, display: "\uB8F0\uC14B" },
|
|
192
|
+
{ path: namingRulesPath, display: "\uB124\uC774\uBC0D \uADDC\uCE59" },
|
|
193
|
+
{ path: codingConventionRulesPath, display: "\uCF54\uB529 \uCEE8\uBCA4\uC158" }
|
|
194
|
+
];
|
|
195
|
+
const systemPromptFiles = rules.filter((rule) => fs.existsSync(rule.path)).map((rule) => `--append-system-prompt-file ${rule.path}`).join(" ");
|
|
196
|
+
const reviewFormOption = fs.existsSync(reviewFormPath2) ? `--append-system-prompt-file ${reviewFormPath2}` : "";
|
|
197
|
+
const command = `cat ${tempDiffPath2} | claude ${modelOption} ${systemPromptFiles} ${reviewFormOption} -p "\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."`;
|
|
198
|
+
if (args.includes("--test")) {
|
|
199
|
+
const safeCommand = command.replace(/"/g, '\\"');
|
|
200
|
+
return `echo "[TEST MODE] Claude \uBA85\uB839\uC5B4\uAC00 \uC2E4\uD589\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.
|
|
201
|
+
|
|
202
|
+
\uC0DD\uC131\uB420 \uBA85\uB839\uC5B4 \uBBF8\uB9AC\uBCF4\uAE30:
|
|
203
|
+
${safeCommand}"`;
|
|
204
|
+
}
|
|
205
|
+
return command;
|
|
206
|
+
};
|
|
207
|
+
function checkClaudeCliInstalled() {
|
|
208
|
+
try {
|
|
209
|
+
execSync("claude --version", { stdio: "ignore" });
|
|
210
|
+
} catch {
|
|
211
|
+
console.log("\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");
|
|
212
|
+
try {
|
|
213
|
+
execSync("npm install -g @anthropic-ai/claude-code", { stdio: "inherit" });
|
|
214
|
+
console.log("\u2705 claude-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
215
|
+
console.log("\u26A0\uFE0F claude-cli \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
216
|
+
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.');
|
|
217
|
+
process.exit(1);
|
|
218
|
+
} catch (installError) {
|
|
219
|
+
console.error("\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).");
|
|
220
|
+
console.error(installError);
|
|
221
|
+
process.exit(1);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
var args2 = process.argv.slice(2);
|
|
226
|
+
var createGeminiCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
227
|
+
let modelOption = "";
|
|
228
|
+
if (args2.includes("--review")) {
|
|
229
|
+
modelOption = "--model pro";
|
|
230
|
+
} else if (args2.includes("--flash")) {
|
|
231
|
+
modelOption = "--model flash";
|
|
232
|
+
} else {
|
|
233
|
+
const modelIndex = args2.indexOf("--model");
|
|
234
|
+
if (modelIndex !== -1 && args2[modelIndex + 1]) {
|
|
235
|
+
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.");
|
|
236
|
+
modelOption = `--model ${args2[modelIndex + 1]}`;
|
|
143
237
|
} else {
|
|
144
238
|
console.warn("\u26A0\uFE0F \uBAA8\uB378\uC774 \uC9C0\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. \uAE30\uBCF8 \uBAA8\uB378\uC778 gemini-flash\uB97C \uC0AC\uC6A9\uD569\uB2C8\uB2E4.");
|
|
145
239
|
modelOption = "--model flash";
|
|
@@ -152,7 +246,7 @@ var createCommand = (tempDiffPath2, reviewFormPath2) => {
|
|
|
152
246
|
];
|
|
153
247
|
const validRules = rules.filter((rule) => fs.existsSync(rule.path)).map((rule) => `@${rule.path}`).join(", ");
|
|
154
248
|
const command = `gemini ${modelOption} -p "\uB2E4\uC74C \uADDC\uCE59\uB4E4\uC744 \uCC38\uACE0\uD574\uC11C(${validRules}) \uC774 diff(@${tempDiffPath2})\uB97C \uB9AC\uBDF0\uD574\uC918. \uB9AC\uBDF0\uC591\uC2DD\uC740 @${reviewFormPath2} \uC5D0 \uB9DE\uCDB0\uC11C \uC791\uC131\uD574\uC918. "`;
|
|
155
|
-
if (
|
|
249
|
+
if (args2.includes("--test")) {
|
|
156
250
|
const safeCommand = command.replace(/"/g, '\\"');
|
|
157
251
|
return `echo "[TEST MODE] Gemini \uBA85\uB839\uC5B4\uAC00 \uC2E4\uD589\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4.
|
|
158
252
|
|
|
@@ -161,51 +255,92 @@ ${safeCommand}"`;
|
|
|
161
255
|
}
|
|
162
256
|
return command;
|
|
163
257
|
};
|
|
164
|
-
|
|
165
|
-
// src/pr-review/review.ts
|
|
166
|
-
var args2 = process.argv.slice(2);
|
|
167
|
-
var isTest = args2.includes("--test");
|
|
168
|
-
checkGeminiCliInstalled();
|
|
169
|
-
try {
|
|
170
|
-
console.log("\u{1F680} AI Code Review\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4...");
|
|
171
|
-
const nowStr = getNowString();
|
|
172
|
-
createReportDirectory();
|
|
173
|
-
const diffArgs = getDiffArgs();
|
|
174
|
-
let diff = "";
|
|
175
|
-
const { includeParams, excludeParams } = getGitDiffFilter();
|
|
258
|
+
function checkGeminiCliInstalled() {
|
|
176
259
|
try {
|
|
177
|
-
|
|
260
|
+
execSync("gemini --version", { stdio: "ignore" });
|
|
178
261
|
} catch {
|
|
262
|
+
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");
|
|
263
|
+
try {
|
|
264
|
+
execSync("npm install -g @google/gemini-cli", { stdio: "inherit" });
|
|
265
|
+
console.log("\u2705 gemini-cli \uC124\uCE58\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.");
|
|
266
|
+
console.log("\u26A0\uFE0F Gemini API \uC0AC\uC6A9\uC744 \uC704\uD574 \uC778\uC99D\uC774 \uD544\uC694\uD569\uB2C8\uB2E4.");
|
|
267
|
+
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.');
|
|
268
|
+
process.exit(1);
|
|
269
|
+
} catch (installError) {
|
|
270
|
+
console.error("\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).");
|
|
271
|
+
console.error(installError);
|
|
272
|
+
process.exit(1);
|
|
273
|
+
}
|
|
179
274
|
}
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// src/pr-review/review.ts
|
|
278
|
+
async function main() {
|
|
279
|
+
const args3 = process.argv.slice(2);
|
|
280
|
+
const isTest = args3.includes("--test");
|
|
281
|
+
const service = await showSelectionAIService();
|
|
282
|
+
switch (service) {
|
|
283
|
+
case "gemini":
|
|
284
|
+
checkGeminiCliInstalled();
|
|
285
|
+
break;
|
|
286
|
+
case "claude":
|
|
287
|
+
checkClaudeCliInstalled();
|
|
288
|
+
break;
|
|
184
289
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
290
|
+
try {
|
|
291
|
+
console.log("\u{1F680} AI Code Review\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4...");
|
|
292
|
+
const nowStr = getNowString();
|
|
293
|
+
createReportDirectory();
|
|
294
|
+
const diffArgs = getDiffArgs();
|
|
295
|
+
let diff = "";
|
|
296
|
+
const { includeParams, excludeParams } = getGitDiffFilter();
|
|
297
|
+
try {
|
|
298
|
+
diff = execSync(`git diff ${diffArgs} -- ${includeParams} ${excludeParams}`).toString();
|
|
299
|
+
} catch {
|
|
300
|
+
}
|
|
301
|
+
if (!diff.trim() && !isTest) {
|
|
302
|
+
console.log("\u2139\uFE0F \uB9AC\uBDF0\uD560 \uBCC0\uACBD \uC0AC\uD56D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4 (Unstaged Empty & HEAD Empty).");
|
|
303
|
+
deleteTempDiff();
|
|
304
|
+
process.exit(0);
|
|
305
|
+
}
|
|
306
|
+
fs.writeFileSync(tempDiffPath, diff);
|
|
307
|
+
const savedDiffPath = getNextFilePath(REPORT_DIR, `${nowStr}-diff`, ".txt");
|
|
308
|
+
fs.copyFileSync(tempDiffPath, savedDiffPath);
|
|
309
|
+
let command = "";
|
|
310
|
+
switch (service) {
|
|
311
|
+
case "gemini":
|
|
312
|
+
command = createGeminiCommand(tempDiffPath, reviewFormPath);
|
|
313
|
+
break;
|
|
314
|
+
case "claude":
|
|
315
|
+
command = createClaudeCommand(tempDiffPath, reviewFormPath);
|
|
316
|
+
break;
|
|
317
|
+
case "codex":
|
|
318
|
+
break;
|
|
319
|
+
}
|
|
320
|
+
const result = execSync(command).toString();
|
|
321
|
+
console.log(result);
|
|
322
|
+
const savedReportPath = getNextFilePath(REPORT_DIR, nowStr, ".md");
|
|
323
|
+
fs.writeFileSync(savedReportPath, result);
|
|
324
|
+
if (isTest) {
|
|
325
|
+
fs.appendFileSync(savedReportPath, `
|
|
194
326
|
|
|
195
327
|
## \uC0AC\uC6A9\uB41C \uBA85\uB839\uC5B4
|
|
196
328
|
|
|
197
329
|
${command}`);
|
|
198
|
-
|
|
330
|
+
}
|
|
331
|
+
console.log(`
|
|
199
332
|
\u2705 \uB9AC\uBDF0\uAC00 \uC644\uB8CC\uB418\uC5C8\uC2B5\uB2C8\uB2E4.`);
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
} catch (error) {
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
333
|
+
console.log(`\u{1F4C4} \uB9AC\uD3EC\uD2B8 \uC800\uC7A5 \uC704\uCE58: ${savedReportPath}`);
|
|
334
|
+
console.log(`diff \uC800\uC7A5 \uC704\uCE58: ${savedDiffPath}`);
|
|
335
|
+
openReport(savedReportPath);
|
|
336
|
+
deleteTempDiff();
|
|
337
|
+
} catch (error) {
|
|
338
|
+
console.error("\u274C \uB9AC\uBDF0 \uB3C4\uC911 \uC624\uB958\uAC00 \uBC1C\uC0DD\uD588\uC2B5\uB2C8\uB2E4.");
|
|
339
|
+
console.error(error);
|
|
340
|
+
deleteTempDiff();
|
|
341
|
+
process.exit(1);
|
|
342
|
+
}
|
|
209
343
|
}
|
|
344
|
+
main();
|
|
210
345
|
//# sourceMappingURL=review.js.map
|
|
211
346
|
//# sourceMappingURL=review.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/common/installation-gemini.ts","../../src/pr-review/helper.ts","../../src/pr-review/commander.ts","../../src/pr-review/review.ts"],"names":["execSync","args","tempDiffPath","reviewFormPath","fs"],"mappings":"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","file":"review.js","sourcesContent":["import { execSync } from \"child_process\";\n\n// gemini-cli 설치 확인 및 설치\nexport function checkGeminiCliInstalled() {\n try {\n execSync('gemini --version', { stdio: 'ignore' });\n } catch {\n console.log('ℹ️ gemini-cli가 설치되어 있지 않습니다. 설치를 진행합니다... npm install -g @google/gemini-cli');\n try {\n execSync('npm install -g @google/gemini-cli', { stdio: 'inherit' });\n console.log('✅ gemini-cli 설치가 완료되었습니다.');\n console.log('⚠️ Gemini API 사용을 위해 인증이 필요합니다.');\n console.log(' 터미널에서 \"gemini\" 를 입력하여 브라우저 로그인을 완료한 후, 다시 시도해주세요.');\n process.exit(1);\n } catch (installError) {\n console.error('❌ gemini-cli 설치 중 오류가 발생했습니다. 권한 문제일 수 있습니다 (sudo 필요).');\n console.error(installError);\n process.exit(1);\n }\n }\n}","import { execSync } from 'child_process';\nimport fs from 'fs'\nimport path from 'path';\nimport { fileURLToPath } from 'url';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\n// 설치된 위치에 맞게 review-rules.md 경로를 계산 (dist에서 src로 이동 등 고려)\n// dist/common/helper.js 가 실행되므로 __dirname은 .../dist/common 입니다.\n// 따라서 ../../src/pr-review/rules 로 이동해야 원본 소스의 규칙 파일을 찾을 수 있습니다.\nexport const rulesPath = path.resolve(__dirname, '../../src/pr-review/rules/review-rules.md');\nexport const namingRulesPath = path.resolve(__dirname, '../../src/pr-review/rules/naming-rule.md');\nexport const codingConventionRulesPath = path.resolve(__dirname, '../../src/pr-review/rules/coding-convention.md');\nexport const reviewFormPath = path.resolve(__dirname, '../../src/pr-review/form/review-form.md');\nexport const reviewFormOneByOnePath = path.resolve(__dirname, '../../src/pr-review/form/review-form-one-by-one.md');\nexport const REPORT_DIR = '.review-report';\nexport const tempDiffPath = 'temp_diff.txt';\n\nexport const ignoreList = [\n 'package.json',\n '*.yml',\n '*.md',\n '*.lock',\n 'dist/',\n 'node_modules/',\n 'assets/',\n 'public/',\n '*.json',\n '*.yaml',\n '.review-report/' // 생성되는 리포트 폴더도 제외\n];\n\n\nexport function getNextFilePath(dir: string, baseName: string, extension: string) {\n let counter = 1;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const filePath = path.join(dir, `${baseName}-${counter}${extension}`);\n if (!fs.existsSync(filePath)) {\n return filePath;\n }\n counter++;\n }\n}\n\nexport function deleteFile(filePath: string) {\n if (fs.existsSync(filePath)) {\n fs.unlinkSync(filePath);\n }\n}\n\n\n/**\n * 임시파일 삭제\n */\nexport function deleteTempDiff() {\n deleteFile(tempDiffPath);\n}\n\n\n/**\n * 리뷰 결과 폴더 생성\n */\nexport function createReportDirectory() {\n if (!fs.existsSync(REPORT_DIR)) {\n fs.mkdirSync(REPORT_DIR, { recursive: true });\n }\n}\n\n\n/**\n * 현재 시간 문자열 생성\n */\nexport function getNowString() {\n const now = new Date();\n const YYYY = now.getFullYear();\n const MM = String(now.getMonth() + 1).padStart(2, '0');\n const DD = String(now.getDate()).padStart(2, '0');\n const HH = String(now.getHours()).padStart(2, '0');\n const mm = String(now.getMinutes()).padStart(2, '0');\n const ss = String(now.getSeconds()).padStart(2, '0');\n\n return `${YYYY}-${MM}-${DD}_${HH}-${mm}-${ss}`;\n}\n\nexport function getGitDiffFilter() {\n\n // 1. 리뷰 대상 파일 확장자 정의\n const includeExtensions = ['*.ts', '*.tsx', '*.js', '*.jsx'];\n\n // ignoreList 를 import 하여 재사용하여 작성한다.\n const excludePatterns = ignoreList.map(item => `:(exclude)${item}`);\n\n // const excludePatterns = [':(exclude)*.lock', ':(exclude)dist/', ':(exclude)*.md'];\n\n // 2. 변경된 파일 목록 가져오기 (각 패턴을 따옴표로 감싸서 쉘 에러 방지)\n const quote = (pattern: string) => `\"${pattern}\"`;\n const includeParams = includeExtensions.map(quote).join(' ');\n const excludeParams = excludePatterns.map(quote).join(' ');\n\n return { includeParams, excludeParams };\n\n\n}\n\nexport function openReport(reportPath: string) {\n // 브라우저 열기\n try {\n execSync(`open -a \"Google Chrome\" \"${path.resolve(reportPath)}\"`);\n console.log(`🚀 브라우저에서 리포트를 열었습니다.`);\n } catch (e) {\n console.error('⚠️ 브라우저 열기 실패:', e);\n }\n}\n\n\nexport function getDiffArgs() {\n const args = process.argv.slice(2);\n const commitIndex = args.indexOf('--commit');\n const { includeParams, excludeParams } = getGitDiffFilter();\n\n let diffArgs = '';\n\n if (commitIndex !== -1) {\n // 특정 커밋 (및 이전 n개) 리뷰\n const commitHash = args[commitIndex + 1];\n if (!commitHash) {\n console.error('❌ 커밋 해시가 제공되지 않았습니다.');\n process.exit(1);\n }\n\n // n값 확인 (optional)\n const nextArg = args[commitIndex + 2];\n let n = 0;\n if (nextArg && !nextArg.startsWith('--')) {\n n = parseInt(nextArg, 10);\n if (isNaN(n)) {\n n = 0;\n }\n }\n\n console.log(`ℹ️ 커밋 '${commitHash}' ${n > 0 ? ` 포함 총 ${n + 1}개의 커밋` : ''}을 리뷰합니다...`);\n diffArgs = `${commitHash}~${n + 1} ${commitHash}`;\n } else {\n // 기본 모드:\n // 1. Unstaged 변경사항 확인\n try {\n const check = execSync(`git diff --name-only -- ${includeParams} ${excludeParams}`).toString();\n if (!check.trim()) {\n console.log('ℹ️ Unstaged 변경사항이 없습니다. 마지막 커밋(HEAD)을 리뷰합니다...');\n diffArgs = 'HEAD~1 HEAD';\n }\n } catch {\n // git diff 실패시 무시\n }\n }\n\n return diffArgs;\n}","import fs from 'fs';\n\nimport { codingConventionRulesPath, namingRulesPath, rulesPath } from \"./helper\";\n// gemini 실행 및 결과 캡처\nconst args = process.argv.slice(2);\n\n/**\n * @description\n * Google AI Studio / Vertex AI에서 제공하는 추상적 모델 식별자 (Alias) 목록입니다. 이들은 특정 버전에 고정되지 않고, \n * 구글이 최신이라고 판단하는 모델로 자동 연결됩니다.\n * 1. Pro 계열 (고성능, 밸런스)\n * gemini-pro: 현재 기준 가장 안정적인 최신 Pro 모델 (보통 1.0 Pro 또는 1.5 Pro 중 설정된 기본값)\n * 2. Flash 계열 (빠른 속도, 가성비)\n * gemini-flash: 현재 기준 가장 최신 Flash 모델 (보통 1.5 Flash)\n * 3. Experimental (실험적 기능, 최신 기술)\n * gemini-exp: 가장 실험적인 최신 모델 (가변적)\n * gemini-flash-thinking-exp: 최신의 \"Thinking\" 모델 (사고력 강화)\n * 주의사항\n * gemini-ultra (가장 강력한 모델)는 현재 CLI에서 바로 접근 가능한 공개 Alias가 제한적일 수 있습니다. (주로 pro와 flash 위주로 제공)\n * 추상적인 이름(gemini-pro)을 쓰면 구글 마음대로 모델이 업데이트될 수 있어서, \n * 운영 환경에서는 gemini-1.5-pro-001 처럼 고정된 버전을 쓰는 것이 안전하지만, 개발/테스트용으로는 위 Alias들이 편리합니다.\n */\nexport const createCommand = (tempDiffPath: string, reviewFormPath: string) => {\n\n let modelOption = '';\n\n if (args.includes('--review')) {\n // 안정적인 고성능 모델\n // 긴 컨텍스트 처리에 강점\n modelOption = '--model pro';\n } else if (args.includes('--flash')) {\n // 속도 우선\n // 오타 수정, 간단한 리뷰에 적합\n modelOption = '--model flash';\n } else {\n // 사용자 직접 지정\n const modelIndex = args.indexOf('--model');\n // args[modelIndex + 1] 에는 사용자가 지정한 모델명이 들어갑니다.\n // 예: gemini-pro, gemini-1.5-pro-latest, gemini-1.5-flash, gemini-2.0-flash-exp 등\n if (modelIndex !== -1 && args[modelIndex + 1]) {\n console.warn('⚠️ 지정한 모델이 없는 경우, 에러가 발생하니 주의하세요.')\n modelOption = `--model ${args[modelIndex + 1]}`;\n } else {\n console.warn('⚠️ 모델이 지정되지 않았습니다. 기본 모델인 gemini-flash를 사용합니다.')\n modelOption = '--model flash';\n }\n }\n\n // 존재하지 않는 파일은 제외하여 명령어 생성\n const rules = [\n { path: rulesPath, display: '룰셋' },\n { path: namingRulesPath, display: '네이밍 규칙' },\n { path: codingConventionRulesPath, display: '코딩 컨벤션' }\n ];\n\n const validRules = rules\n .filter(rule => fs.existsSync(rule.path))\n .map(rule => `@${rule.path}`)\n .join(', ');\n\n // gemini 실행 및 결과 캡처\n // 주의: gemini CLI가 non-interactive 모드로 실행되려면 프롬프트 전달 방식이 중요합니다.\n // 보통 \"query\" 형태로 전달하면 동작하지만, 확실히 하기 위해 필요한 경우 -p 옵션 사용 고려\n const command = `gemini ${modelOption} -p \"다음 규칙들을 참고해서(${validRules}) 이 diff(@${tempDiffPath})를 리뷰해줘. 리뷰양식은 @${reviewFormPath} 에 맞춰서 작성해줘. \"`;\n\n // test mode\n if (args.includes('--test')) {\n const safeCommand = command.replace(/\"/g, '\\\\\"');\n\n return `echo \"[TEST MODE] Gemini 명령어가 실행되지 않았습니다.\\n\\n생성될 명령어 미리보기:\\n${safeCommand}\"`;\n }\n\n return command;\n}","#!/usr/bin/env node\nimport { execSync } from 'child_process';\nimport fs from 'fs';\n\nimport { checkGeminiCliInstalled } from '../common/installation-gemini';\n\nimport { createCommand } from './commander';\nimport {\n createReportDirectory,\n deleteTempDiff,\n getGitDiffFilter,\n getNextFilePath,\n getNowString,\n getDiffArgs,\n openReport,\n REPORT_DIR,\n reviewFormPath,\n tempDiffPath\n} from './helper';\n// gemini 실행 및 결과 캡처\nconst args = process.argv.slice(2);\nconst isTest = args.includes('--test');\n\n// gemini-cli 설치 확인 및 설치\ncheckGeminiCliInstalled();\n\ntry {\n console.log('🚀 AI Code Review를 시작합니다...');\n\n const nowStr = getNowString();\n\n // 리뷰 결과 폴더 생성\n createReportDirectory();\n\n // diff 가져오기\n const diffArgs = getDiffArgs();\n let diff = '';\n const { includeParams, excludeParams } = getGitDiffFilter();\n\n try {\n diff = execSync(`git diff ${diffArgs} -- ${includeParams} ${excludeParams}`).toString();\n } catch {\n // ignore\n }\n\n if (!diff.trim() && !isTest) {\n console.log('ℹ️ 리뷰할 변경 사항이 없습니다 (Unstaged Empty & HEAD Empty).');\n // 임시 파일 삭제\n deleteTempDiff();\n process.exit(0);\n }\n\n\n fs.writeFileSync(tempDiffPath, diff);\n\n // diff 파일 저장 (.review-report 안으로 복사)\n const savedDiffPath = getNextFilePath(REPORT_DIR, `${nowStr}-diff`, '.txt');\n fs.copyFileSync(tempDiffPath, savedDiffPath);\n\n // 명령어 생성\n const command = createCommand(tempDiffPath, reviewFormPath);\n\n // 결과가 길 수 있으므로 buffer를 넉넉하게 잡거나 순차적으로 받음. 여기서는 간단히 toString()\n const result = execSync(command).toString();\n\n // 콘솔 출력\n console.log(result);\n\n // 리뷰 결과 저장\n const savedReportPath = getNextFilePath(REPORT_DIR, nowStr, '.md');\n fs.writeFileSync(savedReportPath, result);\n\n //사용한 명령어도 저장\n fs.appendFileSync(savedReportPath, `\\n\\n## 사용된 명령어\\n\\n${command}`);\n\n console.log(`\\n✅ 리뷰가 완료되었습니다.`);\n console.log(`📄 리포트 저장 위치: ${savedReportPath}`);\n console.log(`diff 저장 위치: ${savedDiffPath}`);\n\n // 브라우저 열기\n openReport(savedReportPath);\n\n // 임시 파일 삭제\n deleteTempDiff();\n\n} catch (error) {\n console.error('❌ 리뷰 도중 오류가 발생했습니다.');\n console.error(error);\n\n // 임시 파일 삭제\n deleteTempDiff();\n process.exit(1);\n}\n\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/common/helper.ts","../../src/pr-review/claude/claude-commander.ts","../../src/pr-review/claude/installation-claude.ts","../../src/pr-review/gemini/gemini-commander.ts","../../src/pr-review/gemini/installation-gemini.ts","../../src/pr-review/review.ts"],"names":["args","tempDiffPath","reviewFormPath","fs","execSync"],"mappings":"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","file":"review.js","sourcesContent":["import { execSync } from 'child_process';\nimport fs from 'fs'\nimport path from 'path';\nimport readline from 'readline';\nimport { fileURLToPath } from 'url';\n\nimport { AIServiceType } from './types';\n\nconst __dirname = path.dirname(fileURLToPath(import.meta.url));\n\n// 설치된 위치에 맞게 review-rules.md 경로를 계산 (dist에서 src로 이동 등 고려)\n// dist/common/helper.js 가 실행되므로 __dirname은 .../dist/common 입니다.\n// 따라서 ../../src/pr-review/rules 로 이동해야 원본 소스의 규칙 파일을 찾을 수 있습니다.\nexport const rulesPath = path.resolve(__dirname, '../../src/pr-review/rules/review-rules.md');\nexport const namingRulesPath = path.resolve(__dirname, '../../src/pr-review/rules/naming-rule.md');\nexport const codingConventionRulesPath = path.resolve(__dirname, '../../src/pr-review/rules/coding-convention.md');\nexport const reviewFormPath = path.resolve(__dirname, '../../src/pr-review/form/review-form.md');\nexport const reviewFormOneByOnePath = path.resolve(__dirname, '../../src/pr-review/form/review-form-one-by-one.md');\nexport const REPORT_DIR = '.review-report';\nexport const tempDiffPath = 'temp_diff.txt';\nexport const AIServices: AIServiceType[] = ['gemini', 'claude', 'codex'];\nexport const ignoreList = [\n 'package.json',\n '*.yml',\n '*.md',\n '*.lock',\n 'dist/',\n 'node_modules/',\n 'assets/',\n 'public/',\n '*.json',\n '*.yaml',\n '.review-report/' // 생성되는 리포트 폴더도 제외\n];\n\n\nexport function getNextFilePath(dir: string, baseName: string, extension: string) {\n let counter = 1;\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const filePath = path.join(dir, `${baseName}-${counter}${extension}`);\n if (!fs.existsSync(filePath)) {\n return filePath;\n }\n counter++;\n }\n}\n\nexport function deleteFile(filePath: string) {\n if (fs.existsSync(filePath)) {\n fs.unlinkSync(filePath);\n }\n}\n\n\n/**\n * 임시파일 삭제\n */\nexport function deleteTempDiff() {\n deleteFile(tempDiffPath);\n}\n\n\n/**\n * 리뷰 결과 폴더 생성\n */\nexport function createReportDirectory() {\n if (!fs.existsSync(REPORT_DIR)) {\n fs.mkdirSync(REPORT_DIR, { recursive: true });\n }\n}\n\n\n/**\n * 현재 시간 문자열 생성\n */\nexport function getNowString() {\n const now = new Date();\n const YYYY = now.getFullYear();\n const MM = String(now.getMonth() + 1).padStart(2, '0');\n const DD = String(now.getDate()).padStart(2, '0');\n const HH = String(now.getHours()).padStart(2, '0');\n const mm = String(now.getMinutes()).padStart(2, '0');\n const ss = String(now.getSeconds()).padStart(2, '0');\n\n return `${YYYY}-${MM}-${DD}_${HH}-${mm}-${ss}`;\n}\n\nexport function getGitDiffFilter() {\n\n // 1. 리뷰 대상 파일 확장자 정의\n const includeExtensions = ['*.ts', '*.tsx', '*.js', '*.jsx'];\n\n // ignoreList 를 import 하여 재사용하여 작성한다.\n const excludePatterns = ignoreList.map(item => `:(exclude)${item}`);\n\n // const excludePatterns = [':(exclude)*.lock', ':(exclude)dist/', ':(exclude)*.md'];\n\n // 2. 변경된 파일 목록 가져오기 (각 패턴을 따옴표로 감싸서 쉘 에러 방지)\n const quote = (pattern: string) => `\"${pattern}\"`;\n const includeParams = includeExtensions.map(quote).join(' ');\n const excludeParams = excludePatterns.map(quote).join(' ');\n\n return { includeParams, excludeParams };\n\n\n}\n\nexport function openReport(reportPath: string) {\n // 브라우저 열기\n try {\n execSync(`open -a \"Google Chrome\" \"${path.resolve(reportPath)}\"`);\n console.log(`🚀 브라우저에서 리포트를 열었습니다.`);\n } catch (e) {\n console.error('⚠️ 브라우저 열기 실패:', e);\n }\n}\n\n\nexport function getDiffArgs() {\n const args = process.argv.slice(2);\n const commitIndex = args.indexOf('--commit');\n const { includeParams, excludeParams } = getGitDiffFilter();\n\n let diffArgs = '';\n\n if (commitIndex !== -1) {\n // 특정 커밋 (및 이전 n개) 리뷰\n const commitHash = args[commitIndex + 1];\n if (!commitHash) {\n console.error('❌ 커밋 해시가 제공되지 않았습니다.');\n process.exit(1);\n }\n\n // n값 확인 (optional)\n const nextArg = args[commitIndex + 2];\n let n = 0;\n if (nextArg && !nextArg.startsWith('--')) {\n n = parseInt(nextArg, 10);\n if (isNaN(n)) {\n n = 0;\n }\n }\n\n console.log(`ℹ️ 커밋 '${commitHash}' ${n > 0 ? ` 포함 총 ${n + 1}개의 커밋` : ''}을 리뷰합니다...`);\n diffArgs = `${commitHash}~${n + 1} ${commitHash}`;\n } else {\n // 기본 모드:\n // 1. Unstaged 변경사항 확인\n try {\n const check = execSync(`git diff --name-only -- ${includeParams} ${excludeParams}`).toString();\n if (!check.trim()) {\n console.log('ℹ️ Unstaged 변경사항이 없습니다. 마지막 커밋(HEAD)을 리뷰합니다...');\n diffArgs = 'HEAD~1 HEAD';\n }\n } catch {\n // git diff 실패시 무시\n }\n }\n\n return diffArgs;\n}\n\n// export const ServiceType = {\n// GEMINI: 'gemini',\n// CLAUDE: 'claude',\n// CODEX: 'codex'\n\n// }\n\n/**\n * AI 서비스 선택\n */\nexport function selectAIService() {\n const args = process.argv.slice(2);\n const serviceIndex = args.indexOf('--service');\n const service = args[serviceIndex + 1];\n if (!service) {\n console.error('❌ 서비스가 선택되지 않았습니다.');\n process.exit(1);\n }\n\n return service;\n}\n\n/**\n * 터미널에서 라디오 버튼 형태로 AI 서비스를 선택합니다.\n */\nexport async function showSelectionAIService(): Promise<AIServiceType> {\n\n let selectedIndex = 0;\n\n // Use readline to handle keypresses\n // 키 입력을 처리하기 위해 readline 인터페이스 사용\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n terminal: true\n });\n\n let firstRender = true;\n\n // Hide cursor\n process.stdout.write('\\u001b[?25l');\n\n const render = () => {\n if (!firstRender) {\n // Move cursor back to the starting line of the selection UI\n // We print (1 question line + services.length lines)\n // 선택 UI의 시작 라인으로 커서 이동 (질문 1줄 + 서비스 목록 N줄)\n readline.moveCursor(process.stdout, 0, -(AIServices.length + 1));\n }\n firstRender = false;\n\n // Clear everything from cursor down to avoid ghosting/overlaps\n // 잔상이나 겹침을 방지하기 위해 커서 위치부터 아래쪽 모두 지움\n readline.clearScreenDown(process.stdout);\n\n process.stdout.write('🤖 AI 서비스를 선택해주세요 (\\u001b[33m↑↓ 방향키\\u001b[0m 이동, \\u001b[33mEnter\\u001b[0m 선택):\\n');\n AIServices.forEach((service, index) => {\n if (index === selectedIndex) {\n process.stdout.write(` \\u001b[36m>\\u001b[0m \\u001b[36m◉\\u001b[0m \\u001b[1m${service}\\u001b[0m\\n`);\n } else {\n process.stdout.write(` ◯ ${service}\\n`);\n }\n });\n };\n\n render();\n\n return new Promise((resolve) => {\n const onData = (data: Buffer) => {\n const key = data.toString();\n if (key === '\\u0003') { // Ctrl+C\n process.stdout.write('\\u001b[?25h'); // Show cursor\n process.exit(0);\n }\n if (key === '\\x1b[A') { // Up arrow\n selectedIndex = (selectedIndex - 1 + AIServices.length) % AIServices.length;\n render();\n } else if (key === '\\x1b[B') { // Down arrow\n selectedIndex = (selectedIndex + 1) % AIServices.length;\n render();\n } else if (key === '\\r' || key === '\\n') { // Enter\n process.stdin.removeListener('data', onData);\n process.stdin.setRawMode(false);\n process.stdin.pause();\n rl.close();\n\n // Show cursor\n process.stdout.write('\\u001b[?25h');\n\n console.log(`\\n✅ \\u001b[32m${AIServices[selectedIndex]}\\u001b[0m 서비스가 선택되었습니다.\\n`);\n const result = AIServices[selectedIndex];\n if (result) {\n resolve(result);\n }\n }\n };\n\n process.stdin.setRawMode(true);\n process.stdin.resume();\n process.stdin.on('data', onData);\n });\n}\n\n","import fs from 'fs';\n\nimport { codingConventionRulesPath, namingRulesPath, rulesPath } from \"../../common/helper\";\n\nconst args = process.argv.slice(2);\n\n/**\n * @description\n * Claude Code CLI를 활용한 코드 리뷰 명령어를 생성합니다.\n * \n * 모델 별칭(Alias):\n * 1. sonnet (기본값, 균형 잡힌 성능) - 일반적인 코드 리뷰에 적합\n * 2. opus (최고 성능) - 복잡한 분석, 긴 컨텍스트 처리에 강점\n * 3. haiku (빠른 속도) - 오타 수정, 간단한 리뷰에 적합\n * \n * Claude CLI 기능 활용:\n * - `-p`: 비대화형 모드(print mode)로 실행하여 결과를 stdout으로 출력\n * - `--append-system-prompt-file`: 룰셋/리뷰양식 파일을 시스템 프롬프트에 추가 (Claude가 \"지침\"으로 인식)\n * - `cat diff | claude`: diff 내용을 stdin으로 파이프하여 \"리뷰 대상\"으로 전달\n */\nexport const createClaudeCommand = (tempDiffPath: string, reviewFormPath: string) => {\n\n let modelOption = '';\n\n if (args.includes('--review')) {\n // 최고 성능 모델 (opus)\n // 복잡한 코드 분석, 긴 컨텍스트 처리에 강점\n modelOption = '--model opus';\n } else if (args.includes('--flash')) {\n // 속도 우선 모델 (haiku)\n // 오타 수정, 간단한 리뷰에 적합\n modelOption = '--model haiku';\n } else {\n // 사용자 직접 지정\n const modelIndex = args.indexOf('--model');\n // args[modelIndex + 1] 에는 사용자가 지정한 모델명이 들어갑니다.\n // 예: sonnet, opus, haiku, claude-sonnet-4-5-20250929 등\n if (modelIndex !== -1 && args[modelIndex + 1]) {\n console.warn('⚠️ 지정한 모델이 없는 경우, 에러가 발생하니 주의하세요.')\n modelOption = `--model ${args[modelIndex + 1]}`;\n } else {\n console.warn('⚠️ 모델이 지정되지 않았습니다. 기본 모델인 sonnet을 사용합니다.')\n modelOption = '--model sonnet';\n }\n }\n\n // 룰셋 파일들을 --append-system-prompt-file 로 시스템 프롬프트에 추가\n // Claude가 \"지침/규칙\"으로 인식하도록 시스템 프롬프트 레벨에 주입\n const rules = [\n { path: rulesPath, display: '룰셋' },\n { path: namingRulesPath, display: '네이밍 규칙' },\n { path: codingConventionRulesPath, display: '코딩 컨벤션' }\n ];\n\n const systemPromptFiles = rules\n .filter(rule => fs.existsSync(rule.path))\n .map(rule => `--append-system-prompt-file ${rule.path}`)\n .join(' ');\n\n // 리뷰 양식도 시스템 프롬프트에 추가 (출력 포맷 지침)\n const reviewFormOption = fs.existsSync(reviewFormPath)\n ? `--append-system-prompt-file ${reviewFormPath}`\n : '';\n\n // Claude CLI 명령어 생성\n // cat으로 diff 내용을 stdin 파이프 → Claude가 \"리뷰 대상 데이터\"로 인식\n // -p: 비대화형 모드로 실행\n const command = `cat ${tempDiffPath} | claude ${modelOption} ${systemPromptFiles} ${reviewFormOption} -p \"위 규칙들을 참고하여 이 diff를 코드리뷰해줘. 리뷰양식에 맞춰서 작성해줘.\"`;\n\n // test mode\n if (args.includes('--test')) {\n const safeCommand = command.replace(/\"/g, '\\\\\"');\n\n return `echo \"[TEST MODE] Claude 명령어가 실행되지 않았습니다.\\n\\n생성될 명령어 미리보기:\\n${safeCommand}\"`;\n }\n\n return command;\n}","import { execSync } from \"child_process\";\n\n// claude-cli 설치 확인 및 설치\nexport function checkClaudeCliInstalled() {\n try {\n execSync('claude --version', { stdio: 'ignore' });\n } catch {\n console.log('ℹ️ claude-cli가 설치되어 있지 않습니다. 설치를 진행합니다... npm install -g @anthropic-ai/claude-code');\n try {\n execSync('npm install -g @anthropic-ai/claude-code', { stdio: 'inherit' });\n console.log('✅ claude-cli 설치가 완료되었습니다.');\n console.log('⚠️ claude-cli 사용을 위해 인증이 필요합니다.');\n console.log(' 터미널에서 \"claude\" 를 입력하여 브라우저 로그인을 완료한 후, 다시 시도해주세요.');\n process.exit(1);\n } catch (installError) {\n console.error('❌ claude-cli 설치 중 오류가 발생했습니다. 권한 문제일 수 있습니다 (sudo 필요).');\n console.error(installError);\n process.exit(1);\n }\n }\n}","import fs from 'fs';\n\nimport { codingConventionRulesPath, namingRulesPath, rulesPath } from \"../../common/helper\";\nimport { AIServiceType } from '../../common/types';\n// gemini 실행 및 결과 캡처\nconst args = process.argv.slice(2);\n\n/**\n * @description\n * Google AI Studio / Vertex AI에서 제공하는 추상적 모델 식별자 (Alias) 목록입니다. 이들은 특정 버전에 고정되지 않고, \n * 구글이 최신이라고 판단하는 모델로 자동 연결됩니다.\n * 1. Pro 계열 (고성능, 밸런스)\n * gemini-pro: 현재 기준 가장 안정적인 최신 Pro 모델 (보통 1.0 Pro 또는 1.5 Pro 중 설정된 기본값)\n * 2. Flash 계열 (빠른 속도, 가성비)\n * gemini-flash: 현재 기준 가장 최신 Flash 모델 (보통 1.5 Flash)\n * 3. Experimental (실험적 기능, 최신 기술)\n * gemini-exp: 가장 실험적인 최신 모델 (가변적)\n * gemini-flash-thinking-exp: 최신의 \"Thinking\" 모델 (사고력 강화)\n * 주의사항\n * gemini-ultra (가장 강력한 모델)는 현재 CLI에서 바로 접근 가능한 공개 Alias가 제한적일 수 있습니다. (주로 pro와 flash 위주로 제공)\n * 추상적인 이름(gemini-pro)을 쓰면 구글 마음대로 모델이 업데이트될 수 있어서, \n * 운영 환경에서는 gemini-1.5-pro-001 처럼 고정된 버전을 쓰는 것이 안전하지만, 개발/테스트용으로는 위 Alias들이 편리합니다.\n */\nexport const createGeminiCommand = (tempDiffPath: string, reviewFormPath: string) => {\n\n let modelOption = '';\n\n if (args.includes('--review')) {\n // 안정적인 고성능 모델\n // 긴 컨텍스트 처리에 강점\n modelOption = '--model pro';\n } else if (args.includes('--flash')) {\n // 속도 우선\n // 오타 수정, 간단한 리뷰에 적합\n modelOption = '--model flash';\n } else {\n // 사용자 직접 지정\n const modelIndex = args.indexOf('--model');\n // args[modelIndex + 1] 에는 사용자가 지정한 모델명이 들어갑니다.\n // 예: gemini-pro, gemini-1.5-pro-latest, gemini-1.5-flash, gemini-2.0-flash-exp 등\n if (modelIndex !== -1 && args[modelIndex + 1]) {\n console.warn('⚠️ 지정한 모델이 없는 경우, 에러가 발생하니 주의하세요.')\n modelOption = `--model ${args[modelIndex + 1]}`;\n } else {\n console.warn('⚠️ 모델이 지정되지 않았습니다. 기본 모델인 gemini-flash를 사용합니다.')\n modelOption = '--model flash';\n }\n }\n\n // 존재하지 않는 파일은 제외하여 명령어 생성\n const rules = [\n { path: rulesPath, display: '룰셋' },\n { path: namingRulesPath, display: '네이밍 규칙' },\n { path: codingConventionRulesPath, display: '코딩 컨벤션' }\n ];\n\n const validRules = rules\n .filter(rule => fs.existsSync(rule.path))\n .map(rule => `@${rule.path}`)\n .join(', ');\n\n // gemini 실행 및 결과 캡처\n // 주의: gemini CLI가 non-interactive 모드로 실행되려면 프롬프트 전달 방식이 중요합니다.\n // 보통 \"query\" 형태로 전달하면 동작하지만, 확실히 하기 위해 필요한 경우 -p 옵션 사용 고려\n const command = `gemini ${modelOption} -p \"다음 규칙들을 참고해서(${validRules}) 이 diff(@${tempDiffPath})를 리뷰해줘. 리뷰양식은 @${reviewFormPath} 에 맞춰서 작성해줘. \"`;\n\n // test mode\n if (args.includes('--test')) {\n const safeCommand = command.replace(/\"/g, '\\\\\"');\n\n return `echo \"[TEST MODE] Gemini 명령어가 실행되지 않았습니다.\\n\\n생성될 명령어 미리보기:\\n${safeCommand}\"`;\n }\n\n return command;\n}","import { execSync } from \"child_process\";\n\n// gemini-cli 설치 확인 및 설치\nexport function checkGeminiCliInstalled() {\n try {\n execSync('gemini --version', { stdio: 'ignore' });\n } catch {\n console.log('ℹ️ gemini-cli가 설치되어 있지 않습니다. 설치를 진행합니다... npm install -g @google/gemini-cli');\n try {\n execSync('npm install -g @google/gemini-cli', { stdio: 'inherit' });\n console.log('✅ gemini-cli 설치가 완료되었습니다.');\n console.log('⚠️ Gemini API 사용을 위해 인증이 필요합니다.');\n console.log(' 터미널에서 \"gemini\" 를 입력하여 브라우저 로그인을 완료한 후, 다시 시도해주세요.');\n process.exit(1);\n } catch (installError) {\n console.error('❌ gemini-cli 설치 중 오류가 발생했습니다. 권한 문제일 수 있습니다 (sudo 필요).');\n console.error(installError);\n process.exit(1);\n }\n }\n}","#!/usr/bin/env node\nimport { execSync } from 'child_process';\nimport fs from 'fs';\n\nimport {\n createReportDirectory,\n deleteTempDiff,\n getGitDiffFilter,\n getNextFilePath,\n getNowString,\n getDiffArgs,\n openReport,\n REPORT_DIR,\n reviewFormPath,\n tempDiffPath,\n showSelectionAIService\n} from '../common/helper';\n\nimport { createClaudeCommand } from './claude/claude-commander';\nimport { checkClaudeCliInstalled } from './claude/installation-claude';\nimport { createGeminiCommand } from './gemini/gemini-commander';\nimport { checkGeminiCliInstalled } from './gemini/installation-gemini';\n\n\nasync function main() {\n\n\n // gemini 실행 및 결과 캡처\n const args = process.argv.slice(2);\n const isTest = args.includes('--test');\n\n // AI 서비스 선택\n const service = await showSelectionAIService();\n\n\n switch (service) {\n case 'gemini':\n // gemini-cli 설치 확인 및 설치\n checkGeminiCliInstalled();\n break;\n case 'claude':\n // claude-cli 설치 확인 및 설치\n checkClaudeCliInstalled();\n break;\n case 'codex':\n /**\n * @todo codex-cli 설치 확인 및 설치\n */\n break;\n }\n\n\n\n try {\n console.log('🚀 AI Code Review를 시작합니다...');\n\n const nowStr = getNowString();\n\n // 리뷰 결과 폴더 생성\n createReportDirectory();\n\n // diff 가져오기\n const diffArgs = getDiffArgs();\n let diff = '';\n const { includeParams, excludeParams } = getGitDiffFilter();\n\n try {\n diff = execSync(`git diff ${diffArgs} -- ${includeParams} ${excludeParams}`).toString();\n } catch {\n // ignore\n }\n\n if (!diff.trim() && !isTest) {\n console.log('ℹ️ 리뷰할 변경 사항이 없습니다 (Unstaged Empty & HEAD Empty).');\n // 임시 파일 삭제\n deleteTempDiff();\n process.exit(0);\n }\n\n\n fs.writeFileSync(tempDiffPath, diff);\n\n // diff 파일 저장 (.review-report 안으로 복사)\n const savedDiffPath = getNextFilePath(REPORT_DIR, `${nowStr}-diff`, '.txt');\n fs.copyFileSync(tempDiffPath, savedDiffPath);\n\n // 명령어 생성\n let command = '';\n\n switch (service) {\n case 'gemini':\n // gemini-cli 에 맞게 프롬프트 명령어 생성\n command = createGeminiCommand(tempDiffPath, reviewFormPath);\n break;\n case 'claude':\n // claude-cli 에 맞게 프롬프트 명령어 생성\n command = createClaudeCommand(tempDiffPath, reviewFormPath);\n break;\n case 'codex':\n /**\n * @todo codex-cli 에 맞게 프롬프트 명령어 생성\n */\n break;\n }\n\n // 결과가 길 수 있으므로 buffer를 넉넉하게 잡거나 순차적으로 받음. 여기서는 간단히 toString()\n const result = execSync(command).toString();\n\n // 콘솔 출력\n console.log(result);\n\n // 리뷰 결과 저장\n const savedReportPath = getNextFilePath(REPORT_DIR, nowStr, '.md');\n fs.writeFileSync(savedReportPath, result);\n\n //사용한 명령어도 저장(디버깅용)\n if (isTest) {\n fs.appendFileSync(savedReportPath, `\\n\\n## 사용된 명령어\\n\\n${command}`);\n }\n\n console.log(`\\n✅ 리뷰가 완료되었습니다.`);\n console.log(`📄 리포트 저장 위치: ${savedReportPath}`);\n console.log(`diff 저장 위치: ${savedDiffPath}`);\n\n // 브라우저 열기\n openReport(savedReportPath);\n\n // 임시 파일 삭제\n deleteTempDiff();\n\n } catch (error) {\n console.error('❌ 리뷰 도중 오류가 발생했습니다.');\n console.error(error);\n\n // 임시 파일 삭제\n deleteTempDiff();\n process.exit(1);\n }\n\n\n}\n\nmain();"]}
|
package/package.json
CHANGED
|
@@ -6,13 +6,13 @@
|
|
|
6
6
|
},
|
|
7
7
|
"files": [
|
|
8
8
|
"dist",
|
|
9
|
-
"src/
|
|
10
|
-
"src/
|
|
11
|
-
"src/
|
|
12
|
-
"src/
|
|
13
|
-
"src/
|
|
9
|
+
"src/common/rules/review-rules.md",
|
|
10
|
+
"src/common/rules/naming-rules.pdf",
|
|
11
|
+
"src/common/rules/coding-convention-rules.pdf",
|
|
12
|
+
"src/common/form/review-form.md",
|
|
13
|
+
"src/common/form/review-form-one-by-one.md"
|
|
14
14
|
],
|
|
15
|
-
"version": "0.
|
|
15
|
+
"version": "0.3.0",
|
|
16
16
|
"private": false,
|
|
17
17
|
"type": "module",
|
|
18
18
|
"author": "",
|
|
@@ -35,9 +35,9 @@
|
|
|
35
35
|
"storybook": "tsup --watch",
|
|
36
36
|
"build": "tsup",
|
|
37
37
|
"release": "pnpm publish",
|
|
38
|
-
"install-gcloud": "tsx src/
|
|
39
|
-
"review:interactive": "tsx src/pr-review/interactive-version/index.ts",
|
|
40
|
-
"review:vertex": "tsx src/pr-review/vertex-version/index.ts",
|
|
38
|
+
"install-gcloud": "tsx src/pr-review/gemini/installation-gcloud.ts",
|
|
39
|
+
"review:interactive": "tsx src/pr-review/gemini/interactive-version/index.ts",
|
|
40
|
+
"review:vertex": "tsx src/pr-review/gemini/vertex-version/index.ts",
|
|
41
41
|
"gcloud:logout": " gcloud auth application-default revoke ",
|
|
42
42
|
"gemini-uninstall": "npm uninstall -g @google/gemini-cli"
|
|
43
43
|
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
## 코드 리뷰 규칙
|
|
2
|
+
|
|
3
|
+
### 언어
|
|
4
|
+
|
|
5
|
+
- 모든 내용은 한국어를 사용할것.
|
|
6
|
+
|
|
7
|
+
### 프로그래밍의 기본베이스 관련
|
|
8
|
+
|
|
9
|
+
- SOLID 원칙을 준수하는지 체크
|
|
10
|
+
- clean architecture 원칙을 준수하는지 체크
|
|
11
|
+
|
|
12
|
+
### 클린아키텍쳐 관련(추후 사용예정, 아직은 적용하지 룰에 적용하지 않습니다.)
|
|
13
|
+
|
|
14
|
+
- [name].tsx 는 API 호출을 담당한다. 핸들러 선언을 담당한다.
|
|
15
|
+
- [name].view.tsx 는 UI 렌더링을 담당한다. 핸들러를 직접 선언하지 않는다. API를 직접 호출하지 않는다.
|
|
16
|
+
|
|
17
|
+
### 타입스크립트 관련
|
|
18
|
+
|
|
19
|
+
- any 타입을 사용하는지 체크
|
|
20
|
+
|
|
21
|
+
### 리액트 컴포넌트 구조 관련
|
|
22
|
+
|
|
23
|
+
- 컴포넌트안에서 css를 인라인으로 직접 선언하는지 체크
|
|
24
|
+
|
|
25
|
+
### 기타 리뷰시, 요구사항
|
|
26
|
+
|
|
27
|
+
- 개발적으로 더 좋은 가이드가 있으면 같이 알려줘.
|
|
28
|
+
|
|
29
|
+
- 답변은 반드시 한국어로 할것.
|
|
30
|
+
|
|
31
|
+
- 확인한 파일목록을 표현할것.
|
|
32
|
+
|
|
33
|
+
- 체크한 파일목록을 보여주고,파일명 옆에 체크리스트를 통과했는지 표시할것
|
|
34
|
+
|
|
35
|
+
- 체크리스트를 통과하지 못한 파일이 있다면, 해당 파일의 어떤 부분이 체크리스트를 통과하지 못했는지 표시할것
|
|
36
|
+
|
|
37
|
+
### ignore 파일들
|
|
38
|
+
|
|
39
|
+
- package.json
|
|
40
|
+
|
|
41
|
+
- \*.yml
|
|
42
|
+
|
|
43
|
+
- \*.md
|
|
44
|
+
|
|
45
|
+
- \*.lock
|
|
46
|
+
|
|
47
|
+
- dist폴더내 파일들
|
|
48
|
+
|
|
49
|
+
- node_modules 폴더내 파일들
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/common/installation-gcloud.ts"],"names":["execSync"],"mappings":";;;;;;AASO,IAAM,oBAAoB,MAAM;AACrC,EAAI,IAAA;AACF,IAAAA,sBAAA,CAAS,kBAAkB,CAAA;AAE3B,IAAO,OAAA,IAAA;AAAA,WACA,KAAO,EAAA;AACd,IAAO,OAAA,KAAA;AAAA;AAEX;AAOO,IAAM,gBAAgB,MAAM;AACjC,EAAA,IAAI,mBAAqB,EAAA;AACvB,IAAA,OAAA,CAAQ,IAAI,uCAAuC,CAAA;AAEnD,IAAA;AAAA;AAEF,EAAA,MAAM,MAAM,OAAQ,CAAA,IAAA;AACpB,EAAA,MAAM,KAAK,OAAQ,CAAA,QAAA;AACnB,EAAA,IAAI,OAAO,OAAS,EAAA;AAClB,IAAM,MAAA,IAAI,MAAM,yBAAyB,CAAA;AAAA;AAE3C,EAAI,IAAA,GAAA,KAAQ,KAAS,IAAA,GAAA,KAAQ,OAAS,EAAA;AACpC,IAAM,MAAA,IAAI,MAAM,kCAAkC,CAAA;AAAA;AAGpD,EAAM,MAAA,QAAA,GAAW,yCAAyC,GAAG,CAAA,OAAA,CAAA;AAC7D,EAAM,MAAA,WAAA,GAAc,QAAQ,GAAI,EAAA;AAGhC,EAAQ,OAAA,CAAA,GAAA,CAAI,CAAe,4CAAA,EAAA,QAAQ,CAAE,CAAA,CAAA;AACrC,EAASA,sBAAA,CAAA,CAAA,SAAA,EAAY,QAAQ,CAAI,CAAA,EAAA,EAAE,KAAK,WAAa,EAAA,KAAA,EAAO,WAAW,CAAA;AAGvE,EAAA,OAAA,CAAQ,IAAI,6CAAuB,CAAA;AAGnC,EAAAA,sBAAA,CAAS,iCAAiC,EAAE,GAAA,EAAK,WAAa,EAAA,KAAA,EAAO,WAAW,CAAA;AAWlF;AAGA,IAAI,QAAQ,IAAK,CAAA,CAAC,MAAM,yQAAY,CAAI,SAAS,OAAQ,CAAA,IAAA,CAAK,CAAC,CAAC,KAAK,OAAQ,CAAA,IAAA,CAAK,CAAC,CAAE,CAAA,QAAA,CAAS,UAAU,CAAI,CAAA,EAAA;AAC1G,EAAc,aAAA,EAAA;AAChB","file":"installation-gcloud.cjs","sourcesContent":["//tar -xf google-cloud-cli-linux-x86_64.tar.gz\n//./google-cloud-sdk/install.sh\n//gcloud init\n//gcloud config set accessibility/screen_reader true\n//https://docs.cloud.google.com/sdk/docs/install-sdk\n\nimport { execSync } from 'child_process';\n\n//테스트\nexport const isInstalledGcloud = () => {\n try {\n execSync('gcloud --version');\n\n return true;\n } catch (error) {\n return false;\n }\n};\n\n/**\n * 현재 linux cpu의 종류에 따라 resource 폴더안에 파일2개중에서, 선택하여 압축을 풀고, install.sh를 실행한다.\n * src/resource/google-cloud-cli-linux-arm.tar.gz\n * src/resource/google-cloud-cli-linux-x64.tar.gz\n */\nexport const installGcloud = () => {\n if (isInstalledGcloud()) {\n console.log('Google Cloud SDK is already installed');\n\n return;\n }\n const cpu = process.arch;\n const os = process.platform;\n if (os !== 'linux') {\n throw new Error('Only Linux is supported');\n }\n if (cpu !== 'x64' && cpu !== 'arm64') {\n throw new Error('Only x64 and arm64 are supported');\n }\n\n const filePath = `./src/resource/google-cloud-cli-linux-${cpu}.tar.gz`;\n const packageRoot = process.cwd();\n\n // 압축 풀기\n console.log(`📦 압축 해제 중: ${filePath}`);\n execSync(`tar -xvf ${filePath}`, { cwd: packageRoot, stdio: 'inherit' });\n\n // install.sh 실행\n console.log('🚀 install.sh 실행 중...');\n // execSync('./google-cloud-sdk/install.sh --quiet', { cwd: packageRoot, stdio: 'inherit' });\n\n execSync('./google-cloud-sdk/install.sh', { cwd: packageRoot, stdio: 'inherit' });\n // gcloud init (대화형이므로 사용자 주의 필요)\n // console.log('⚠️ gcloud init을 실행합니다. 대화형 설정이 필요할 수 있습니다.');\n // execSync('gcloud init', { cwd: packageRoot, stdio: 'inherit' }); // 실제 환경에서 차단될 수 있으므로 주석 처리하거나 주의\n\n // gcloud config set accessibility/screen_reader true\n // console.log('⚙️ gcloud 설정 중...');\n // const gcloudBin = './google-cloud-sdk/bin/gcloud';\n // execSync(`${gcloudBin} config set accessibility/screen_reader true`, { cwd: packageRoot, stdio: 'inherit' });\n\n // console.log('✅ Google Cloud SDK 설치 완료');\n};\n\n// 직접 실행 시 함수 호출\nif (process.argv[1] && (import.meta.url.endsWith(process.argv[1]) || process.argv[1].endsWith('index.ts'))) {\n installGcloud();\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/common/installation-gcloud.ts"],"names":[],"mappings":";;;AASO,IAAM,oBAAoB,MAAM;AACrC,EAAI,IAAA;AACF,IAAA,QAAA,CAAS,kBAAkB,CAAA;AAE3B,IAAO,OAAA,IAAA;AAAA,WACA,KAAO,EAAA;AACd,IAAO,OAAA,KAAA;AAAA;AAEX;AAOO,IAAM,gBAAgB,MAAM;AACjC,EAAA,IAAI,mBAAqB,EAAA;AACvB,IAAA,OAAA,CAAQ,IAAI,uCAAuC,CAAA;AAEnD,IAAA;AAAA;AAEF,EAAA,MAAM,MAAM,OAAQ,CAAA,IAAA;AACpB,EAAA,MAAM,KAAK,OAAQ,CAAA,QAAA;AACnB,EAAA,IAAI,OAAO,OAAS,EAAA;AAClB,IAAM,MAAA,IAAI,MAAM,yBAAyB,CAAA;AAAA;AAE3C,EAAI,IAAA,GAAA,KAAQ,KAAS,IAAA,GAAA,KAAQ,OAAS,EAAA;AACpC,IAAM,MAAA,IAAI,MAAM,kCAAkC,CAAA;AAAA;AAGpD,EAAM,MAAA,QAAA,GAAW,yCAAyC,GAAG,CAAA,OAAA,CAAA;AAC7D,EAAM,MAAA,WAAA,GAAc,QAAQ,GAAI,EAAA;AAGhC,EAAQ,OAAA,CAAA,GAAA,CAAI,CAAe,4CAAA,EAAA,QAAQ,CAAE,CAAA,CAAA;AACrC,EAAS,QAAA,CAAA,CAAA,SAAA,EAAY,QAAQ,CAAI,CAAA,EAAA,EAAE,KAAK,WAAa,EAAA,KAAA,EAAO,WAAW,CAAA;AAGvE,EAAA,OAAA,CAAQ,IAAI,6CAAuB,CAAA;AAGnC,EAAA,QAAA,CAAS,iCAAiC,EAAE,GAAA,EAAK,WAAa,EAAA,KAAA,EAAO,WAAW,CAAA;AAWlF;AAGA,IAAI,QAAQ,IAAK,CAAA,CAAC,MAAM,MAAY,CAAA,IAAA,CAAA,GAAA,CAAI,SAAS,OAAQ,CAAA,IAAA,CAAK,CAAC,CAAC,KAAK,OAAQ,CAAA,IAAA,CAAK,CAAC,CAAE,CAAA,QAAA,CAAS,UAAU,CAAI,CAAA,EAAA;AAC1G,EAAc,aAAA,EAAA;AAChB","file":"installation-gcloud.js","sourcesContent":["//tar -xf google-cloud-cli-linux-x86_64.tar.gz\n//./google-cloud-sdk/install.sh\n//gcloud init\n//gcloud config set accessibility/screen_reader true\n//https://docs.cloud.google.com/sdk/docs/install-sdk\n\nimport { execSync } from 'child_process';\n\n//테스트\nexport const isInstalledGcloud = () => {\n try {\n execSync('gcloud --version');\n\n return true;\n } catch (error) {\n return false;\n }\n};\n\n/**\n * 현재 linux cpu의 종류에 따라 resource 폴더안에 파일2개중에서, 선택하여 압축을 풀고, install.sh를 실행한다.\n * src/resource/google-cloud-cli-linux-arm.tar.gz\n * src/resource/google-cloud-cli-linux-x64.tar.gz\n */\nexport const installGcloud = () => {\n if (isInstalledGcloud()) {\n console.log('Google Cloud SDK is already installed');\n\n return;\n }\n const cpu = process.arch;\n const os = process.platform;\n if (os !== 'linux') {\n throw new Error('Only Linux is supported');\n }\n if (cpu !== 'x64' && cpu !== 'arm64') {\n throw new Error('Only x64 and arm64 are supported');\n }\n\n const filePath = `./src/resource/google-cloud-cli-linux-${cpu}.tar.gz`;\n const packageRoot = process.cwd();\n\n // 압축 풀기\n console.log(`📦 압축 해제 중: ${filePath}`);\n execSync(`tar -xvf ${filePath}`, { cwd: packageRoot, stdio: 'inherit' });\n\n // install.sh 실행\n console.log('🚀 install.sh 실행 중...');\n // execSync('./google-cloud-sdk/install.sh --quiet', { cwd: packageRoot, stdio: 'inherit' });\n\n execSync('./google-cloud-sdk/install.sh', { cwd: packageRoot, stdio: 'inherit' });\n // gcloud init (대화형이므로 사용자 주의 필요)\n // console.log('⚠️ gcloud init을 실행합니다. 대화형 설정이 필요할 수 있습니다.');\n // execSync('gcloud init', { cwd: packageRoot, stdio: 'inherit' }); // 실제 환경에서 차단될 수 있으므로 주석 처리하거나 주의\n\n // gcloud config set accessibility/screen_reader true\n // console.log('⚙️ gcloud 설정 중...');\n // const gcloudBin = './google-cloud-sdk/bin/gcloud';\n // execSync(`${gcloudBin} config set accessibility/screen_reader true`, { cwd: packageRoot, stdio: 'inherit' });\n\n // console.log('✅ Google Cloud SDK 설치 완료');\n};\n\n// 직접 실행 시 함수 호출\nif (process.argv[1] && (import.meta.url.endsWith(process.argv[1]) || process.argv[1].endsWith('index.ts'))) {\n installGcloud();\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/common/installation-gemini.ts"],"names":["execSync"],"mappings":";;;;;AAGO,SAAS,uBAA0B,GAAA;AACtC,EAAI,IAAA;AACA,IAAAA,sBAAA,CAAS,kBAAoB,EAAA,EAAE,KAAO,EAAA,QAAA,EAAU,CAAA;AAAA,GAC5C,CAAA,MAAA;AACJ,IAAA,OAAA,CAAQ,IAAI,sLAA6E,CAAA;AACzF,IAAI,IAAA;AACA,MAAAA,sBAAA,CAAS,mCAAqC,EAAA,EAAE,KAAO,EAAA,SAAA,EAAW,CAAA;AAClE,MAAA,OAAA,CAAQ,IAAI,kFAA2B,CAAA;AACvC,MAAA,OAAA,CAAQ,IAAI,6GAAkC,CAAA;AAC9C,MAAA,OAAA,CAAQ,IAAI,4MAAsD,CAAA;AAClE,MAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,aACT,YAAc,EAAA;AACnB,MAAA,OAAA,CAAQ,MAAM,qLAAwD,CAAA;AACtE,MAAA,OAAA,CAAQ,MAAM,YAAY,CAAA;AAC1B,MAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA;AAClB;AAER","file":"installation-gemini.cjs","sourcesContent":["import { execSync } from \"child_process\";\n\n// gemini-cli 설치 확인 및 설치\nexport function checkGeminiCliInstalled() {\n try {\n execSync('gemini --version', { stdio: 'ignore' });\n } catch {\n console.log('ℹ️ gemini-cli가 설치되어 있지 않습니다. 설치를 진행합니다... npm install -g @google/gemini-cli');\n try {\n execSync('npm install -g @google/gemini-cli', { stdio: 'inherit' });\n console.log('✅ gemini-cli 설치가 완료되었습니다.');\n console.log('⚠️ Gemini API 사용을 위해 인증이 필요합니다.');\n console.log(' 터미널에서 \"gemini\" 를 입력하여 브라우저 로그인을 완료한 후, 다시 시도해주세요.');\n process.exit(1);\n } catch (installError) {\n console.error('❌ gemini-cli 설치 중 오류가 발생했습니다. 권한 문제일 수 있습니다 (sudo 필요).');\n console.error(installError);\n process.exit(1);\n }\n }\n}"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/common/installation-gemini.ts"],"names":[],"mappings":";;;AAGO,SAAS,uBAA0B,GAAA;AACtC,EAAI,IAAA;AACA,IAAA,QAAA,CAAS,kBAAoB,EAAA,EAAE,KAAO,EAAA,QAAA,EAAU,CAAA;AAAA,GAC5C,CAAA,MAAA;AACJ,IAAA,OAAA,CAAQ,IAAI,sLAA6E,CAAA;AACzF,IAAI,IAAA;AACA,MAAA,QAAA,CAAS,mCAAqC,EAAA,EAAE,KAAO,EAAA,SAAA,EAAW,CAAA;AAClE,MAAA,OAAA,CAAQ,IAAI,kFAA2B,CAAA;AACvC,MAAA,OAAA,CAAQ,IAAI,6GAAkC,CAAA;AAC9C,MAAA,OAAA,CAAQ,IAAI,4MAAsD,CAAA;AAClE,MAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,aACT,YAAc,EAAA;AACnB,MAAA,OAAA,CAAQ,MAAM,qLAAwD,CAAA;AACtE,MAAA,OAAA,CAAQ,MAAM,YAAY,CAAA;AAC1B,MAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA;AAClB;AAER","file":"installation-gemini.js","sourcesContent":["import { execSync } from \"child_process\";\n\n// gemini-cli 설치 확인 및 설치\nexport function checkGeminiCliInstalled() {\n try {\n execSync('gemini --version', { stdio: 'ignore' });\n } catch {\n console.log('ℹ️ gemini-cli가 설치되어 있지 않습니다. 설치를 진행합니다... npm install -g @google/gemini-cli');\n try {\n execSync('npm install -g @google/gemini-cli', { stdio: 'inherit' });\n console.log('✅ gemini-cli 설치가 완료되었습니다.');\n console.log('⚠️ Gemini API 사용을 위해 인증이 필요합니다.');\n console.log(' 터미널에서 \"gemini\" 를 입력하여 브라우저 로그인을 완료한 후, 다시 시도해주세요.');\n process.exit(1);\n } catch (installError) {\n console.error('❌ gemini-cli 설치 중 오류가 발생했습니다. 권한 문제일 수 있습니다 (sudo 필요).');\n console.error(installError);\n process.exit(1);\n }\n }\n}"]}
|