cciwon-code-review-cli 2.0.4 → 2.0.5

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 (2) hide show
  1. package/bin/code-review.js +154 -2
  2. package/package.json +1 -1
@@ -5,6 +5,8 @@ const chalk = require('chalk');
5
5
  const ora = require('ora');
6
6
  const fs = require('fs');
7
7
  const path = require('path');
8
+ const { execSync } = require('child_process');
9
+ const os = require('os');
8
10
  const CodeReviewClient = require('../lib/api-client');
9
11
 
10
12
  const program = new Command();
@@ -19,6 +21,153 @@ program
19
21
  const SERVER_URL = process.env.CODE_REVIEW_SERVER || 'http://211.56.247.71:8000';
20
22
  const client = new CodeReviewClient(SERVER_URL);
21
23
 
24
+ // ==========================================
25
+ // Diff 파싱 및 VSCode 표시 함수
26
+ // ==========================================
27
+ function parseDiffAndShowInVSCode(reviewText, originalFilePath) {
28
+ const lines = reviewText.split('\n');
29
+ const diffs = [];
30
+ let currentDiff = null;
31
+ let reviewContent = [];
32
+ let inDiffBlock = false;
33
+
34
+ for (let i = 0; i < lines.length; i++) {
35
+ const line = lines[i];
36
+
37
+ // unified diff 시작 감지 (--- 와 +++ 패턴)
38
+ if (line.startsWith('---') && i + 1 < lines.length && lines[i + 1].startsWith('+++')) {
39
+ inDiffBlock = true;
40
+ currentDiff = {
41
+ filename: null,
42
+ diffLines: [line, lines[i + 1]]
43
+ };
44
+ i++; // +++ 라인 건너뛰기
45
+ continue;
46
+ }
47
+
48
+ // diff 블록 내부
49
+ if (inDiffBlock) {
50
+ if (line.startsWith('@@') || line.startsWith('-') || line.startsWith('+') || line.startsWith(' ')) {
51
+ currentDiff.diffLines.push(line);
52
+ } else if (line.trim() === '' || line.startsWith('===')) {
53
+ // diff 블록 종료
54
+ if (currentDiff) {
55
+ diffs.push(currentDiff);
56
+ currentDiff = null;
57
+ }
58
+ inDiffBlock = false;
59
+ reviewContent.push(line);
60
+ } else {
61
+ currentDiff.diffLines.push(line);
62
+ }
63
+ } else {
64
+ // 일반 리뷰 텍스트
65
+ reviewContent.push(line);
66
+ }
67
+ }
68
+
69
+ // 마지막 diff 저장
70
+ if (currentDiff) {
71
+ diffs.push(currentDiff);
72
+ }
73
+
74
+ // diff가 있으면 VSCode로 표시
75
+ if (diffs.length > 0) {
76
+ diffs.forEach((diff, index) => {
77
+ try {
78
+ // 임시 디렉토리 생성
79
+ const tmpDir = path.join(os.tmpdir(), `code-review-${Date.now()}-${index}`);
80
+ fs.mkdirSync(tmpDir, { recursive: true });
81
+
82
+ // 원본/수정본 파일 생성
83
+ const originalFile = path.join(tmpDir, 'original' + path.extname(originalFilePath));
84
+ const modifiedFile = path.join(tmpDir, 'modified' + path.extname(originalFilePath));
85
+
86
+ // diff에서 원본/수정본 코드 추출
87
+ const { original, modified } = extractCodeFromDiff(diff.diffLines, originalFilePath);
88
+
89
+ fs.writeFileSync(originalFile, original);
90
+ fs.writeFileSync(modifiedFile, modified);
91
+
92
+ // VSCode diff 뷰어 열기
93
+ try {
94
+ execSync(`code --diff "${originalFile}" "${modifiedFile}"`, { stdio: 'ignore' });
95
+ console.log(chalk.green(`\n📝 VSCode에서 diff를 열었습니다 (${index + 1}/${diffs.length})`));
96
+ } catch (e) {
97
+ console.log(chalk.yellow(`\n⚠️ VSCode를 열 수 없습니다. diff를 수동으로 확인하세요:`));
98
+ console.log(chalk.gray(diff.diffLines.join('\n')));
99
+ }
100
+
101
+ // 임시 파일은 5분 후 자동 삭제
102
+ setTimeout(() => {
103
+ try {
104
+ fs.unlinkSync(originalFile);
105
+ fs.unlinkSync(modifiedFile);
106
+ fs.rmdirSync(tmpDir);
107
+ } catch (e) {
108
+ // 무시
109
+ }
110
+ }, 5 * 60 * 1000);
111
+
112
+ } catch (error) {
113
+ console.error(chalk.red(`diff 처리 실패: ${error.message}`));
114
+ }
115
+ });
116
+ }
117
+
118
+ // 리뷰 텍스트만 반환
119
+ return reviewContent.join('\n').trim();
120
+ }
121
+
122
+ // diff에서 원본/수정본 추출
123
+ function extractCodeFromDiff(diffLines, originalFilePath) {
124
+ let original = '';
125
+ let modified = '';
126
+
127
+ // 원본 파일이 있으면 읽기
128
+ if (fs.existsSync(originalFilePath)) {
129
+ original = fs.readFileSync(originalFilePath, 'utf-8');
130
+ }
131
+
132
+ // diff 라인을 파싱해서 수정본 생성
133
+ const originalLines = original.split('\n');
134
+ const modifiedLines = [];
135
+
136
+ let lineNum = 0;
137
+ for (const line of diffLines) {
138
+ if (line.startsWith('@@')) {
139
+ // @@ -15,2 +15,2 @@ 형식 파싱
140
+ const match = line.match(/@@ -(\d+),?(\d*) \+(\d+),?(\d*) @@/);
141
+ if (match) {
142
+ lineNum = parseInt(match[1]) - 1;
143
+ }
144
+ } else if (line.startsWith('-')) {
145
+ // 삭제된 라인 (원본에만 있음)
146
+ lineNum++;
147
+ } else if (line.startsWith('+')) {
148
+ // 추가된 라인 (수정본에만 있음)
149
+ modifiedLines.push(line.substring(1));
150
+ } else if (line.startsWith(' ')) {
151
+ // 변경 없는 라인
152
+ if (lineNum < originalLines.length) {
153
+ modifiedLines.push(originalLines[lineNum]);
154
+ lineNum++;
155
+ } else {
156
+ modifiedLines.push(line.substring(1));
157
+ }
158
+ }
159
+ }
160
+
161
+ // 수정본이 비어있으면 원본을 기반으로 단순 패치 시도
162
+ if (modifiedLines.length === 0) {
163
+ modified = original;
164
+ } else {
165
+ modified = modifiedLines.join('\n');
166
+ }
167
+
168
+ return { original, modified };
169
+ }
170
+
22
171
  // ==========================================
23
172
  // 폴더 리뷰 명령어
24
173
  // ==========================================
@@ -108,9 +257,12 @@ program
108
257
 
109
258
  spinner.succeed(chalk.green('✅ 리뷰 완료!'));
110
259
 
111
- // 결과 출력
260
+ // diff를 파싱하고 VSCode로 표시, 리뷰 텍스트만 반환
261
+ const reviewTextOnly = parseDiffAndShowInVSCode(result.review, absolutePath);
262
+
263
+ // 결과 출력 (리뷰 텍스트만)
112
264
  console.log('\n' + chalk.bold.cyan('=== 코드 리뷰 결과 ==='));
113
- console.log(result.review);
265
+ console.log(reviewTextOnly);
114
266
 
115
267
  } catch (error) {
116
268
  spinner.fail(chalk.red('❌ 리뷰 실패'));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cciwon-code-review-cli",
3
- "version": "2.0.4",
3
+ "version": "2.0.5",
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": {