cciwon-code-review-cli 2.0.9 → 2.1.1

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.
Files changed (113) hide show
  1. package/lib/api-client.js +34 -0
  2. package/lib/chat-mode.js +118 -63
  3. package/package.json +1 -1
  4. package/.ipynb_checkpoints/README-checkpoint.md +0 -233
  5. package/.ipynb_checkpoints/package-checkpoint.json +0 -36
  6. package/unsloth_compiled_cache/.locks/.lock.AqlmLoraLinear_peft_forward.py +0 -0
  7. package/unsloth_compiled_cache/.locks/.lock.AwqLoraLinear_peft_forward.py +0 -0
  8. package/unsloth_compiled_cache/.locks/.lock.BatchNorm1d.py +0 -0
  9. package/unsloth_compiled_cache/.locks/.lock.BatchNorm2d.py +0 -0
  10. package/unsloth_compiled_cache/.locks/.lock.BatchNorm3d.py +0 -0
  11. package/unsloth_compiled_cache/.locks/.lock.Conv1d.py +0 -0
  12. package/unsloth_compiled_cache/.locks/.lock.Conv2d.py +0 -0
  13. package/unsloth_compiled_cache/.locks/.lock.Conv3d.py +0 -0
  14. package/unsloth_compiled_cache/.locks/.lock.ConvTranspose1d.py +0 -0
  15. package/unsloth_compiled_cache/.locks/.lock.ConvTranspose2d.py +0 -0
  16. package/unsloth_compiled_cache/.locks/.lock.ConvTranspose3d.py +0 -0
  17. package/unsloth_compiled_cache/.locks/.lock.GPTQLoraLinear_peft_forward.py +0 -0
  18. package/unsloth_compiled_cache/.locks/.lock.GroupNorm.py +0 -0
  19. package/unsloth_compiled_cache/.locks/.lock.LayerNorm.py +0 -0
  20. package/unsloth_compiled_cache/.locks/.lock.Linear4bit_peft_forward.py +0 -0
  21. package/unsloth_compiled_cache/.locks/.lock.Linear8bitLt_peft_forward.py +0 -0
  22. package/unsloth_compiled_cache/.locks/.lock.Linear_peft_forward.py +0 -0
  23. package/unsloth_compiled_cache/.locks/.lock.LoraParallelLinear_peft_forward.py +0 -0
  24. package/unsloth_compiled_cache/.locks/.lock.RMSNorm.py +0 -0
  25. package/unsloth_compiled_cache/.locks/.lock.UnslothBCOTrainer.py +0 -0
  26. package/unsloth_compiled_cache/.locks/.lock.UnslothCPOTrainer.py +0 -0
  27. package/unsloth_compiled_cache/.locks/.lock.UnslothDPOTrainer.py +0 -0
  28. package/unsloth_compiled_cache/.locks/.lock.UnslothGKDTrainer.py +0 -0
  29. package/unsloth_compiled_cache/.locks/.lock.UnslothGRPOTrainer.py +0 -0
  30. package/unsloth_compiled_cache/.locks/.lock.UnslothKTOTrainer.py +0 -0
  31. package/unsloth_compiled_cache/.locks/.lock.UnslothNashMDTrainer.py +0 -0
  32. package/unsloth_compiled_cache/.locks/.lock.UnslothORPOTrainer.py +0 -0
  33. package/unsloth_compiled_cache/.locks/.lock.UnslothOnlineDPOTrainer.py +0 -0
  34. package/unsloth_compiled_cache/.locks/.lock.UnslothPPOTrainer.py +0 -0
  35. package/unsloth_compiled_cache/.locks/.lock.UnslothPRMTrainer.py +0 -0
  36. package/unsloth_compiled_cache/.locks/.lock.UnslothRLOOTrainer.py +0 -0
  37. package/unsloth_compiled_cache/.locks/.lock.UnslothRewardTrainer.py +0 -0
  38. package/unsloth_compiled_cache/.locks/.lock.UnslothSFTTrainer.py +0 -0
  39. package/unsloth_compiled_cache/.locks/.lock.UnslothXPOTrainer.py +0 -0
  40. package/unsloth_compiled_cache/.locks/.lock.unsloth_compiled_module_qwen3_moe.py +0 -0
  41. package/unsloth_compiled_cache/.locks/.lock.unsloth_compiled_module_siglip.py +0 -0
  42. package/unsloth_compiled_cache/AqlmLoraLinear_peft_forward.py +0 -88
  43. package/unsloth_compiled_cache/AwqLoraLinear_peft_forward.py +0 -87
  44. package/unsloth_compiled_cache/BatchNorm1d.py +0 -117
  45. package/unsloth_compiled_cache/BatchNorm2d.py +0 -117
  46. package/unsloth_compiled_cache/BatchNorm3d.py +0 -117
  47. package/unsloth_compiled_cache/Conv1d.py +0 -70
  48. package/unsloth_compiled_cache/Conv2d.py +0 -70
  49. package/unsloth_compiled_cache/Conv3d.py +0 -70
  50. package/unsloth_compiled_cache/ConvTranspose1d.py +0 -97
  51. package/unsloth_compiled_cache/ConvTranspose2d.py +0 -106
  52. package/unsloth_compiled_cache/ConvTranspose3d.py +0 -98
  53. package/unsloth_compiled_cache/GPTQLoraLinear_peft_forward.py +0 -95
  54. package/unsloth_compiled_cache/GroupNorm.py +0 -70
  55. package/unsloth_compiled_cache/LayerNorm.py +0 -72
  56. package/unsloth_compiled_cache/Linear4bit_peft_forward.py +0 -115
  57. package/unsloth_compiled_cache/Linear8bitLt_peft_forward.py +0 -113
  58. package/unsloth_compiled_cache/Linear_peft_forward.py +0 -104
  59. package/unsloth_compiled_cache/LoraParallelLinear_peft_forward.py +0 -91
  60. package/unsloth_compiled_cache/RMSNorm.py +0 -73
  61. package/unsloth_compiled_cache/UnslothBCOTrainer.py +0 -2026
  62. package/unsloth_compiled_cache/UnslothCPOTrainer.py +0 -1806
  63. package/unsloth_compiled_cache/UnslothDPOTrainer.py +0 -2750
  64. package/unsloth_compiled_cache/UnslothGKDTrainer.py +0 -1157
  65. package/unsloth_compiled_cache/UnslothGRPOTrainer.py +0 -3607
  66. package/unsloth_compiled_cache/UnslothKTOTrainer.py +0 -2220
  67. package/unsloth_compiled_cache/UnslothNashMDTrainer.py +0 -1210
  68. package/unsloth_compiled_cache/UnslothORPOTrainer.py +0 -1730
  69. package/unsloth_compiled_cache/UnslothOnlineDPOTrainer.py +0 -2313
  70. package/unsloth_compiled_cache/UnslothPPOTrainer.py +0 -1504
  71. package/unsloth_compiled_cache/UnslothPRMTrainer.py +0 -979
  72. package/unsloth_compiled_cache/UnslothRLOOTrainer.py +0 -2674
  73. package/unsloth_compiled_cache/UnslothRewardTrainer.py +0 -1197
  74. package/unsloth_compiled_cache/UnslothSFTTrainer.py +0 -1416
  75. package/unsloth_compiled_cache/UnslothXPOTrainer.py +0 -1255
  76. package/unsloth_compiled_cache/__pycache__/AqlmLoraLinear_peft_forward.cpython-312.pyc +0 -0
  77. package/unsloth_compiled_cache/__pycache__/AwqLoraLinear_peft_forward.cpython-312.pyc +0 -0
  78. package/unsloth_compiled_cache/__pycache__/BatchNorm1d.cpython-312.pyc +0 -0
  79. package/unsloth_compiled_cache/__pycache__/BatchNorm2d.cpython-312.pyc +0 -0
  80. package/unsloth_compiled_cache/__pycache__/BatchNorm3d.cpython-312.pyc +0 -0
  81. package/unsloth_compiled_cache/__pycache__/Conv1d.cpython-312.pyc +0 -0
  82. package/unsloth_compiled_cache/__pycache__/Conv2d.cpython-312.pyc +0 -0
  83. package/unsloth_compiled_cache/__pycache__/Conv3d.cpython-312.pyc +0 -0
  84. package/unsloth_compiled_cache/__pycache__/ConvTranspose1d.cpython-312.pyc +0 -0
  85. package/unsloth_compiled_cache/__pycache__/ConvTranspose2d.cpython-312.pyc +0 -0
  86. package/unsloth_compiled_cache/__pycache__/ConvTranspose3d.cpython-312.pyc +0 -0
  87. package/unsloth_compiled_cache/__pycache__/GPTQLoraLinear_peft_forward.cpython-312.pyc +0 -0
  88. package/unsloth_compiled_cache/__pycache__/GroupNorm.cpython-312.pyc +0 -0
  89. package/unsloth_compiled_cache/__pycache__/LayerNorm.cpython-312.pyc +0 -0
  90. package/unsloth_compiled_cache/__pycache__/Linear4bit_peft_forward.cpython-312.pyc +0 -0
  91. package/unsloth_compiled_cache/__pycache__/Linear8bitLt_peft_forward.cpython-312.pyc +0 -0
  92. package/unsloth_compiled_cache/__pycache__/Linear_peft_forward.cpython-312.pyc +0 -0
  93. package/unsloth_compiled_cache/__pycache__/LoraParallelLinear_peft_forward.cpython-312.pyc +0 -0
  94. package/unsloth_compiled_cache/__pycache__/RMSNorm.cpython-312.pyc +0 -0
  95. package/unsloth_compiled_cache/__pycache__/UnslothBCOTrainer.cpython-312.pyc +0 -0
  96. package/unsloth_compiled_cache/__pycache__/UnslothCPOTrainer.cpython-312.pyc +0 -0
  97. package/unsloth_compiled_cache/__pycache__/UnslothDPOTrainer.cpython-312.pyc +0 -0
  98. package/unsloth_compiled_cache/__pycache__/UnslothGKDTrainer.cpython-312.pyc +0 -0
  99. package/unsloth_compiled_cache/__pycache__/UnslothGRPOTrainer.cpython-312.pyc +0 -0
  100. package/unsloth_compiled_cache/__pycache__/UnslothKTOTrainer.cpython-312.pyc +0 -0
  101. package/unsloth_compiled_cache/__pycache__/UnslothNashMDTrainer.cpython-312.pyc +0 -0
  102. package/unsloth_compiled_cache/__pycache__/UnslothORPOTrainer.cpython-312.pyc +0 -0
  103. package/unsloth_compiled_cache/__pycache__/UnslothOnlineDPOTrainer.cpython-312.pyc +0 -0
  104. package/unsloth_compiled_cache/__pycache__/UnslothPPOTrainer.cpython-312.pyc +0 -0
  105. package/unsloth_compiled_cache/__pycache__/UnslothPRMTrainer.cpython-312.pyc +0 -0
  106. package/unsloth_compiled_cache/__pycache__/UnslothRLOOTrainer.cpython-312.pyc +0 -0
  107. package/unsloth_compiled_cache/__pycache__/UnslothRewardTrainer.cpython-312.pyc +0 -0
  108. package/unsloth_compiled_cache/__pycache__/UnslothSFTTrainer.cpython-312.pyc +0 -0
  109. package/unsloth_compiled_cache/__pycache__/UnslothXPOTrainer.cpython-312.pyc +0 -0
  110. package/unsloth_compiled_cache/__pycache__/unsloth_compiled_module_qwen3_moe.cpython-312.pyc +0 -0
  111. package/unsloth_compiled_cache/__pycache__/unsloth_compiled_module_siglip.cpython-312.pyc +0 -0
  112. package/unsloth_compiled_cache/unsloth_compiled_module_qwen3_moe.py +0 -726
  113. package/unsloth_compiled_cache/unsloth_compiled_module_siglip.py +0 -534
package/lib/api-client.js CHANGED
@@ -63,6 +63,40 @@ class CodeReviewClient {
63
63
  }
64
64
  }
65
65
 
66
+ /**
67
+ * 대화형 코드 리뷰
68
+ * @param {string} sessionId - 세션 ID
69
+ * @param {string} message - 사용자 메시지
70
+ * @param {string} fileContent - 파일 내용 (최초 1회)
71
+ * @param {string} filePath - 파일 경로 (최초 1회)
72
+ */
73
+ async chat(sessionId, message, fileContent = null, filePath = null) {
74
+ try {
75
+ const response = await this.client.post('/chat', {
76
+ session_id: sessionId,
77
+ message,
78
+ file_content: fileContent,
79
+ file_path: filePath
80
+ });
81
+ return response.data;
82
+ } catch (error) {
83
+ this.handleError(error);
84
+ }
85
+ }
86
+
87
+ /**
88
+ * 대화 세션 초기화
89
+ * @param {string} sessionId - 세션 ID
90
+ */
91
+ async clearChat(sessionId) {
92
+ try {
93
+ const response = await this.client.delete(`/chat/${sessionId}`);
94
+ return response.data;
95
+ } catch (error) {
96
+ this.handleError(error);
97
+ }
98
+ }
99
+
66
100
  /**
67
101
  * 에러 핸들링
68
102
  */
package/lib/chat-mode.js CHANGED
@@ -3,17 +3,18 @@ const readline = require('readline');
3
3
  const chalk = require('chalk');
4
4
  const FileReader = require('./file-reader');
5
5
  const CodeReviewClient = require('./api-client');
6
- const { parseDiffAndShowInVSCode } = require('./diff-viewer');
6
+ const crypto = require('crypto');
7
7
 
8
8
  class ChatMode {
9
9
  constructor() {
10
10
  this.fileReader = new FileReader();
11
- // 환경변수가 있으면 사용, 없으면 기본값 사용
12
11
  const serverUrl = process.env.CODE_REVIEW_SERVER;
13
12
  this.client = serverUrl ? new CodeReviewClient(serverUrl) : new CodeReviewClient();
14
13
  this.projectFiles = [];
15
- this.filesContent = {};
16
14
  this.rl = null;
15
+ this.sessionId = crypto.randomBytes(16).toString('hex');
16
+ this.currentFile = null; // 현재 리뷰 중인 파일
17
+ this.currentFileContent = null;
17
18
  }
18
19
 
19
20
  /**
@@ -68,7 +69,8 @@ class ChatMode {
68
69
  prompt: chalk.bold.cyan('> ')
69
70
  });
70
71
 
71
- console.log(chalk.gray('무엇을 도와드릴까요? (종료하려면 "exit" 입력)\n'));
72
+ console.log(chalk.gray('파일을 선택하여 대화를 시작하세요. 예: "api.py 리뷰해줘"'));
73
+ console.log(chalk.gray('종료하려면 "exit" 입력\n'));
72
74
  this.rl.prompt();
73
75
 
74
76
  this.rl.on('line', async (input) => {
@@ -81,10 +83,17 @@ class ChatMode {
81
83
 
82
84
  if (command === 'exit' || command === 'quit') {
83
85
  console.log(chalk.green('\n👋 안녕히 가세요!'));
86
+ await this.cleanup();
84
87
  this.rl.close();
85
88
  process.exit(0);
86
89
  }
87
90
 
91
+ if (command === 'clear' || command === '초기화') {
92
+ await this.clearCurrentFile();
93
+ this.rl.prompt();
94
+ return;
95
+ }
96
+
88
97
  await this.handleCommand(command);
89
98
  this.rl.prompt();
90
99
  });
@@ -100,10 +109,10 @@ class ChatMode {
100
109
  async handleCommand(command) {
101
110
  const lowerCommand = command.toLowerCase();
102
111
 
103
- // 파일 리뷰 요청 감지
104
- if (lowerCommand.includes('리뷰') || lowerCommand.includes('review') ||
105
- lowerCommand.includes('검사') || lowerCommand.includes('check')) {
106
- await this.handleReviewRequest(command);
112
+ // 파일 선택 또는 리뷰 요청 감지
113
+ if (lowerCommand.includes('리뷰') || lowerCommand.includes('review')) {
114
+ // 파일 선택 및 대화 시작
115
+ await this.selectFileAndStartChat(command);
107
116
  }
108
117
  // 파일 목록 요청
109
118
  else if (lowerCommand.includes('목록') || lowerCommand.includes('list') ||
@@ -114,17 +123,22 @@ class ChatMode {
114
123
  else if (lowerCommand.includes('help') || lowerCommand.includes('도움말')) {
115
124
  this.showHelp();
116
125
  }
117
- // 기타 - 일반 질문으로 처리
126
+ // 기타 - 현재 파일에 대한 대화
118
127
  else {
119
- console.log(chalk.yellow('\n💡 파일을 리뷰하려면 "파일명 리뷰해줘" 형식으로 입력해주세요.'));
120
- console.log(chalk.gray(' 예: api.py 리뷰해줘, 모든 Python 파일 검사해줘\n'));
128
+ if (this.currentFile) {
129
+ // 현재 파일이 선택되어 있으면 대화 계속
130
+ await this.continueChat(command);
131
+ } else {
132
+ console.log(chalk.yellow('\n💡 먼저 파일을 선택해주세요.'));
133
+ console.log(chalk.gray(' 예: api.py 리뷰해줘\n'));
134
+ }
121
135
  }
122
136
  }
123
137
 
124
138
  /**
125
- * 리뷰 요청 처리
139
+ * 파일 선택 및 대화 시작
126
140
  */
127
- async handleReviewRequest(command) {
141
+ async selectFileAndStartChat(command) {
128
142
  // 파일 매칭
129
143
  const matchedFiles = this.fileReader.matchFiles(command, this.projectFiles);
130
144
 
@@ -134,44 +148,105 @@ class ChatMode {
134
148
  return;
135
149
  }
136
150
 
137
- console.log(chalk.cyan(`\n🔍 ${matchedFiles.length}개 파일 리뷰 중...\n`));
151
+ let filePath;
152
+
153
+ if (matchedFiles.length > 1) {
154
+ console.log(chalk.yellow('\n⚠️ 여러 파일이 매칭됩니다:'));
155
+ matchedFiles.forEach((file, index) => {
156
+ console.log(chalk.cyan(` ${index + 1}. ${file}`));
157
+ });
158
+ console.log('');
159
+
160
+ const answer = await this.askQuestion(`선택 (1-${matchedFiles.length}): `);
161
+ const selection = parseInt(answer);
162
+
163
+ if (isNaN(selection) || selection < 1 || selection > matchedFiles.length) {
164
+ console.log(chalk.red('\n❌ 잘못된 선택입니다.\n'));
165
+ return;
166
+ }
138
167
 
139
- for (const filePath of matchedFiles) {
140
- await this.reviewFile(filePath);
168
+ filePath = matchedFiles[selection - 1];
169
+ } else {
170
+ filePath = matchedFiles[0];
141
171
  }
142
- }
143
172
 
144
- /**
145
- * 단일 파일 리뷰
146
- */
147
- async reviewFile(filePath) {
173
+ // 파일 내용 읽기
148
174
  try {
149
- console.log(chalk.bold(`\n=== ${filePath} ===\n`));
150
-
151
- // 파일 내용 읽기
152
- console.log(chalk.gray(`📖 파일 읽는 중...`));
175
+ console.log(chalk.cyan(`\n📖 ${filePath} 파일을 읽는 중...`));
153
176
  const content = await this.fileReader.readFile(filePath);
154
- console.log(chalk.gray(`✓ 파일 읽기 완료 (${content.length}자)`));
155
177
 
156
- // 언어 감지
157
- const language = this.detectLanguage(filePath);
158
- console.log(chalk.gray(`🔍 언어: ${language}`));
178
+ // 파일이 바뀌면 세션 초기화
179
+ if (this.currentFile && this.currentFile !== filePath) {
180
+ await this.client.clearChat(this.sessionId);
181
+ this.sessionId = crypto.randomBytes(16).toString('hex');
182
+ }
183
+
184
+ this.currentFile = filePath;
185
+ this.currentFileContent = content;
159
186
 
160
- // 서버에 리뷰 요청
161
- console.log(chalk.gray(`🚀 서버로 리뷰 요청 중...`));
162
- const result = await this.client.reviewCode(content, language);
163
- console.log(chalk.gray(`✓ 리뷰 완료\n`));
187
+ console.log(chalk.green(`✅ 파일 로드 완료 (${content.length}자)`));
188
+ console.log(chalk.cyan(`\n💬 "${this.currentFile}" 대해 질문하세요!\n`));
164
189
 
165
- // diff를 파싱하고 VSCode로 표시, 리뷰 텍스트만 반환
166
- const reviewTextOnly = parseDiffAndShowInVSCode(result.review, filePath);
190
+ // 초기 메시지 전송
191
+ const initialMessage = "이 파일을 리뷰해주세요. 주요 문제점과 개선사항을 알려주세요.";
192
+ await this.sendMessage(initialMessage, true);
167
193
 
168
- // 결과 출력 (리뷰 텍스트만)
169
- console.log(chalk.bold.cyan('=== 코드 리뷰 결과 ==='));
170
- console.log(reviewTextOnly);
194
+ } catch (error) {
195
+ console.error(chalk.red(`❌ 파일 읽기 실패: ${error.message}\n`));
196
+ }
197
+ }
198
+
199
+ /**
200
+ * 대화 계속하기
201
+ */
202
+ async continueChat(message) {
203
+ await this.sendMessage(message, false);
204
+ }
205
+
206
+ /**
207
+ * 메시지 전송
208
+ */
209
+ async sendMessage(message, isFirst) {
210
+ try {
211
+ console.log(chalk.gray('🤔 생각 중...\n'));
212
+
213
+ const response = await this.client.chat(
214
+ this.sessionId,
215
+ message,
216
+ isFirst ? this.currentFileContent : null,
217
+ isFirst ? this.currentFile : null
218
+ );
219
+
220
+ console.log(chalk.bold.green('코드가드:'));
221
+ console.log(response.response);
171
222
  console.log('');
172
223
 
173
224
  } catch (error) {
174
- console.error(chalk.red(`❌ 리뷰 실패 (${filePath}): ${error.message}\n`));
225
+ console.error(chalk.red(`❌ 에러: ${error.message}\n`));
226
+ }
227
+ }
228
+
229
+ /**
230
+ * 현재 파일 초기화
231
+ */
232
+ async clearCurrentFile() {
233
+ if (this.currentFile) {
234
+ await this.client.clearChat(this.sessionId);
235
+ console.log(chalk.yellow(`\n🔄 "${this.currentFile}" 대화를 초기화했습니다.\n`));
236
+ this.currentFile = null;
237
+ this.currentFileContent = null;
238
+ this.sessionId = crypto.randomBytes(16).toString('hex');
239
+ } else {
240
+ console.log(chalk.yellow('\n⚠️ 활성화된 파일이 없습니다.\n'));
241
+ }
242
+ }
243
+
244
+ /**
245
+ * 정리
246
+ */
247
+ async cleanup() {
248
+ if (this.currentFile) {
249
+ await this.client.clearChat(this.sessionId);
175
250
  }
176
251
  }
177
252
 
@@ -196,35 +271,15 @@ class ChatMode {
196
271
  */
197
272
  showHelp() {
198
273
  console.log(chalk.bold('\n📖 사용 가능한 명령어:\n'));
199
- console.log(chalk.cyan(' 파일명 리뷰해줘') + chalk.gray(' - 특정 파일 리뷰'));
200
- console.log(chalk.cyan(' 모든 Python 파일 검사') + chalk.gray(' - 확장자별 리뷰'));
274
+ console.log(chalk.cyan(' 파일명 리뷰해줘') + chalk.gray(' - 파일 선택 및 대화 시작'));
275
+ console.log(chalk.cyan(' 부분 설명해줘') + chalk.gray(' - 선택된 파일에 대해 추가 질문'));
276
+ console.log(chalk.cyan(' 보안 문제는?') + chalk.gray(' - 선택된 파일에 대해 추가 질문'));
201
277
  console.log(chalk.cyan(' 파일 목록') + chalk.gray(' - 분석 가능한 파일 목록'));
278
+ console.log(chalk.cyan(' clear / 초기화') + chalk.gray(' - 현재 대화 초기화'));
202
279
  console.log(chalk.cyan(' help') + chalk.gray(' - 이 도움말'));
203
280
  console.log(chalk.cyan(' exit') + chalk.gray(' - 종료\n'));
204
281
  }
205
282
 
206
- /**
207
- * 파일 확장자로 언어 감지
208
- */
209
- detectLanguage(filePath) {
210
- const ext = filePath.split('.').pop().toLowerCase();
211
- const langMap = {
212
- 'py': 'python',
213
- 'js': 'javascript',
214
- 'jsx': 'javascript',
215
- 'ts': 'typescript',
216
- 'tsx': 'typescript',
217
- 'java': 'java',
218
- 'cpp': 'cpp',
219
- 'c': 'c',
220
- 'go': 'go',
221
- 'rs': 'rust',
222
- 'rb': 'ruby',
223
- 'php': 'php'
224
- };
225
- return langMap[ext] || 'text';
226
- }
227
-
228
283
  /**
229
284
  * 사용자에게 질문하고 답변 받기
230
285
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cciwon-code-review-cli",
3
- "version": "2.0.9",
3
+ "version": "2.1.1",
4
4
  "description": "AI-powered code review CLI tool using Qwen3-Coder-30B model with IP whitelist support",
5
5
  "main": "lib/api-client.js",
6
6
  "bin": {
@@ -1,233 +0,0 @@
1
- # cciwon-code-review-cli
2
-
3
- AI 기반 코드 리뷰 CLI 도구 (Qwen3-Coder-30B DPO 파인튜닝 모델 사용)
4
-
5
- ## 특징
6
-
7
- - 🔒 **폐쇄망 지원**: IP 화이트리스트 기반 (192.168.10.152)
8
- - 📁 **폴더 전체 리뷰**: 프로젝트 전체를 한 번에 분석
9
- - 📄 **파일 단위 리뷰**: 개별 파일 심층 분석
10
- - 🛡️ **보안 중심**: SQL Injection, XSS 등 보안 취약점 탐지
11
- - ⚡ **빠른 응답**: vLLM 기반 고성능 추론
12
-
13
- ## 설치
14
-
15
- ### 1. 서버 설정
16
-
17
- 먼저 vLLM 서버를 시작해야 합니다:
18
-
19
- ```bash
20
- # 필수 패키지 설치
21
- pip install vllm fastapi uvicorn
22
-
23
- # 서버 실행
24
- cd /home/cwk317/codereivew
25
- python vllm_server.py
26
- ```
27
-
28
- 서버가 `192.168.10.152:8000`에서 실행됩니다.
29
-
30
- ### 2. CLI 설치
31
-
32
- ```bash
33
- cd code-review-cli
34
- npm install
35
- npm link # 전역 설치
36
- ```
37
-
38
- 또는 로컬에서 직접 사용:
39
-
40
- ```bash
41
- node bin/code-review.js <command>
42
- ```
43
-
44
- ## 사용법
45
-
46
- ### 서버 상태 확인
47
-
48
- ```bash
49
- code-review health
50
- ```
51
-
52
- 출력 예시:
53
- ```
54
- ✅ 서버 정상 작동 중
55
-
56
- 서버 정보:
57
- - 상태: healthy
58
- - 모델 로드: 완료
59
- - 서버 URL: http://192.168.10.152:8000
60
- ```
61
-
62
- ### 폴더 전체 리뷰
63
-
64
- ```bash
65
- code-review folder /path/to/project
66
- ```
67
-
68
- 옵션:
69
- - `-i, --include <patterns>`: 포함할 파일 패턴 (기본: `*.py,*.js,*.ts,*.java,*.cpp,*.go`)
70
- - `-e, --exclude <patterns>`: 제외할 패턴 (기본: `node_modules,__pycache__,.git,*.pyc`)
71
- - `-m, --max-files <number>`: 최대 파일 수 (기본: 50)
72
-
73
- 예시:
74
- ```bash
75
- # Python 프로젝트 리뷰
76
- code-review folder ./my-python-project -i "*.py" -e "__pycache__,*.pyc,venv"
77
-
78
- # JavaScript 프로젝트 리뷰
79
- code-review folder ./my-js-project -i "*.js,*.jsx" -e "node_modules,dist,build"
80
-
81
- # 모든 코드 파일 리뷰 (최대 100개)
82
- code-review folder ./my-project -m 100
83
- ```
84
-
85
- ### 단일 파일 리뷰
86
-
87
- ```bash
88
- code-review file /path/to/file.py
89
- ```
90
-
91
- 옵션:
92
- - `-l, --language <lang>`: 프로그래밍 언어 (기본: python)
93
- - `-c, --checklist <path>`: 체크리스트 파일 경로
94
-
95
- 예시:
96
- ```bash
97
- # Python 파일 리뷰
98
- code-review file ./app.py -l python
99
-
100
- # TypeScript 파일 + 체크리스트
101
- code-review file ./api.ts -l typescript -c ./checklist.txt
102
-
103
- # Java 파일 리뷰
104
- code-review file ./Main.java -l java
105
- ```
106
-
107
- ## VSCode 통합
108
-
109
- ### 방법 1: Tasks 사용
110
-
111
- `.vscode/tasks.json` 파일 생성:
112
-
113
- ```json
114
- {
115
- "version": "2.0.0",
116
- "tasks": [
117
- {
118
- "label": "Code Review: Current Folder",
119
- "type": "shell",
120
- "command": "code-review folder ${workspaceFolder}",
121
- "problemMatcher": [],
122
- "presentation": {
123
- "reveal": "always",
124
- "panel": "new"
125
- }
126
- },
127
- {
128
- "label": "Code Review: Current File",
129
- "type": "shell",
130
- "command": "code-review file ${file}",
131
- "problemMatcher": [],
132
- "presentation": {
133
- "reveal": "always",
134
- "panel": "new"
135
- }
136
- }
137
- ]
138
- }
139
- ```
140
-
141
- 사용법:
142
- 1. `Ctrl+Shift+P` → `Tasks: Run Task`
143
- 2. `Code Review: Current Folder` 또는 `Code Review: Current File` 선택
144
-
145
- ### 방법 2: 터미널에서 직접 사용
146
-
147
- VSCode 내장 터미널에서:
148
-
149
- ```bash
150
- # 현재 워크스페이스 리뷰
151
- code-review folder .
152
-
153
- # 특정 파일 리뷰
154
- code-review file src/main.py
155
- ```
156
-
157
- ## 환경 변수
158
-
159
- 서버 URL을 변경하려면 환경 변수 설정:
160
-
161
- ```bash
162
- export CODE_REVIEW_SERVER=http://192.168.10.152:8000
163
- code-review health
164
- ```
165
-
166
- ## IP 화이트리스트
167
-
168
- 현재 허용된 IP:
169
- - `192.168.10.152` (서버 IP)
170
- - `127.0.0.1` (로컬 테스트용)
171
-
172
- 다른 IP에서 접근 시:
173
- ```
174
- ❌ 허용된 아이피가 아닙니다
175
- 현재 IP: 192.168.10.xxx
176
- 허용된 IP: 192.168.10.152, 127.0.0.1
177
- ```
178
-
179
- IP 추가하려면 `vllm_server.py`의 `ALLOWED_IPS` 수정:
180
-
181
- ```python
182
- ALLOWED_IPS = ["192.168.10.152", "127.0.0.1", "192.168.10.100"] # 새 IP 추가
183
- ```
184
-
185
- ## 트러블슈팅
186
-
187
- ### 서버 연결 실패
188
-
189
- ```
190
- ❌ 서버 연결 실패
191
- 서버 연결 실패: http://192.168.10.152:8000
192
- 서버가 실행 중인지 확인하세요.
193
- ```
194
-
195
- 해결:
196
- 1. vLLM 서버가 실행 중인지 확인: `ps aux | grep vllm_server`
197
- 2. 서버 로그 확인: `tail -f /path/to/server.log`
198
- 3. 방화벽 확인: `sudo ufw status`
199
-
200
- ### IP 차단
201
-
202
- ```
203
- ❌ 허용된 아이피가 아닙니다
204
- ```
205
-
206
- 해결:
207
- 1. 현재 IP 확인: `curl ifconfig.me`
208
- 2. `vllm_server.py`의 `ALLOWED_IPS`에 추가
209
- 3. 서버 재시작
210
-
211
- ### 메모리 부족
212
-
213
- vLLM 서버가 OOM으로 죽는 경우:
214
-
215
- `vllm_server.py` 수정:
216
- ```python
217
- llm = LLM(
218
- model=OUTPUT_DIR,
219
- tensor_parallel_size=2,
220
- gpu_memory_utilization=0.7, # 0.9 → 0.7로 감소
221
- max_model_len=1024, # 2048 → 1024로 감소
222
- )
223
- ```
224
-
225
- ## 성능
226
-
227
- - 평균 응답 시간: ~5초 (폴더 리뷰, 10개 파일 기준)
228
- - 동시 처리: vLLM 배치 처리로 여러 요청 동시 처리 가능
229
- - GPU 사용량: 2x RTX 5090 (50-60GB)
230
-
231
- ## 라이선스
232
-
233
- MIT
@@ -1,36 +0,0 @@
1
- {
2
- "name": "cciwon-code-review-cli",
3
- "version": "2.0.6",
4
- "description": "AI-powered code review CLI tool using Qwen3-Coder-30B model with IP whitelist support",
5
- "main": "lib/api-client.js",
6
- "bin": {
7
- "code-review": "bin/code-review.js"
8
- },
9
- "scripts": {
10
- "test": "echo \"Error: no test specified\" && exit 1"
11
- },
12
- "keywords": [
13
- "code-review",
14
- "ai",
15
- "qwen",
16
- "qwen3-coder",
17
- "code-analysis",
18
- "security",
19
- "llm",
20
- "code-quality",
21
- "static-analysis"
22
- ],
23
- "author": "cciwon",
24
- "license": "MIT",
25
- "dependencies": {
26
- "axios": "^1.6.0",
27
- "commander": "^11.1.0",
28
- "chalk": "^4.1.2",
29
- "ora": "^5.4.1",
30
- "fast-glob": "^3.3.2",
31
- "readline": "^1.3.0"
32
- },
33
- "engines": {
34
- "node": ">=14.0.0"
35
- }
36
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes