korekt-cli 0.2.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/README.md ADDED
@@ -0,0 +1,130 @@
1
+ # Korekt CLI
2
+
3
+ AI-powered code review CLI - Keep your kode korekt โœจ
4
+
5
+ `kk` integrates seamlessly with your local Git workflow to provide intelligent code reviews powered by AI.
6
+
7
+ ## Features
8
+
9
+ * **AI-Powered Analysis**: Get instant, intelligent code reviews with severity levels, categories, and actionable suggestions
10
+ * **Local Git Integration**: Works with committed changes, staged changes, and unstaged modifications
11
+ * **Ticket System Integration**: Automatically extracts ticket IDs from branch names and commit messages (Jira & Azure DevOps)
12
+ * **Beautiful Output**: Color-coded issues with severity indicators, file locations, and suggested fixes
13
+ * **Ultra-Fast**: Short command syntax (`kk`) for maximum developer efficiency
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install -g korekt-cli
19
+ ```
20
+
21
+ ## Quick Start
22
+
23
+ Configure the CLI with your API credentials:
24
+
25
+ ```bash
26
+ kk config --key YOUR_API_KEY
27
+ kk config --endpoint https://api.korekt.ai/review/local
28
+ ```
29
+
30
+ Run your first review:
31
+
32
+ ```bash
33
+ # Review committed changes against a target branch
34
+ kk review main
35
+
36
+ # Review only staged changes
37
+ kk stg
38
+
39
+ # Review only unstaged changes
40
+ kk diff
41
+
42
+ # Review all uncommitted changes (staged + unstaged)
43
+ kk all
44
+ ```
45
+
46
+ ## Usage
47
+
48
+ ### Configuration
49
+
50
+ ```bash
51
+ # Set API key
52
+ kk config --key YOUR_API_KEY
53
+
54
+ # Set API endpoint
55
+ kk config --endpoint https://api.korekt.ai/review/local
56
+
57
+ # Set default ticket system (jira or ado)
58
+ kk config --ticket-system jira
59
+
60
+ # Show current configuration
61
+ kk config --show
62
+ ```
63
+
64
+ ### Review Commands
65
+
66
+ ```bash
67
+ # Review committed changes (auto-detect base branch)
68
+ kk review
69
+
70
+ # Review against specific branch
71
+ kk review main
72
+
73
+ # Review with ticket system override
74
+ kk review main --ticket-system ado
75
+
76
+ # Review with ignored files
77
+ kk review main --ignore "*.lock" "dist/*"
78
+
79
+ # Dry run (preview payload without sending)
80
+ kk review main --dry-run
81
+
82
+ # Review staged changes only
83
+ kk stg
84
+ # Aliases: kk staged, kk cached
85
+
86
+ # Review unstaged changes only
87
+ kk diff
88
+
89
+ # Review all uncommitted changes
90
+ kk all
91
+
92
+ # Include untracked files
93
+ kk all --untracked
94
+ ```
95
+
96
+ ### Alternative Command
97
+
98
+ Both `kk` and `korekt` commands are available:
99
+
100
+ ```bash
101
+ korekt review main # Same as: kk review main
102
+ ```
103
+
104
+ ## Environment Variables
105
+
106
+ You can also configure using environment variables:
107
+
108
+ ```bash
109
+ export KOREKT_API_KEY="your-api-key"
110
+ export KOREKT_API_ENDPOINT="https://api.korekt.ai/review/local"
111
+ export KOREKT_TICKET_SYSTEM="jira"
112
+ ```
113
+
114
+ Note: Config file takes precedence over environment variables.
115
+
116
+ ## Help
117
+
118
+ For more options and detailed help:
119
+
120
+ ```bash
121
+ kk --help
122
+ kk review --help
123
+ ```
124
+
125
+ ## Development
126
+
127
+ To run tests:
128
+ ```bash
129
+ npm test
130
+ ```
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "korekt-cli",
3
+ "version": "0.2.0",
4
+ "description": "AI-powered code review CLI - Keep your kode korekt",
5
+ "main": "src/index.js",
6
+ "bin": {
7
+ "kk": "src/index.js",
8
+ "korekt": "src/index.js"
9
+ },
10
+ "type": "module",
11
+ "scripts": {
12
+ "test": "vitest",
13
+ "test:watch": "vitest --watch",
14
+ "test:coverage": "vitest --coverage"
15
+ },
16
+ "keywords": [
17
+ "code-review",
18
+ "ai",
19
+ "cli",
20
+ "git",
21
+ "korekt",
22
+ "code-quality",
23
+ "static-analysis"
24
+ ],
25
+ "author": "Vladan Djokic",
26
+ "repository": {
27
+ "type": "git",
28
+ "url": "git+https://github.com/vladan-me/korekt-cli.git"
29
+ },
30
+ "bugs": {
31
+ "url": "https://github.com/vladan-me/korekt-cli/issues"
32
+ },
33
+ "homepage": "https://korekt.ai",
34
+ "files": [
35
+ "src"
36
+ ],
37
+ "license": "UNLICENSED",
38
+ "dependencies": {
39
+ "axios": "^1.12.2",
40
+ "chalk": "^5.6.2",
41
+ "commander": "^14.0.1",
42
+ "conf": "^15.0.2",
43
+ "dotenv": "^17.2.3",
44
+ "execa": "^9.6.0",
45
+ "ora": "^9.0.0"
46
+ },
47
+ "devDependencies": {
48
+ "vitest": "^3.2.4"
49
+ }
50
+ }
package/src/config.js ADDED
@@ -0,0 +1,75 @@
1
+ import Conf from 'conf';
2
+ import dotenv from 'dotenv';
3
+
4
+ // Load .env file if it exists (quietly)
5
+ dotenv.config({ quiet: true });
6
+
7
+ // Initialize config
8
+ const config = new Conf({
9
+ projectName: 'korekt-cli',
10
+ });
11
+
12
+ /**
13
+ * Get the API key from config or environment
14
+ * Priority: 1) config store, 2) .env file
15
+ */
16
+ export function getApiKey() {
17
+ const configKey = config.get('apiKey');
18
+ if (configKey) return configKey;
19
+
20
+ return process.env.KOREKT_API_KEY || null;
21
+ }
22
+
23
+ /**
24
+ * Set the API key in config store
25
+ */
26
+ export function setApiKey(key) {
27
+ config.set('apiKey', key);
28
+ }
29
+
30
+ /**
31
+ * Get the API endpoint URL from config or environment
32
+ * Priority: 1) config store, 2) .env file
33
+ */
34
+ export function getApiEndpoint() {
35
+ const configEndpoint = config.get('apiEndpoint');
36
+ if (configEndpoint) return configEndpoint;
37
+
38
+ return process.env.KOREKT_API_ENDPOINT || null;
39
+ }
40
+
41
+ /**
42
+ * Set the API endpoint in config store
43
+ */
44
+ export function setApiEndpoint(endpoint) {
45
+ config.set('apiEndpoint', endpoint);
46
+ }
47
+
48
+ /**
49
+ * Get the ticket system from config or environment
50
+ * Priority: 1) config store, 2) .env file
51
+ */
52
+ export function getTicketSystem() {
53
+ const configTicketSystem = config.get('ticketSystem');
54
+ if (configTicketSystem) return configTicketSystem;
55
+
56
+ return process.env.KOREKT_TICKET_SYSTEM || null;
57
+ }
58
+
59
+ /**
60
+ * Set the ticket system in config store
61
+ */
62
+ export function setTicketSystem(system) {
63
+ config.set('ticketSystem', system);
64
+ }
65
+
66
+ /**
67
+ * Get all configuration
68
+ */
69
+ export function getConfig() {
70
+ return {
71
+ apiKey: getApiKey(),
72
+ apiEndpoint: getApiEndpoint(),
73
+ ticketSystem: getTicketSystem(),
74
+ };
75
+ }
@@ -0,0 +1,143 @@
1
+ import chalk from 'chalk';
2
+ import path from 'path';
3
+ import { execaSync } from 'execa';
4
+
5
+ // Emojis and colors inspired by the provided ADO script
6
+ const SEVERITY_ICONS = {
7
+ critical: '๐ŸŸฃ',
8
+ high: '๐Ÿ”ด',
9
+ medium: '๐ŸŸ ',
10
+ low: '๐ŸŸก',
11
+ };
12
+
13
+ const SEVERITY_COLORS = {
14
+ critical: chalk.magenta.bold,
15
+ high: chalk.red.bold,
16
+ medium: chalk.yellow.bold,
17
+ low: chalk.gray.bold,
18
+ };
19
+
20
+ const CATEGORY_ICONS = {
21
+ bug: '๐Ÿž',
22
+ security: '๐Ÿ›ก๏ธ',
23
+ best_practice: 'โœจ',
24
+ dependency: '๐Ÿ“ฆ',
25
+ performance: '๐Ÿš€',
26
+ rbac: '๐Ÿ”‘',
27
+ syntax: '๐Ÿ“',
28
+ clean_code: '๐Ÿงผ',
29
+ documentation: '๐Ÿ“',
30
+ test_coverage: '๐Ÿงช',
31
+ readability: '๐Ÿ“–',
32
+ default: 'โš™๏ธ', // Default icon
33
+ };
34
+
35
+ /**
36
+ * Capitalize and replace underscores for category display.
37
+ * @param {string} category
38
+ * @returns {string}
39
+ */
40
+ function formatCategory(category) {
41
+ if (!category) return '';
42
+ return category
43
+ .replace(/_/g, ' ')
44
+ .replace(/\b\w/g, char => char.toUpperCase());
45
+ }
46
+
47
+ /**
48
+ * Get the git repository root directory.
49
+ * @returns {string} - Absolute path to the git repository root
50
+ */
51
+ function getGitRoot() {
52
+ try {
53
+ const { stdout } = execaSync('git', ['rev-parse', '--show-toplevel']);
54
+ return stdout.trim();
55
+ } catch (error) {
56
+ // Fallback to current working directory if not in a git repo
57
+ return process.cwd();
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Convert a relative file path to an absolute path for better IDE integration.
63
+ * @param {string} filePath - The file path from the API response
64
+ * @returns {string} - Absolute file path
65
+ */
66
+ function toAbsolutePath(filePath) {
67
+ if (path.isAbsolute(filePath)) {
68
+ return filePath;
69
+ }
70
+ const gitRoot = getGitRoot();
71
+ return path.join(gitRoot, filePath);
72
+ }
73
+
74
+ /**
75
+ * Format and display the API response in the new, detailed style.
76
+ * @param {Object} data - The API response data
77
+ */
78
+ export function formatReviewOutput(data) {
79
+ const { review, summary } = data.analysis;
80
+
81
+ console.log(chalk.bold.blue('๐Ÿค– Automated Code Review Results\n'));
82
+
83
+ // --- Praises Section ---
84
+ if (review && review.praises && review.praises.length > 0) {
85
+ console.log(chalk.bold.magenta(`โœจ Praises (${summary.total_praises})`));
86
+ review.praises.forEach(praise => {
87
+ const categoryIcon = CATEGORY_ICONS[praise.category] || CATEGORY_ICONS.default;
88
+ const formattedCategory = formatCategory(praise.category);
89
+ const absolutePath = toAbsolutePath(praise.file_path);
90
+ console.log(` โœ… ${chalk.green.bold(formattedCategory)} in ${absolutePath}:${praise.line_number}`);
91
+ console.log(` ${praise.message}\n`);
92
+ });
93
+ }
94
+
95
+ // --- Issues Section ---
96
+ if (review && review.issues && review.issues.length > 0) {
97
+ console.log(chalk.bold.red(`โš ๏ธ Issues Found (${summary.total_issues})`));
98
+
99
+ // Severity Summary Table
100
+ console.log(chalk.underline('Severity Count:'));
101
+ const severities = ['critical', 'high', 'medium', 'low'];
102
+ severities.forEach(severity => {
103
+ const count = summary[severity] || 0;
104
+ if (count > 0) {
105
+ const icon = SEVERITY_ICONS[severity];
106
+ const color = SEVERITY_COLORS[severity];
107
+ const label = severity.charAt(0).toUpperCase() + severity.slice(1);
108
+ console.log(`${icon} ${color(label)}: ${count}`);
109
+ }
110
+ });
111
+ console.log(''); // Newline for spacing
112
+
113
+ // Issues Details
114
+ review.issues.forEach((issue, index) => {
115
+ const severityIcon = SEVERITY_ICONS[issue.severity] || 'โ“';
116
+ const severityColor = SEVERITY_COLORS[issue.severity] || chalk.white;
117
+ const categoryIcon = CATEGORY_ICONS[issue.category] || CATEGORY_ICONS.default;
118
+ const formattedCategory = formatCategory(issue.category);
119
+ const absolutePath = toAbsolutePath(issue.file_path);
120
+
121
+ console.log(
122
+ `${severityIcon} ${severityColor(
123
+ issue.severity.toUpperCase()
124
+ )} in ${absolutePath}:${issue.line_number} (${categoryIcon} ${formattedCategory})`
125
+ );
126
+ console.log(` ${issue.message}`);
127
+
128
+ if (issue.suggested_fix) {
129
+ console.log(chalk.bold('\n๐Ÿ’ก Suggested Fix:'));
130
+ // Indent the suggested fix for readability
131
+ const indentedFix = issue.suggested_fix.split('\n').map(line => ` ${line}`).join('\n');
132
+ console.log(chalk.green(indentedFix));
133
+ }
134
+
135
+ // Add separator between issues (but not after the last one)
136
+ if (index < review.issues.length - 1) {
137
+ const terminalWidth = process.stdout.columns || 80;
138
+ console.log(chalk.gray('โ”€'.repeat(terminalWidth)));
139
+ }
140
+ console.log(); // Add a blank line for spacing
141
+ });
142
+ }
143
+ }