korekt-cli 0.12.0 → 0.13.2

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/README.md CHANGED
@@ -4,17 +4,7 @@
4
4
  [![npm downloads](https://img.shields.io/npm/dm/korekt-cli.svg)](https://www.npmjs.com/package/korekt-cli)
5
5
  [![license](https://img.shields.io/npm/l/korekt-cli.svg)](https://www.npmjs.com/package/korekt-cli)
6
6
 
7
- AI-powered code review CLI - Keep your kode korekt
8
-
9
- `kk` integrates seamlessly with your local Git workflow to provide intelligent code reviews powered by AI.
10
-
11
- ## Features
12
-
13
- * **AI-Powered Analysis**: Get instant, intelligent code reviews with severity levels, categories, and actionable suggestions
14
- * **Local Git Integration**: Works with committed changes, staged changes, and unstaged modifications
15
- * **Ticket Context Enrichment**: Server-side ticket extraction from branch names and commit messages (Jira & Azure DevOps)
16
- * **Beautiful Output**: Color-coded issues with severity indicators, file locations, and suggested fixes
17
- * **Ultra-Fast**: Short command syntax (`kk`) for maximum developer efficiency
7
+ AI-powered code review from your terminal.
18
8
 
19
9
  ## Installation
20
10
 
@@ -22,112 +12,81 @@ AI-powered code review CLI - Keep your kode korekt
22
12
  npm install -g korekt-cli
23
13
  ```
24
14
 
25
- ## Quick Start
26
-
27
- Configure the CLI with your API credentials:
15
+ ## Setup
28
16
 
29
17
  ```bash
30
18
  kk config --key YOUR_API_KEY
31
- kk config --endpoint https://api.korekt.ai/api/review
32
19
  ```
33
20
 
34
- Run your first review:
35
-
36
- ```bash
37
- # Review committed changes against a target branch
38
- kk review main
39
-
40
- # Review only staged changes
41
- kk stg
42
-
43
- # Review only unstaged changes
44
- kk diff
21
+ ## Local Workflow
45
22
 
23
+ ### Review Your Changes
46
24
 
25
+ ```bash
26
+ kk review main # Review commits against main
27
+ kk stg # Review staged changes
28
+ kk diff # Review unstaged changes
47
29
  ```
48
30
 
49
- ## Usage
50
-
51
- ### Configuration
31
+ ### Choose AI Model
52
32
 
53
33
  ```bash
54
- # Set API key
55
- kk config --key YOUR_API_KEY
56
-
57
- # Set API endpoint
58
- kk config --endpoint https://api.korekt.ai/api/review
59
-
60
- # Show current configuration
61
- kk config --show
34
+ kk review -m # Interactive model picker
35
+ kk review -m gemini-3-flash-preview # Direct selection
62
36
  ```
63
37
 
64
- ### Review Commands
38
+ Available models (ranked by recommendation):
65
39
 
66
- ```bash
67
- # Review committed changes (auto-detect base branch)
68
- kk review
40
+ 1. **gemini-3-flash-preview** - Most efficient, recommended for daily use
41
+ 2. **gemini-3-pro-preview** - Best quality for complex reviews
42
+ 3. **gemini-2.5-pro** - High quality alternative
43
+ 4. **gemini-2.5-flash** - Legacy, avoid
69
44
 
70
- # Review against specific branch
71
- kk review main
45
+ ### Ignore Files
72
46
 
73
- # Review with ignored files
47
+ ```bash
74
48
  kk review main --ignore "*.lock" "dist/*"
49
+ ```
75
50
 
76
- # Dry run (preview payload without sending)
77
- kk review main --dry-run
51
+ ## CI/CD Integration
78
52
 
79
- # Output JSON for CI/CD integration
80
- kk review main --json
53
+ ### Post to Pull Request
81
54
 
82
- # Review staged changes only
83
- kk stg
84
- # Aliases: kk staged, kk cached
55
+ ```bash
56
+ kk review --comment # Auto-posts findings to PR
57
+ ```
85
58
 
86
- # Review unstaged changes only
87
- kk diff
59
+ Works with GitHub Actions, Azure Pipelines, and Bitbucket Pipelines.
88
60
 
89
- # JSON output works with all review commands
90
- kk stg --json
91
- kk diff --json
61
+ ### Post to Ticket
62
+
63
+ ```bash
64
+ kk review --post-ticket # Posts findings to linked Jira/Azure ticket
92
65
  ```
93
66
 
94
- ### Alternative Command
67
+ Ticket IDs are automatically extracted from branch names and commit messages.
95
68
 
96
- Both `kk` and `korekt` commands are available:
69
+ ### JSON Output
97
70
 
98
71
  ```bash
99
- korekt review main # Same as: kk review main
72
+ kk review main --json # Machine-readable output
100
73
  ```
101
74
 
102
75
  ## Environment Variables
103
76
 
104
- You can also configure using environment variables:
105
-
106
77
  ```bash
107
78
  export KOREKT_API_KEY="your-api-key"
108
- export KOREKT_API_ENDPOINT="https://api.korekt.ai/api/review"
109
79
  ```
110
80
 
111
- Note: Config file takes precedence over environment variables.
81
+ Alternative to `kk config --key`. Config file takes precedence.
112
82
 
113
83
  ## Help
114
84
 
115
- For more options and detailed help:
116
-
117
85
  ```bash
118
86
  kk --help
119
87
  kk review --help
120
88
  ```
121
89
 
122
- ## Development
123
-
124
- To run tests:
125
- ```bash
126
- npm test
127
- ```
128
-
129
90
  ## License
130
91
 
131
- MIT © [Vladan Djokic](https://korekt.ai)
132
-
133
- See [LICENSE](./LICENSE) for details.
92
+ MIT - See [LICENSE](./LICENSE) for details.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "korekt-cli",
3
- "version": "0.12.0",
3
+ "version": "0.13.2",
4
4
  "description": "AI-powered code review CLI - Keep your kode korekt",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/config.js CHANGED
@@ -44,13 +44,3 @@ export function getApiEndpoint() {
44
44
  export function setApiEndpoint(endpoint) {
45
45
  config.set('apiEndpoint', endpoint);
46
46
  }
47
-
48
- /**
49
- * Get all configuration
50
- */
51
- export function getConfig() {
52
- return {
53
- apiKey: getApiKey(),
54
- apiEndpoint: getApiEndpoint(),
55
- };
56
- }
package/src/index.js CHANGED
@@ -72,6 +72,24 @@ async function confirmAction(message) {
72
72
  });
73
73
  }
74
74
 
75
+ /**
76
+ * Handle skipped response from API (when integration mode prevents CLI review)
77
+ * @param {Object} response - Axios response object
78
+ * @param {Object} options - Command options (json flag, etc.)
79
+ * @param {Object} spinner - Ora spinner instance
80
+ * @returns {boolean} - True if response was skipped, false otherwise
81
+ */
82
+ export function handleSkippedResponse(response, options, spinner) {
83
+ if (response.data.skipped) {
84
+ spinner.info(response.data.message || 'Review skipped.');
85
+ if (options.json) {
86
+ output(JSON.stringify(response.data, null, 2));
87
+ }
88
+ return true;
89
+ }
90
+ return false;
91
+ }
92
+
75
93
  /**
76
94
  * Available Gemini models for code review
77
95
  */
@@ -339,6 +357,12 @@ program
339
357
 
340
358
  clearInterval(timer);
341
359
  const elapsed = Math.floor((Date.now() - startTime) / 1000);
360
+
361
+ // Handle skipped response (integration mode prevents CLI review)
362
+ if (handleSkippedResponse(response, options, spinner)) {
363
+ return;
364
+ }
365
+
342
366
  spinner.succeed(`Review completed in ${elapsed}s!`);
343
367
 
344
368
  // Handle --comment flag: post results to PR
@@ -523,6 +547,12 @@ async function reviewUncommitted(mode, options) {
523
547
 
524
548
  clearInterval(timer);
525
549
  const elapsed = Math.floor((Date.now() - startTime) / 1000);
550
+
551
+ // Handle skipped response (integration mode prevents CLI review)
552
+ if (handleSkippedResponse(response, options, spinner)) {
553
+ return;
554
+ }
555
+
526
556
  spinner.succeed(`Review completed in ${elapsed}s!`);
527
557
 
528
558
  // Output results to stdout
package/src/index.test.js CHANGED
@@ -1,5 +1,11 @@
1
1
  import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
- import { truncateFileData, formatErrorOutput, detectCIProvider, getPrUrl } from './index.js';
2
+ import {
3
+ truncateFileData,
4
+ formatErrorOutput,
5
+ detectCIProvider,
6
+ getPrUrl,
7
+ handleSkippedResponse,
8
+ } from './index.js';
3
9
 
4
10
  describe('CLI JSON output mode', () => {
5
11
  let stdoutSpy;
@@ -549,6 +555,114 @@ describe('--model flag behavior', () => {
549
555
  });
550
556
  });
551
557
 
558
+ describe('skipped response handling', () => {
559
+ let stdoutSpy;
560
+
561
+ beforeEach(() => {
562
+ stdoutSpy = vi.spyOn(process.stdout, 'write').mockImplementation(() => true);
563
+ });
564
+
565
+ afterEach(() => {
566
+ vi.restoreAllMocks();
567
+ });
568
+
569
+ it('should return true and call spinner.info when response is skipped', () => {
570
+ const response = {
571
+ data: {
572
+ skipped: true,
573
+ reason: 'webhook_mode_active',
574
+ message: 'Review skipped due to webhook mode.',
575
+ },
576
+ };
577
+ const options = { json: false };
578
+ const spinner = { info: vi.fn() };
579
+
580
+ const result = handleSkippedResponse(response, options, spinner);
581
+
582
+ expect(result).toBe(true);
583
+ expect(spinner.info).toHaveBeenCalledWith('Review skipped due to webhook mode.');
584
+ });
585
+
586
+ it('should return false when response is not skipped', () => {
587
+ const response = {
588
+ data: {
589
+ review: { issues: [], praises: [] },
590
+ summary: { total_issues: 0 },
591
+ },
592
+ };
593
+ const options = { json: false };
594
+ const spinner = { info: vi.fn() };
595
+
596
+ const result = handleSkippedResponse(response, options, spinner);
597
+
598
+ expect(result).toBe(false);
599
+ expect(spinner.info).not.toHaveBeenCalled();
600
+ });
601
+
602
+ it('should output JSON to stdout when json option is true and response is skipped', () => {
603
+ const response = {
604
+ data: {
605
+ skipped: true,
606
+ reason: 'local_reviews_disabled',
607
+ message: 'Local reviews disabled.',
608
+ },
609
+ };
610
+ const options = { json: true };
611
+ const spinner = { info: vi.fn() };
612
+
613
+ handleSkippedResponse(response, options, spinner);
614
+
615
+ expect(stdoutSpy).toHaveBeenCalledWith(JSON.stringify(response.data, null, 2) + '\n');
616
+ });
617
+
618
+ it('should not output JSON when json option is false', () => {
619
+ const response = {
620
+ data: {
621
+ skipped: true,
622
+ reason: 'reviews_disabled',
623
+ message: 'Reviews disabled.',
624
+ },
625
+ };
626
+ const options = { json: false };
627
+ const spinner = { info: vi.fn() };
628
+
629
+ handleSkippedResponse(response, options, spinner);
630
+
631
+ expect(stdoutSpy).not.toHaveBeenCalled();
632
+ });
633
+
634
+ it('should use default message when response message is empty', () => {
635
+ const response = {
636
+ data: {
637
+ skipped: true,
638
+ reason: 'webhook_mode_active',
639
+ },
640
+ };
641
+ const options = { json: false };
642
+ const spinner = { info: vi.fn() };
643
+
644
+ handleSkippedResponse(response, options, spinner);
645
+
646
+ expect(spinner.info).toHaveBeenCalledWith('Review skipped.');
647
+ });
648
+
649
+ it('should handle all skip reason types', () => {
650
+ const reasons = ['webhook_mode_active', 'reviews_disabled', 'local_reviews_disabled'];
651
+ const spinner = { info: vi.fn() };
652
+
653
+ reasons.forEach((reason) => {
654
+ const response = {
655
+ data: { skipped: true, reason, message: `Skipped: ${reason}` },
656
+ };
657
+
658
+ const result = handleSkippedResponse(response, { json: false }, spinner);
659
+ expect(result).toBe(true);
660
+ });
661
+
662
+ expect(spinner.info).toHaveBeenCalledTimes(3);
663
+ });
664
+ });
665
+
552
666
  describe('getPrUrl', () => {
553
667
  const originalEnv = process.env;
554
668