coderev-cli 1.0.9 โ†’ 1.0.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "coderev-cli",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "Multi-agent AI code review for git -- parallel agents with confidence scoring",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env node
1
+ ๏ปฟ#!/usr/bin/env node
2
2
 
3
3
  const { program } = require('commander');
4
4
  const chalk = require('chalk');
@@ -71,7 +71,7 @@ program
71
71
  return;
72
72
  }
73
73
 
74
- console.error(chalk.bold(`\n๐Ÿ“‹ Found ${prList.length} open PRs in ${prRef.owner}/${prRef.repo}:`));
74
+ console.error(chalk.bold(`\n้ฆƒๆต Found ${prList.length} open PRs in ${prRef.owner}/${prRef.repo}:`));
75
75
  for (const pr of prList) {
76
76
  console.error(` #${pr.number} ${pr.title} (${pr.draft ? 'draft' : 'open'})`);
77
77
  }
@@ -79,7 +79,7 @@ program
79
79
 
80
80
  const results = [];
81
81
  for (const pr of prList) {
82
- console.error(chalk.blue(`โ†ป Reviewing PR #${pr.number}...`));
82
+ console.error(chalk.blue(`้ˆซ?Reviewing PR #${pr.number}...`));
83
83
  const fullRef = { owner: prRef.owner, repo: prRef.repo, pr: pr.number };
84
84
  try {
85
85
  const prDiff = await fetchPrDiff(fullRef, token);
@@ -89,7 +89,7 @@ program
89
89
  if (options.post) {
90
90
  const md = formatMarkdown(result);
91
91
  await postPrComment(fullRef, md, token);
92
- console.error(chalk.green(` โœ” #${pr.number} reviewed & posted`));
92
+ console.error(chalk.green(` ้‰?#${pr.number} reviewed & posted`));
93
93
  } else {
94
94
  const scoreColor = result.score >= 80 ? chalk.green : result.score >= 50 ? chalk.yellow : chalk.red;
95
95
  const scoreStr = scoreColor(`${result.score}/100`);
@@ -97,7 +97,7 @@ program
97
97
  console.error(` ${scoreStr} (${issueCount} issues) - ${result.summary || ''}`);
98
98
  }
99
99
  } catch (err) {
100
- console.error(chalk.red(` โœ– #${pr.number}: ${err.message}`));
100
+ console.error(chalk.red(` ้‰?#${pr.number}: ${err.message}`));
101
101
  }
102
102
  }
103
103
 
@@ -105,7 +105,7 @@ program
105
105
  const scores = results.filter(r => r.result).map(r => r.result.score);
106
106
  if (scores.length > 0) {
107
107
  const avg = (scores.reduce((a, b) => a + b, 0) / scores.length).toFixed(1);
108
- console.error(chalk.bold(`\n๐Ÿ“Š Batch Summary: ${results.length}/${prList.length} reviewed, avg score: ${avg}`));
108
+ console.error(chalk.bold(`\n้ฆƒๆณ Batch Summary: ${results.length}/${prList.length} reviewed, avg score: ${avg}`));
109
109
  }
110
110
 
111
111
  if (options.output === 'json') {
@@ -124,35 +124,35 @@ program
124
124
  const { resolveMrRef, fetchMrDiff } = require('./gitlab');
125
125
  const glRef = resolveMrRef(options.gl, options.repo);
126
126
  const glToken = options.gitlabToken || process.env.GITLAB_TOKEN;
127
- console.error(chalk.blue(`โ†ป Fetching GitLab MR ${glRef.owner}/${glRef.repo}!${glRef.mr}...`));
127
+ console.error(chalk.blue(`้ˆซ?Fetching GitLab MR ${glRef.owner}/${glRef.repo}!${glRef.mr}...`));
128
128
  diff = await fetchMrDiff(glRef, glToken);
129
- console.error(chalk.green(`โœ” Diff fetched (${diff.length} chars)`));
129
+ console.error(chalk.green(`้‰?Diff fetched (${diff.length} chars)`));
130
130
  } else if (options.gee) {
131
131
  const { resolvePrRef: resolveGiteeRef, fetchPrDiff: fetchGiteeDiff } = require('./gitee');
132
132
  const geeRef = resolveGiteeRef(options.gee, options.repo);
133
133
  const geeToken = options.geeToken || process.env.GITEE_TOKEN;
134
- console.error(chalk.blue(`โ†ป Fetching Gitee PR ${geeRef.owner}/${geeRef.repo}!${geeRef.pr}...`));
134
+ console.error(chalk.blue(`้ˆซ?Fetching Gitee PR ${geeRef.owner}/${geeRef.repo}!${geeRef.pr}...`));
135
135
  diff = await fetchGiteeDiff(geeRef, geeToken);
136
- console.error(chalk.green(`โœ” Diff fetched (${diff.length} chars)`));
136
+ console.error(chalk.green(`้‰?Diff fetched (${diff.length} chars)`));
137
137
  } else if (options.gc) {
138
138
  const { resolveMrRef: resolveGcRef, fetchMrDiff: fetchGcDiff } = require('./gitcode');
139
139
  const gcRef = resolveGcRef(options.gc, options.repo);
140
140
  const gcToken = options.gcToken || process.env.GITCODE_TOKEN;
141
- console.error(chalk.blue(`โ†ป Fetching GitCode MR ${gcRef.owner}/${gcRef.repo}!${gcRef.mr}...`));
141
+ console.error(chalk.blue(`้ˆซ?Fetching GitCode MR ${gcRef.owner}/${gcRef.repo}!${gcRef.mr}...`));
142
142
  diff = await fetchGcDiff(gcRef, gcToken);
143
- console.error(chalk.green(`โœ” Diff fetched (${diff.length} chars)`));
143
+ console.error(chalk.green(`้‰?Diff fetched (${diff.length} chars)`));
144
144
  } else if (options.bb) {
145
145
  const { resolvePrRef: resolveBbRef, fetchPrDiff: fetchBbDiff } = require('./bitbucket');
146
146
  const bbRef = resolveBbRef(options.bb, options.repo);
147
147
  if (options.bbToken) process.env.BITBUCKET_USERNAME = options.bbToken.split(':')[0] || '';
148
148
  const bbToken = options.bbToken || process.env.BITBUCKET_APP_PASSWORD;
149
- console.error(chalk.blue(`โ†ป Fetching Bitbucket PR ${bbRef.owner}/${bbRef.repo}#${bbRef.pr}...`));
149
+ console.error(chalk.blue(`้ˆซ?Fetching Bitbucket PR ${bbRef.owner}/${bbRef.repo}#${bbRef.pr}...`));
150
150
  diff = await fetchBbDiff(bbRef, bbToken);
151
- console.error(chalk.green(`โœ” Diff fetched (${diff.length} chars)`));
151
+ console.error(chalk.green(`้‰?Diff fetched (${diff.length} chars)`));
152
152
  } else if (options.pr) {
153
153
  prRef = resolvePrRef(options.pr, options.repo);
154
154
  const token = resolveToken(options.githubToken, config);
155
- console.error(chalk.blue(`โ†ป Fetching PR ${prRef.owner}/${prRef.repo}#${prRef.pr}...`));
155
+ console.error(chalk.blue(`้ˆซ?Fetching PR ${prRef.owner}/${prRef.repo}#${prRef.pr}...`));
156
156
  diff = await fetchPrDiff(prRef, token);
157
157
  } else if (options.file) {
158
158
  const fs = require('fs');
@@ -166,7 +166,7 @@ program
166
166
  if (stdinBuffer.trim()) {
167
167
  diff = stdinBuffer;
168
168
  } else {
169
- console.error(chalk.red('โœ– No diff input provided. Pipe a diff, use --file, use --repo, or use --pr.'));
169
+ console.error(chalk.red('้‰?No diff input provided. Pipe a diff, use --file, use --repo, or use --pr.'));
170
170
  process.exit(1);
171
171
  }
172
172
  }
@@ -191,22 +191,22 @@ program
191
191
  if (options.post && prRef) {
192
192
  const token = resolveToken(options.githubToken, config);
193
193
  if (!token) {
194
- console.error(chalk.red('โœ– --post requires --github-token or GITHUB_TOKEN env var'));
194
+ console.error(chalk.red('้‰?--post requires --github-token or GITHUB_TOKEN env var'));
195
195
  process.exit(1);
196
196
  }
197
197
  const mdReport = formatMarkdown(result);
198
- console.error(chalk.blue(`โ†ป Posting review to PR ${prRef.owner}/${prRef.repo}#${prRef.pr}...`));
198
+ console.error(chalk.blue(`้ˆซ?Posting review to PR ${prRef.owner}/${prRef.repo}#${prRef.pr}...`));
199
199
  await postPrComment(prRef, mdReport, token);
200
- console.error(chalk.green('โœ” Review posted as PR comment!'));
200
+ console.error(chalk.green('้‰?Review posted as PR comment!'));
201
201
  }
202
202
 
203
203
  if (options.inline && prRef) {
204
204
  const token = resolveToken(options.githubToken, config);
205
205
  if (!token) {
206
- console.error(chalk.red('โœ– --inline requires --github-token or GITHUB_TOKEN env var'));
206
+ console.error(chalk.red('้‰?--inline requires --github-token or GITHUB_TOKEN env var'));
207
207
  process.exit(1);
208
208
  }
209
- console.error(chalk.blue(`โ†ป Posting inline review to PR ${prRef.owner}/${prRef.repo}#${prRef.pr}...`));
209
+ console.error(chalk.blue(`้ˆซ?Posting inline review to PR ${prRef.owner}/${prRef.repo}#${prRef.pr}...`));
210
210
 
211
211
  // Get PR files for commit SHA and file mapping
212
212
  const prFiles = await fetchPrFiles(prRef, token);
@@ -246,23 +246,23 @@ program
246
246
  const headSha = prInfo?.head?.sha;
247
247
  if (headSha) {
248
248
  await postInlineComments(prRef, headSha, inlineComments, token);
249
- console.error(chalk.green(`โœ” ${inlineComments.length} inline comments posted!`));
249
+ console.error(chalk.green(`้‰?${inlineComments.length} inline comments posted!`));
250
250
  } else {
251
- console.error(chalk.red('โœ– Could not resolve PR head commit SHA'));
251
+ console.error(chalk.red('้‰?Could not resolve PR head commit SHA'));
252
252
  }
253
253
  } else {
254
- console.error(chalk.yellow('โš  No line-level issues to post inline'));
254
+ console.error(chalk.yellow('้ˆฟ?No line-level issues to post inline'));
255
255
  }
256
256
  }
257
257
 
258
258
  console.log(output);
259
259
  } catch (err) {
260
- console.error(chalk.red(`โœ– ${err.message}`));
260
+ console.error(chalk.red(`้‰?${err.message}`));
261
261
  process.exit(1);
262
262
  }
263
263
  });
264
264
 
265
- // โ”€โ”€ Cache Management โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
265
+ // ้ˆนโ‚ฌ้ˆนโ‚ฌ Cache Management ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ
266
266
  program
267
267
  .command('cache')
268
268
  .description('Manage review cache')
@@ -274,7 +274,7 @@ program
274
274
 
275
275
  if (action === 'clear') {
276
276
  const count = cleanCache();
277
- console.log(chalk.green(`โœ” Cache cleared (${count} entries removed)`));
277
+ console.log(chalk.green(`้‰?Cache cleared (${count} entries removed)`));
278
278
  } else if (action === 'status') {
279
279
  if (!fs.existsSync(cacheDir)) {
280
280
  console.log(chalk.blue(' Cache is empty'));
@@ -282,11 +282,11 @@ program
282
282
  }
283
283
  const files = fs.readdirSync(cacheDir).filter(f => f.endsWith('.json'));
284
284
  const totalSize = files.reduce((sum, f) => sum + fs.statSync(path.join(cacheDir, f)).size, 0);
285
- console.log(chalk.bold(`\n๐Ÿ“ฆ Cache: ${files.length} entries, ${(totalSize / 1024).toFixed(1)} KB`));
285
+ console.log(chalk.bold(`\n้ฆƒๆ‘ Cache: ${files.length} entries, ${(totalSize / 1024).toFixed(1)} KB`));
286
286
  }
287
287
  });
288
288
 
289
- // โ”€โ”€ Fix โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
289
+ // ้ˆนโ‚ฌ้ˆนโ‚ฌ Fix ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ
290
290
  program
291
291
  .command('fix')
292
292
  .description('Generate a fix patch for issues found in a diff')
@@ -305,7 +305,7 @@ program
305
305
  const { resolvePrRef, fetchPrDiff } = require('./github');
306
306
  prRef = resolvePrRef(options.pr, options.repo);
307
307
  const token = resolveToken(options.githubToken, config);
308
- console.error(chalk.blue(`โ†ป Fetching PR ${prRef.owner}/${prRef.repo}#${prRef.pr}...`));
308
+ console.error(chalk.blue(`้ˆซ?Fetching PR ${prRef.owner}/${prRef.repo}#${prRef.pr}...`));
309
309
  diff = await fetchPrDiff(prRef, token);
310
310
  } else if (options.file) {
311
311
  const fs = require('fs');
@@ -314,13 +314,13 @@ program
314
314
  const fs = require('fs');
315
315
  const stdinBuffer = fs.readFileSync(0, 'utf-8');
316
316
  if (!stdinBuffer.trim()) {
317
- console.error(chalk.red('โœ– No diff input provided.'));
317
+ console.error(chalk.red('้‰?No diff input provided.'));
318
318
  process.exit(1);
319
319
  }
320
320
  diff = stdinBuffer;
321
321
  }
322
322
 
323
- console.error(chalk.blue('โ†ป Generating fix patch...'));
323
+ console.error(chalk.blue('้ˆซ?Generating fix patch...'));
324
324
  const { reviewDiff } = require('./reviewer');
325
325
  const result = await reviewDiff(diff, config, { noCache: true, single: true });
326
326
 
@@ -343,31 +343,31 @@ program
343
343
  const patchMatch = aiResponse.match(/\`\`\`diff\n([\s\S]*?)\n\`\`\`/);
344
344
  const patch = patchMatch ? patchMatch[1] : aiResponse;
345
345
 
346
- console.log('\n' + chalk.bold('๐Ÿฉน Fix Patch:'));
347
- console.log('โ”'.repeat(50));
346
+ console.log('\n' + chalk.bold('้ฆƒโ”• Fix Patch:'));
347
+ console.log('้ˆน?.repeat(50));
348
348
  console.log(patch);
349
349
 
350
350
  if (options.apply) {
351
351
  const fs = require('fs');
352
352
  const tmpFile = path.join(require('os').tmpdir(), 'coderev-fix.patch');
353
353
  fs.writeFileSync(tmpFile, patch);
354
- console.error(chalk.blue(`โ†ป Applying patch from ${tmpFile}...`));
354
+ console.error(chalk.blue(`้ˆซ?Applying patch from ${tmpFile}...`));
355
355
  try {
356
356
  const { execSync } = require('child_process');
357
357
  const cwd = prRef ? undefined : process.cwd();
358
358
  execSync(`git apply "${tmpFile}"`, { cwd, stdio: 'pipe' });
359
- console.log(chalk.green('โœ” Patch applied successfully!'));
359
+ console.log(chalk.green('้‰?Patch applied successfully!'));
360
360
  } catch (applyErr) {
361
- console.error(chalk.red(`โœ– Failed to apply patch: ${applyErr.stderr || applyErr.message}`));
361
+ console.error(chalk.red(`้‰?Failed to apply patch: ${applyErr.stderr || applyErr.message}`));
362
362
  }
363
363
  }
364
364
  } catch (err) {
365
- console.error(chalk.red(`โœ– ${err.message}`));
365
+ console.error(chalk.red(`้‰?${err.message}`));
366
366
  process.exit(1);
367
367
  }
368
368
  });
369
369
 
370
- // โ”€โ”€ Config โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
370
+ // ้ˆนโ‚ฌ้ˆนโ‚ฌ Config ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ
371
371
  program
372
372
  .command('config')
373
373
  .description('Manage configuration')
@@ -381,8 +381,8 @@ program
381
381
  const masked = JSON.parse(JSON.stringify(config));
382
382
  if (masked.ai?.apiKey) masked.ai.apiKey = masked.ai.apiKey.slice(0, 8) + '...' + masked.ai.apiKey.slice(-4);
383
383
  if (masked.github?.token) masked.github.token = masked.github.token.slice(0, 8) + '...' + masked.github.token.slice(-4);
384
- console.log(chalk.bold('\nโš™ Active Configuration:'));
385
- console.log('โ”'.repeat(50));
384
+ console.log(chalk.bold('\n้ˆฟ?Active Configuration:'));
385
+ console.log('้ˆน?.repeat(50));
386
386
  console.log(JSON.stringify(masked, null, 2));
387
387
  } else if (action === 'validate') {
388
388
  const fs = require('fs');
@@ -407,13 +407,13 @@ program
407
407
  if (!parsed.ai?.provider) errors.push('Missing "ai.provider"');
408
408
  if (!parsed.ai?.model) errors.push('Missing "ai.model"');
409
409
  if (errors.length === 0) {
410
- console.log(chalk.green(`โœ” Config valid: ${found}`));
410
+ console.log(chalk.green(`้‰?Config valid: ${found}`));
411
411
  } else {
412
- console.log(chalk.yellow(`โš  Config found but has issues:`));
412
+ console.log(chalk.yellow(`้ˆฟ?Config found but has issues:`));
413
413
  for (const e of errors) console.log(chalk.yellow(` ${e}`));
414
414
  }
415
415
  } catch (parseErr) {
416
- console.error(chalk.red(`โœ– Invalid JSON in ${found}: ${parseErr.message}`));
416
+ console.error(chalk.red(`้‰?Invalid JSON in ${found}: ${parseErr.message}`));
417
417
  }
418
418
  } else {
419
419
  console.log(chalk.blue(' No config file found in current or parent directories.'));
@@ -437,7 +437,7 @@ program
437
437
  }
438
438
  });
439
439
 
440
- // โ”€โ”€ Stats โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
440
+ // ้ˆนโ‚ฌ้ˆนโ‚ฌ Stats ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ
441
441
  program
442
442
  .command('stats')
443
443
  .description('Review statistics and trends')
@@ -448,9 +448,9 @@ program
448
448
 
449
449
  if (options.clear) {
450
450
  if (clearHistory()) {
451
- console.log(chalk.green('โœ” Review history cleared'));
451
+ console.log(chalk.green('้‰?Review history cleared'));
452
452
  } else {
453
- console.error(chalk.red('โœ– Failed to clear history'));
453
+ console.error(chalk.red('้‰?Failed to clear history'));
454
454
  }
455
455
  return;
456
456
  }
@@ -463,8 +463,8 @@ program
463
463
  return;
464
464
  }
465
465
 
466
- console.log(chalk.bold('\n๐Ÿ“Š Review Statistics'));
467
- console.log('โ”'.repeat(50));
466
+ console.log(chalk.bold('\n้ฆƒๆณ Review Statistics'));
467
+ console.log('้ˆน?.repeat(50));
468
468
  console.log(` Period: ${chalk.bold(period)}`);
469
469
  console.log(` Total reviews: ${stats.total}`);
470
470
  if (stats.totalAllTime > stats.total) {
@@ -478,7 +478,7 @@ program
478
478
  if (Object.keys(stats.issueTypes).length > 0) {
479
479
  console.log(chalk.bold('\n Issue Types:'));
480
480
  for (const [type, count] of Object.entries(stats.issueTypes)) {
481
- const icon = type === 'error' ? chalk.red('โœ–') : type === 'warning' ? chalk.yellow('โš ') : chalk.blue('โ„น');
481
+ const icon = type === 'error' ? chalk.red('้‰?) : type === 'warning' ? chalk.yellow('้ˆฟ?) : chalk.blue('้ˆฉ?);
482
482
  console.log(` ${icon} ${type}: ${count}`);
483
483
  }
484
484
  }
@@ -487,14 +487,14 @@ program
487
487
  console.log(chalk.bold('\n Severity:'));
488
488
  for (const [sev, count] of Object.entries(stats.severityBreakdown)) {
489
489
  const color = sev === 'high' ? chalk.red : sev === 'medium' ? chalk.yellow : chalk.blue;
490
- console.log(` ${color('โ—')} ${sev}: ${count}`);
490
+ console.log(` ${color('้ˆผ?)} ${sev}: ${count}`);
491
491
  }
492
492
  }
493
493
 
494
494
  if (stats.trend.length > 0) {
495
495
  console.log(chalk.bold('\n Trend (last ' + stats.trend.length + ' reviews):'));
496
496
  for (const t of stats.trend) {
497
- const bar = 'โ–ˆ'.repeat(Math.max(1, Math.round(t.score / 10)));
497
+ const bar = '้ˆป?.repeat(Math.max(1, Math.round(t.score / 10)));
498
498
  const color = t.score >= 80 ? chalk.green : t.score >= 50 ? chalk.yellow : chalk.red;
499
499
  console.log(` ${t.date} ${color(bar)} ${t.score} (${t.issues} issues)`);
500
500
  }
@@ -502,7 +502,7 @@ program
502
502
  console.log('');
503
503
  });
504
504
 
505
- // โ”€โ”€ Hook โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
505
+ // ้ˆนโ‚ฌ้ˆนโ‚ฌ Hook ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ
506
506
  program
507
507
  .command('hook')
508
508
  .description('Install or remove a git hook (pre-commit / pre-push)')
@@ -517,20 +517,20 @@ program
517
517
 
518
518
  if (action === 'install') {
519
519
  if (!fs.existsSync(gitDir)) {
520
- console.error(chalk.red('โœ– Not a git repository: ' + process.cwd()));
520
+ console.error(chalk.red('้‰?Not a git repository: ' + process.cwd()));
521
521
  process.exit(1);
522
522
  }
523
523
 
524
524
  const hookScript = `#!/bin/sh
525
525
  # coderev ${hookType} hook
526
526
  export PATH="$PATH:$(npm root -g)/../.bin"
527
- echo "โ†ป Running coderev ${hookType} hook..."
527
+ echo "้ˆซ?Running coderev ${hookType} hook..."
528
528
  coderev review --repo . --output markdown > /tmp/coderev-hook-report.md 2>/dev/null
529
529
  SCORE=$(grep -oP 'Score: \\K\\d+' /tmp/coderev-hook-report.md || echo 0)
530
530
  echo "Score: $SCORE/100"
531
531
  MIN_SCORE=${minScore}
532
532
  if [ "$SCORE" -lt "$MIN_SCORE" ]; then
533
- echo "โœ– Score below threshold ($MIN_SCORE). Aborting ${hookType}."
533
+ echo "้‰?Score below threshold ($MIN_SCORE). Aborting ${hookType}."
534
534
  cat /tmp/coderev-hook-report.md
535
535
  exit 1
536
536
  fi
@@ -540,21 +540,21 @@ fi
540
540
  try {
541
541
  fs.chmodSync(hookPath, '755');
542
542
  } catch {}
543
- console.log(chalk.green(`โœ” ${hookType} hook installed at ${hookPath}`));
543
+ console.log(chalk.green(`้‰?${hookType} hook installed at ${hookPath}`));
544
544
  } else if (action === 'remove') {
545
545
  if (fs.existsSync(hookPath)) {
546
546
  fs.unlinkSync(hookPath);
547
- console.log(chalk.green(`โœ” ${hookType} hook removed`));
547
+ console.log(chalk.green(`้‰?${hookType} hook removed`));
548
548
  } else {
549
549
  console.log(chalk.blue(' No hook to remove'));
550
550
  }
551
551
  } else {
552
- console.error(chalk.red('โœ– Unknown action. Use "install" or "remove".'));
552
+ console.error(chalk.red('้‰?Unknown action. Use "install" or "remove".'));
553
553
  process.exit(1);
554
554
  }
555
555
  });
556
556
 
557
- // โ”€โ”€ Init / Setup โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
557
+ // ้ˆนโ‚ฌ้ˆนโ‚ฌ Init / Setup ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ
558
558
  program
559
559
  .command('init')
560
560
  .description('Create a default coderev config file')
@@ -567,6 +567,9 @@ program
567
567
  model: 'deepseek-chat',
568
568
  temperature: 0.3,
569
569
  maxTokens: 4096,
570
+ // ๆฟ‰๎‚ขๅ†ๆตฃ็Šตๆฎ‘ API Key ้Žดๆ ญโ‚ฌๆฐณ็นƒ้œ๎ˆš๎•จ้™ๆฉ€ๅ™บ็’ๅ‰ง็–†
571
+ // apiKey: "sk-xxx",
572
+ // apiKeyEnv: "DEEPSEEK_API_KEY",
570
573
  },
571
574
  rules: {
572
575
  maxLineLength: 100,
@@ -580,7 +583,7 @@ program
580
583
  };
581
584
  const configPath = path.join(process.cwd(), '.coderevrc.json');
582
585
  fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2));
583
- console.log(chalk.green(`โœ” Default config created at ${configPath}`));
586
+ console.log(chalk.green(`้‰?Default config created at ${configPath}`));
584
587
 
585
588
  // Also create .coderevignore if it doesn't exist
586
589
  const ignorePath = path.join(process.cwd(), '.coderevignore');
@@ -597,7 +600,7 @@ dist/
597
600
  build/
598
601
  `;
599
602
  fs.writeFileSync(ignorePath, ignoreContent);
600
- console.log(chalk.green(`โœ” Default .coderevignore created at ${ignorePath}`));
603
+ console.log(chalk.green(`้‰?Default .coderevignore created at ${ignorePath}`));
601
604
  }
602
605
 
603
606
  // Also create .coderevhint if it doesn't exist
@@ -616,13 +619,13 @@ build/
616
619
  - Avoid:
617
620
  `;
618
621
  fs.writeFileSync(hintPath, hintContent);
619
- console.log(chalk.green(`โœ” Default .coderevhint created at ${hintPath}`));
622
+ console.log(chalk.green(`้‰?Default .coderevhint created at ${hintPath}`));
620
623
  }
621
624
  });
622
625
 
623
626
  program.parse(process.argv);
624
627
 
625
- // โ”€โ”€ Helpers โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
628
+ // ้ˆนโ‚ฌ้ˆนโ‚ฌ Helpers ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ้ˆนโ‚ฌ
626
629
  async function getGitDiff(repoPath, base = 'main', head) {
627
630
  const { execSync } = require('child_process');
628
631
  const args = ['git', 'diff'];
@@ -637,8 +640,8 @@ async function getGitDiff(repoPath, base = 'main', head) {
637
640
 
638
641
  function formatTerminal(result) {
639
642
  const lines = [];
640
- lines.push(chalk.bold('\n๐Ÿ“‹ Code Review Report'));
641
- lines.push('โ”'.repeat(50));
643
+ lines.push(chalk.bold('\n้ฆƒๆต Code Review Report'));
644
+ lines.push('้ˆน?.repeat(50));
642
645
 
643
646
  if (result.summary) {
644
647
  lines.push(`\n${chalk.bold('Summary:')} ${result.summary}`);
@@ -653,8 +656,8 @@ function formatTerminal(result) {
653
656
  lines.push(`\n${chalk.bold(`Issues (${result.issues.length}):`)}`);
654
657
  for (const issue of result.issues) {
655
658
  const typeLabel =
656
- issue.type === 'error' ? chalk.red('โœ–') :
657
- issue.type === 'warning' ? chalk.yellow('โš ') : chalk.blue('โ„น');
659
+ issue.type === 'error' ? chalk.red('้‰?) :
660
+ issue.type === 'warning' ? chalk.yellow('้ˆฟ?) : chalk.blue('้ˆฉ?);
658
661
  const severity = issue.severity ? ` [${issue.severity}]` : '';
659
662
  lines.push(` ${typeLabel}${severity} ${issue.message}`);
660
663
  if (issue.file) lines.push(` File: ${issue.file}`);
@@ -666,23 +669,23 @@ function formatTerminal(result) {
666
669
  if (result.suggestions && result.suggestions.length > 0) {
667
670
  lines.push(`\n${chalk.bold('Suggestions:')}`);
668
671
  for (const s of result.suggestions) {
669
- lines.push(` ๐Ÿ’ก ${s}`);
672
+ lines.push(` ้ฆƒๆŒ• ${s}`);
670
673
  }
671
674
  }
672
675
 
673
676
  if (result.praise && result.praise.length > 0) {
674
- lines.push(`\n${chalk.bold('๐Ÿ‘ Good Practices:')}`);
677
+ lines.push(`\n${chalk.bold('้ฆƒๆ†ค Good Practices:')}`);
675
678
  for (const p of result.praise) {
676
- lines.push(` โœ… ${p}`);
679
+ lines.push(` ้‰?${p}`);
677
680
  }
678
681
  }
679
682
 
680
- lines.push('\n' + 'โ”'.repeat(50));
683
+ lines.push('\n' + '้ˆน?.repeat(50));
681
684
  return lines.join('\n');
682
685
  }
683
686
 
684
687
  function formatMarkdown(result) {
685
- let md = '# ๐Ÿ“‹ Code Review Report\n\n';
688
+ let md = '# ้ฆƒๆต Code Review Report\n\n';
686
689
 
687
690
  if (result.summary) md += `**Summary:** ${result.summary}\n\n`;
688
691
  if (result.score !== undefined) md += `**Score:** ${result.score}/100\n\n`;
@@ -701,12 +704,12 @@ function formatMarkdown(result) {
701
704
 
702
705
  if (result.suggestions?.length) {
703
706
  md += `\n## Suggestions\n\n`;
704
- for (const s of result.suggestions) md += `- ๐Ÿ’ก ${s}\n`;
707
+ for (const s of result.suggestions) md += `- ้ฆƒๆŒ• ${s}\n`;
705
708
  }
706
709
 
707
710
  if (result.praise?.length) {
708
- md += `\n## ๐Ÿ‘ Good Practices\n\n`;
709
- for (const p of result.praise) md += `- โœ… ${p}\n`;
711
+ md += `\n## ้ฆƒๆ†ค Good Practices\n\n`;
712
+ for (const p of result.praise) md += `- ้‰?${p}\n`;
710
713
  }
711
714
 
712
715
  return md;
package/src/config.js CHANGED
@@ -80,8 +80,7 @@ function getApiKey(config) {
80
80
  const key = process.env[envVar];
81
81
  if (!key) {
82
82
  throw new Error(
83
- `API key not found. Set ${envVar} environment variable ` +
84
- `or add "apiKey" to your config file.`
83
+ `API key not found.`
85
84
  );
86
85
  }
87
86
  return key;