korekt-cli 0.6.0 ā 0.7.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 +5 -20
- package/package.json +1 -1
- package/src/config.js +1 -20
- package/src/git-logic.js +7 -63
- package/src/git-logic.test.js +5 -48
- package/src/index.js +7 -86
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ AI-powered code review CLI - Keep your kode korekt
|
|
|
12
12
|
|
|
13
13
|
* **AI-Powered Analysis**: Get instant, intelligent code reviews with severity levels, categories, and actionable suggestions
|
|
14
14
|
* **Local Git Integration**: Works with committed changes, staged changes, and unstaged modifications
|
|
15
|
-
* **Ticket
|
|
15
|
+
* **Ticket Context Enrichment**: Server-side ticket extraction from branch names and commit messages (Jira & Azure DevOps)
|
|
16
16
|
* **Beautiful Output**: Color-coded issues with severity indicators, file locations, and suggested fixes
|
|
17
17
|
* **Ultra-Fast**: Short command syntax (`kk`) for maximum developer efficiency
|
|
18
18
|
|
|
@@ -28,7 +28,7 @@ Configure the CLI with your API credentials:
|
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
30
|
kk config --key YOUR_API_KEY
|
|
31
|
-
kk config --endpoint https://api.korekt.ai/review
|
|
31
|
+
kk config --endpoint https://api.korekt.ai/api/review
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
Run your first review:
|
|
@@ -43,8 +43,7 @@ kk stg
|
|
|
43
43
|
# Review only unstaged changes
|
|
44
44
|
kk diff
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
kk all
|
|
46
|
+
|
|
48
47
|
```
|
|
49
48
|
|
|
50
49
|
## Usage
|
|
@@ -56,10 +55,7 @@ kk all
|
|
|
56
55
|
kk config --key YOUR_API_KEY
|
|
57
56
|
|
|
58
57
|
# Set API endpoint
|
|
59
|
-
kk config --endpoint https://api.korekt.ai/review
|
|
60
|
-
|
|
61
|
-
# Set default ticket system (jira or ado)
|
|
62
|
-
kk config --ticket-system jira
|
|
58
|
+
kk config --endpoint https://api.korekt.ai/api/review
|
|
63
59
|
|
|
64
60
|
# Show current configuration
|
|
65
61
|
kk config --show
|
|
@@ -74,9 +70,6 @@ kk review
|
|
|
74
70
|
# Review against specific branch
|
|
75
71
|
kk review main
|
|
76
72
|
|
|
77
|
-
# Review with ticket system override
|
|
78
|
-
kk review main --ticket-system ado
|
|
79
|
-
|
|
80
73
|
# Review with ignored files
|
|
81
74
|
kk review main --ignore "*.lock" "dist/*"
|
|
82
75
|
|
|
@@ -93,16 +86,9 @@ kk stg
|
|
|
93
86
|
# Review unstaged changes only
|
|
94
87
|
kk diff
|
|
95
88
|
|
|
96
|
-
# Review all uncommitted changes
|
|
97
|
-
kk all
|
|
98
|
-
|
|
99
|
-
# Include untracked files
|
|
100
|
-
kk all --untracked
|
|
101
|
-
|
|
102
89
|
# JSON output works with all review commands
|
|
103
90
|
kk stg --json
|
|
104
91
|
kk diff --json
|
|
105
|
-
kk all --json
|
|
106
92
|
```
|
|
107
93
|
|
|
108
94
|
### Alternative Command
|
|
@@ -119,8 +105,7 @@ You can also configure using environment variables:
|
|
|
119
105
|
|
|
120
106
|
```bash
|
|
121
107
|
export KOREKT_API_KEY="your-api-key"
|
|
122
|
-
export KOREKT_API_ENDPOINT="https://api.korekt.ai/review
|
|
123
|
-
export KOREKT_TICKET_SYSTEM="jira"
|
|
108
|
+
export KOREKT_API_ENDPOINT="https://api.korekt.ai/api/review"
|
|
124
109
|
```
|
|
125
110
|
|
|
126
111
|
Note: Config file takes precedence over environment variables.
|
package/package.json
CHANGED
package/src/config.js
CHANGED
|
@@ -35,7 +35,7 @@ export function getApiEndpoint() {
|
|
|
35
35
|
const configEndpoint = config.get('apiEndpoint');
|
|
36
36
|
if (configEndpoint) return configEndpoint;
|
|
37
37
|
|
|
38
|
-
return process.env.KOREKT_API_ENDPOINT || 'https://api.korekt.ai/api/review
|
|
38
|
+
return process.env.KOREKT_API_ENDPOINT || 'https://api.korekt.ai/api/review';
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/**
|
|
@@ -45,24 +45,6 @@ export function setApiEndpoint(endpoint) {
|
|
|
45
45
|
config.set('apiEndpoint', endpoint);
|
|
46
46
|
}
|
|
47
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
48
|
/**
|
|
67
49
|
* Get all configuration
|
|
68
50
|
*/
|
|
@@ -70,6 +52,5 @@ export function getConfig() {
|
|
|
70
52
|
return {
|
|
71
53
|
apiKey: getApiKey(),
|
|
72
54
|
apiEndpoint: getApiEndpoint(),
|
|
73
|
-
ticketSystem: getTicketSystem(),
|
|
74
55
|
};
|
|
75
56
|
}
|
package/src/git-logic.js
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { execa } from 'execa';
|
|
2
2
|
import chalk from 'chalk';
|
|
3
|
-
import fs from 'fs';
|
|
4
|
-
import path from 'path';
|
|
5
3
|
|
|
6
4
|
/**
|
|
7
5
|
* Truncate content to a maximum number of lines using "head and tail".
|
|
@@ -136,16 +134,11 @@ export function parseNameStatus(output) {
|
|
|
136
134
|
}
|
|
137
135
|
|
|
138
136
|
/**
|
|
139
|
-
* Analyze uncommitted changes (staged
|
|
140
|
-
* @param {string} mode - 'staged'
|
|
141
|
-
* @param {string|null} ticketSystem - The ticket system to use (jira or ado), or null to skip ticket extraction
|
|
137
|
+
* Analyze uncommitted changes (staged or unstaged)
|
|
138
|
+
* @param {string} mode - 'staged' or 'unstaged'
|
|
142
139
|
* @returns {Object|null} - The payload object ready for API submission, or null on error
|
|
143
140
|
*/
|
|
144
|
-
export async function runUncommittedReview(
|
|
145
|
-
mode = 'all',
|
|
146
|
-
_ticketSystem = null,
|
|
147
|
-
includeUntracked = false
|
|
148
|
-
) {
|
|
141
|
+
export async function runUncommittedReview(mode = 'unstaged') {
|
|
149
142
|
try {
|
|
150
143
|
// 1. Get Repo URL, current branch name, and repository root
|
|
151
144
|
const { stdout: repoUrl } = await execa('git', ['remote', 'get-url', 'origin']);
|
|
@@ -167,67 +160,23 @@ export async function runUncommittedReview(
|
|
|
167
160
|
if (mode === 'staged') {
|
|
168
161
|
nameStatusOutput = await git('diff', '--cached', '--name-status');
|
|
169
162
|
console.error(chalk.gray('Analyzing staged changes...'));
|
|
170
|
-
} else
|
|
163
|
+
} else {
|
|
171
164
|
nameStatusOutput = await git('diff', '--name-status');
|
|
172
165
|
console.error(chalk.gray('Analyzing unstaged changes...'));
|
|
173
|
-
} else {
|
|
174
|
-
// mode === 'all': combine staged and unstaged
|
|
175
|
-
const staged = await git('diff', '--cached', '--name-status');
|
|
176
|
-
const unstaged = await git('diff', '--name-status');
|
|
177
|
-
nameStatusOutput = [staged, unstaged].filter(Boolean).join('\n');
|
|
178
|
-
console.error(chalk.gray('Analyzing all uncommitted changes...'));
|
|
179
166
|
}
|
|
180
167
|
|
|
181
168
|
const fileList = parseNameStatus(nameStatusOutput);
|
|
182
169
|
const changedFiles = [];
|
|
183
170
|
|
|
184
|
-
|
|
185
|
-
if (includeUntracked) {
|
|
186
|
-
console.error(chalk.gray('Analyzing untracked files...'));
|
|
187
|
-
const untrackedFilesOutput = await git('ls-files', '--others', '--exclude-standard');
|
|
188
|
-
const untrackedFiles = untrackedFilesOutput.split('\n').filter(Boolean);
|
|
189
|
-
|
|
190
|
-
for (const file of untrackedFiles) {
|
|
191
|
-
const fullPath = path.join(repoRootPath, file);
|
|
192
|
-
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
193
|
-
const diff = content
|
|
194
|
-
.split('\n')
|
|
195
|
-
.map((line) => `+${line}`)
|
|
196
|
-
.join('\n');
|
|
197
|
-
changedFiles.push({
|
|
198
|
-
path: file,
|
|
199
|
-
status: 'A', // Untracked files are always additions
|
|
200
|
-
diff: diff,
|
|
201
|
-
content: '', // No old content
|
|
202
|
-
});
|
|
203
|
-
// Add to fileList to prevent duplication if it's also in nameStatusOutput (edge case)
|
|
204
|
-
fileList.push({ status: 'A', path: file, oldPath: file });
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
// Deduplicate file list before processing diffs
|
|
209
|
-
const processedPaths = new Set(changedFiles.map((f) => f.path));
|
|
210
|
-
const uniqueFileList = fileList.filter((file) => !processedPaths.has(file.path));
|
|
211
|
-
|
|
212
|
-
for (const file of uniqueFileList) {
|
|
171
|
+
for (const file of fileList) {
|
|
213
172
|
const { status, path, oldPath } = file;
|
|
214
173
|
|
|
215
174
|
// Get diff for this file
|
|
216
175
|
let diff;
|
|
217
176
|
if (mode === 'staged') {
|
|
218
177
|
diff = await git('diff', '--cached', '-U15', '--', path);
|
|
219
|
-
} else if (mode === 'unstaged') {
|
|
220
|
-
diff = await git('diff', '-U15', '--', path);
|
|
221
178
|
} else {
|
|
222
|
-
|
|
223
|
-
try {
|
|
224
|
-
diff = await git('diff', '--cached', '-U15', '--', path);
|
|
225
|
-
if (!diff) {
|
|
226
|
-
diff = await git('diff', '-U15', '--', path);
|
|
227
|
-
}
|
|
228
|
-
} catch {
|
|
229
|
-
diff = await git('diff', '-U15', '--', path);
|
|
230
|
-
}
|
|
179
|
+
diff = await git('diff', '-U15', '--', path);
|
|
231
180
|
}
|
|
232
181
|
|
|
233
182
|
// Get current content from HEAD (before changes)
|
|
@@ -332,15 +281,10 @@ export async function getContributors(diffRange, repoRootPath) {
|
|
|
332
281
|
/**
|
|
333
282
|
* Main function to analyze local git changes and prepare review payload
|
|
334
283
|
* @param {string|null} targetBranch - The branch to compare against. If null, uses git reflog to find fork point.
|
|
335
|
-
* @param {string|null} ticketSystem - The ticket system to use (jira or ado), or null to skip ticket extraction
|
|
336
284
|
* @param {string[]|null} ignorePatterns - Array of glob patterns to ignore files
|
|
337
285
|
* @returns {Object|null} - The payload object ready for API submission, or null on error
|
|
338
286
|
*/
|
|
339
|
-
export async function runLocalReview(
|
|
340
|
-
targetBranch = null,
|
|
341
|
-
_ticketSystem = null,
|
|
342
|
-
ignorePatterns = null
|
|
343
|
-
) {
|
|
287
|
+
export async function runLocalReview(targetBranch = null, ignorePatterns = null) {
|
|
344
288
|
try {
|
|
345
289
|
// 1. Get Repo URL, current branch name, and repository root
|
|
346
290
|
const { stdout: repoUrl } = await execa('git', ['remote', 'get-url', 'origin']);
|
package/src/git-logic.test.js
CHANGED
|
@@ -83,7 +83,7 @@ describe('runUncommittedReview', () => {
|
|
|
83
83
|
throw new Error(`Unmocked command: ${command}`);
|
|
84
84
|
});
|
|
85
85
|
|
|
86
|
-
const result = await runUncommittedReview('staged'
|
|
86
|
+
const result = await runUncommittedReview('staged');
|
|
87
87
|
|
|
88
88
|
expect(result).toBeDefined();
|
|
89
89
|
expect(result.repo_url).toBe('https://github.com/user/repo'); // Normalized (no .git)
|
|
@@ -120,56 +120,13 @@ describe('runUncommittedReview', () => {
|
|
|
120
120
|
throw new Error(`Unmocked command: ${command}`);
|
|
121
121
|
});
|
|
122
122
|
|
|
123
|
-
const result = await runUncommittedReview('unstaged'
|
|
123
|
+
const result = await runUncommittedReview('unstaged');
|
|
124
124
|
|
|
125
125
|
expect(result).toBeDefined();
|
|
126
126
|
expect(result.source_branch).toBe('feature-branch');
|
|
127
127
|
expect(result.changed_files).toHaveLength(1);
|
|
128
128
|
});
|
|
129
129
|
|
|
130
|
-
it('should analyze all uncommitted changes', async () => {
|
|
131
|
-
vi.mocked(execa).mockImplementation(async (cmd, args) => {
|
|
132
|
-
const command = [cmd, ...args].join(' ');
|
|
133
|
-
|
|
134
|
-
if (command.includes('remote get-url origin')) {
|
|
135
|
-
return { stdout: 'https://github.com/user/repo.git' };
|
|
136
|
-
}
|
|
137
|
-
if (command.includes('rev-parse --abbrev-ref HEAD')) {
|
|
138
|
-
return { stdout: 'feature-branch' };
|
|
139
|
-
}
|
|
140
|
-
if (command.includes('rev-parse --show-toplevel')) {
|
|
141
|
-
return { stdout: '/fake/repo/path' };
|
|
142
|
-
}
|
|
143
|
-
if (command.includes('diff --cached --name-status')) {
|
|
144
|
-
return { stdout: 'M\tstaged.js' };
|
|
145
|
-
}
|
|
146
|
-
if (command === 'git diff --name-status') {
|
|
147
|
-
return { stdout: 'M\tunstaged.js' };
|
|
148
|
-
}
|
|
149
|
-
if (command.includes('diff --cached -U15 -- staged.js')) {
|
|
150
|
-
return { stdout: 'diff staged' };
|
|
151
|
-
}
|
|
152
|
-
if (command.includes('diff -U15 -- unstaged.js')) {
|
|
153
|
-
return { stdout: 'diff unstaged' };
|
|
154
|
-
}
|
|
155
|
-
if (command.includes('show HEAD:staged.js')) {
|
|
156
|
-
return { stdout: 'staged old content' };
|
|
157
|
-
}
|
|
158
|
-
if (command.includes('show HEAD:unstaged.js')) {
|
|
159
|
-
return { stdout: 'unstaged old content' };
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
throw new Error(`Unmocked command: ${command}`);
|
|
163
|
-
});
|
|
164
|
-
|
|
165
|
-
const result = await runUncommittedReview('all', null);
|
|
166
|
-
|
|
167
|
-
expect(result).toBeDefined();
|
|
168
|
-
expect(result.changed_files).toHaveLength(2);
|
|
169
|
-
expect(result.changed_files[0].path).toBe('staged.js');
|
|
170
|
-
expect(result.changed_files[1].path).toBe('unstaged.js');
|
|
171
|
-
});
|
|
172
|
-
|
|
173
130
|
it('should return null when no changes found', async () => {
|
|
174
131
|
vi.mocked(execa).mockImplementation(async (cmd, args) => {
|
|
175
132
|
const command = [cmd, ...args].join(' ');
|
|
@@ -193,7 +150,7 @@ describe('runUncommittedReview', () => {
|
|
|
193
150
|
throw new Error(`Unmocked command: ${command}`);
|
|
194
151
|
});
|
|
195
152
|
|
|
196
|
-
const result = await runUncommittedReview('
|
|
153
|
+
const result = await runUncommittedReview('staged');
|
|
197
154
|
|
|
198
155
|
expect(result).toBeNull();
|
|
199
156
|
});
|
|
@@ -347,7 +304,7 @@ describe('runLocalReview - fork point detection', () => {
|
|
|
347
304
|
throw new Error(`Unmocked command: ${command}`);
|
|
348
305
|
});
|
|
349
306
|
|
|
350
|
-
const result = await runLocalReview(null
|
|
307
|
+
const result = await runLocalReview(null);
|
|
351
308
|
|
|
352
309
|
expect(result).toBeDefined();
|
|
353
310
|
expect(result.source_branch).toBe('feature-branch');
|
|
@@ -397,7 +354,7 @@ describe('runLocalReview - fork point detection', () => {
|
|
|
397
354
|
throw new Error(`Unmocked command: ${command}`);
|
|
398
355
|
});
|
|
399
356
|
|
|
400
|
-
const result = await runLocalReview('main'
|
|
357
|
+
const result = await runLocalReview('main');
|
|
401
358
|
|
|
402
359
|
expect(result).toBeDefined();
|
|
403
360
|
|
package/src/index.js
CHANGED
|
@@ -10,14 +10,7 @@ import { readFileSync } from 'fs';
|
|
|
10
10
|
import { join, dirname } from 'path';
|
|
11
11
|
import { fileURLToPath } from 'url';
|
|
12
12
|
import { runLocalReview } from './git-logic.js';
|
|
13
|
-
import {
|
|
14
|
-
getApiKey,
|
|
15
|
-
setApiKey,
|
|
16
|
-
getApiEndpoint,
|
|
17
|
-
setApiEndpoint,
|
|
18
|
-
getTicketSystem,
|
|
19
|
-
setTicketSystem,
|
|
20
|
-
} from './config.js';
|
|
13
|
+
import { getApiKey, setApiKey, getApiEndpoint, setApiEndpoint } from './config.js';
|
|
21
14
|
import { formatReviewOutput } from './formatter.js';
|
|
22
15
|
|
|
23
16
|
const require = createRequire(import.meta.url);
|
|
@@ -99,18 +92,15 @@ Examples:
|
|
|
99
92
|
$ kk review main Review changes against main branch
|
|
100
93
|
$ kk stg --dry-run Preview staged changes review
|
|
101
94
|
$ kk diff Review unstaged changes
|
|
102
|
-
$ kk all Review all uncommitted changes
|
|
103
95
|
$ kk review main --json Output raw JSON (for CI/CD integration)
|
|
104
96
|
|
|
105
97
|
Common Options:
|
|
106
98
|
--dry-run Show payload without sending to API
|
|
107
99
|
--json Output raw API response as JSON
|
|
108
|
-
--ticket-system <system> Use specific ticket system (jira or ado)
|
|
109
100
|
|
|
110
101
|
Configuration:
|
|
111
102
|
$ kk config --key YOUR_KEY
|
|
112
|
-
$ kk config --endpoint https://api.korekt.ai/review
|
|
113
|
-
$ kk config --ticket-system ado
|
|
103
|
+
$ kk config --endpoint https://api.korekt.ai/api/review
|
|
114
104
|
|
|
115
105
|
CI/CD Integration:
|
|
116
106
|
$ kk get-script github Output GitHub Actions integration script
|
|
@@ -126,7 +116,6 @@ program
|
|
|
126
116
|
'[target-branch]',
|
|
127
117
|
'The branch to compare against (e.g., main, develop). If not specified, auto-detects fork point.'
|
|
128
118
|
)
|
|
129
|
-
.option('--ticket-system <system>', 'Ticket system to use (jira or ado)')
|
|
130
119
|
.option('--dry-run', 'Show payload without sending to API')
|
|
131
120
|
.option(
|
|
132
121
|
'--ignore <patterns...>',
|
|
@@ -153,30 +142,14 @@ program
|
|
|
153
142
|
process.exit(1);
|
|
154
143
|
}
|
|
155
144
|
|
|
156
|
-
// Determine ticket system to use (or null if not configured)
|
|
157
|
-
const ticketSystem = options.ticketSystem || getTicketSystem() || null;
|
|
158
|
-
|
|
159
|
-
// Validate ticket system
|
|
160
|
-
if (ticketSystem && !['jira', 'ado'].includes(ticketSystem.toLowerCase())) {
|
|
161
|
-
log(chalk.red(`Invalid ticket system: ${ticketSystem}`));
|
|
162
|
-
log(chalk.gray('Valid options: jira, ado'));
|
|
163
|
-
process.exit(1);
|
|
164
|
-
}
|
|
165
|
-
|
|
166
145
|
// Gather all data using our git logic module
|
|
167
|
-
const payload = await runLocalReview(targetBranch,
|
|
146
|
+
const payload = await runLocalReview(targetBranch, options.ignore);
|
|
168
147
|
|
|
169
148
|
if (!payload) {
|
|
170
149
|
log(chalk.red('Could not proceed with review due to errors during analysis.'));
|
|
171
150
|
process.exit(1);
|
|
172
151
|
}
|
|
173
152
|
|
|
174
|
-
// Add ticket system to payload if specified
|
|
175
|
-
if (ticketSystem) {
|
|
176
|
-
payload.ticket_system = ticketSystem;
|
|
177
|
-
log(chalk.gray(`Using ticket system: ${ticketSystem}`));
|
|
178
|
-
}
|
|
179
|
-
|
|
180
153
|
// If dry-run, just show the payload and exit
|
|
181
154
|
if (options.dryRun) {
|
|
182
155
|
log(chalk.yellow('\nš Dry Run - Payload that would be sent:\n'));
|
|
@@ -276,7 +249,6 @@ program
|
|
|
276
249
|
.command('review-staged')
|
|
277
250
|
.aliases(['stg', 'staged', 'cached'])
|
|
278
251
|
.description('Review staged changes (git diff --cached)')
|
|
279
|
-
.option('--ticket-system <system>', 'Ticket system to use (jira or ado)')
|
|
280
252
|
.option('--dry-run', 'Show payload without sending to API')
|
|
281
253
|
.option('--json', 'Output raw API response as JSON')
|
|
282
254
|
.action(async (options) => {
|
|
@@ -288,28 +260,13 @@ program
|
|
|
288
260
|
.command('review-unstaged')
|
|
289
261
|
.alias('diff')
|
|
290
262
|
.description('Review unstaged changes (git diff)')
|
|
291
|
-
.option('--ticket-system <system>', 'Ticket system to use (jira or ado)')
|
|
292
263
|
.option('--dry-run', 'Show payload without sending to API')
|
|
293
|
-
.option('--untracked', 'Include untracked files in the review')
|
|
294
264
|
.option('--json', 'Output raw API response as JSON')
|
|
295
265
|
.action(async (options) => {
|
|
296
266
|
log(chalk.blue.bold('š Reviewing unstaged changes...'));
|
|
297
267
|
await reviewUncommitted('unstaged', options);
|
|
298
268
|
});
|
|
299
269
|
|
|
300
|
-
program
|
|
301
|
-
.command('review-all-uncommitted')
|
|
302
|
-
.alias('all')
|
|
303
|
-
.description('Review all uncommitted changes (staged + unstaged)')
|
|
304
|
-
.option('--ticket-system <system>', 'Ticket system to use (jira or ado)')
|
|
305
|
-
.option('--dry-run', 'Show payload without sending to API')
|
|
306
|
-
.option('--untracked', 'Include untracked files in the review')
|
|
307
|
-
.option('--json', 'Output raw API response as JSON')
|
|
308
|
-
.action(async (options) => {
|
|
309
|
-
log(chalk.blue.bold('š Reviewing all uncommitted changes...'));
|
|
310
|
-
await reviewUncommitted('all', options);
|
|
311
|
-
});
|
|
312
|
-
|
|
313
270
|
async function reviewUncommitted(mode, options) {
|
|
314
271
|
const apiKey = getApiKey();
|
|
315
272
|
if (!apiKey) {
|
|
@@ -325,27 +282,14 @@ async function reviewUncommitted(mode, options) {
|
|
|
325
282
|
process.exit(1);
|
|
326
283
|
}
|
|
327
284
|
|
|
328
|
-
const ticketSystem = options.ticketSystem || getTicketSystem() || null;
|
|
329
|
-
|
|
330
|
-
if (ticketSystem && !['jira', 'ado'].includes(ticketSystem.toLowerCase())) {
|
|
331
|
-
log(chalk.red(`Invalid ticket system: ${ticketSystem}`));
|
|
332
|
-
log(chalk.gray('Valid options: jira, ado'));
|
|
333
|
-
process.exit(1);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
285
|
const { runUncommittedReview } = await import('./git-logic.js');
|
|
337
|
-
const payload = await runUncommittedReview(mode
|
|
286
|
+
const payload = await runUncommittedReview(mode);
|
|
338
287
|
|
|
339
288
|
if (!payload) {
|
|
340
289
|
log(chalk.red('No changes found or error occurred during analysis.'));
|
|
341
290
|
process.exit(1);
|
|
342
291
|
}
|
|
343
292
|
|
|
344
|
-
if (ticketSystem) {
|
|
345
|
-
payload.ticket_system = ticketSystem;
|
|
346
|
-
log(chalk.gray(`Using ticket system: ${ticketSystem}`));
|
|
347
|
-
}
|
|
348
|
-
|
|
349
293
|
if (options.dryRun) {
|
|
350
294
|
log(chalk.yellow('\nš Dry Run - Payload that would be sent:\n'));
|
|
351
295
|
|
|
@@ -440,22 +384,17 @@ program
|
|
|
440
384
|
.description('Configure API settings')
|
|
441
385
|
.option('--key <key>', 'Your API key')
|
|
442
386
|
.option('--endpoint <endpoint>', 'Your API endpoint URL')
|
|
443
|
-
.option('--ticket-system <system>', 'Ticket system (jira, ado)')
|
|
444
387
|
.option('--show', 'Show current configuration')
|
|
445
388
|
.action((options) => {
|
|
446
389
|
// Show current config if --show flag is used
|
|
447
390
|
if (options.show) {
|
|
448
391
|
const apiKey = getApiKey();
|
|
449
392
|
const apiEndpoint = getApiEndpoint();
|
|
450
|
-
const ticketSystem = getTicketSystem();
|
|
451
393
|
|
|
452
394
|
console.log(chalk.bold('\nCurrent Configuration:\n'));
|
|
453
395
|
console.log(` API Key: ${apiKey ? chalk.green('ā Set') : chalk.red('ā Not set')}`);
|
|
454
396
|
console.log(
|
|
455
|
-
` API Endpoint: ${apiEndpoint ? chalk.cyan(apiEndpoint) : chalk.red('ā Not set')}`
|
|
456
|
-
);
|
|
457
|
-
console.log(
|
|
458
|
-
` Ticket System: ${ticketSystem ? chalk.cyan(ticketSystem) : chalk.gray('Not configured')}\n`
|
|
397
|
+
` API Endpoint: ${apiEndpoint ? chalk.cyan(apiEndpoint) : chalk.red('ā Not set')}\n`
|
|
459
398
|
);
|
|
460
399
|
return;
|
|
461
400
|
}
|
|
@@ -476,29 +415,11 @@ program
|
|
|
476
415
|
setApiEndpoint(options.endpoint);
|
|
477
416
|
console.log(chalk.green('ā API Endpoint saved successfully!'));
|
|
478
417
|
}
|
|
479
|
-
if (options.
|
|
480
|
-
if (options.ticketSystem === '') {
|
|
481
|
-
// Clear ticket system
|
|
482
|
-
setTicketSystem(null);
|
|
483
|
-
console.log(chalk.green('ā Ticket System cleared!'));
|
|
484
|
-
} else {
|
|
485
|
-
// Validate ticket system
|
|
486
|
-
const validSystems = ['jira', 'ado'];
|
|
487
|
-
if (!validSystems.includes(options.ticketSystem.toLowerCase())) {
|
|
488
|
-
console.error(chalk.red(`Invalid ticket system: ${options.ticketSystem}`));
|
|
489
|
-
console.error(chalk.gray(`Valid options: ${validSystems.join(', ')}`));
|
|
490
|
-
return;
|
|
491
|
-
}
|
|
492
|
-
setTicketSystem(options.ticketSystem);
|
|
493
|
-
console.log(chalk.green('ā Ticket System saved successfully!'));
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
if (!options.key && !options.endpoint && options.ticketSystem === undefined && !options.show) {
|
|
418
|
+
if (!options.key && !options.endpoint && !options.show) {
|
|
497
419
|
console.log(chalk.yellow('Please provide at least one configuration option.'));
|
|
498
420
|
console.log('\nUsage:');
|
|
499
421
|
console.log(' kk config --key YOUR_API_KEY');
|
|
500
|
-
console.log(' kk config --endpoint https://api.korekt.ai/review
|
|
501
|
-
console.log(' kk config --ticket-system jira');
|
|
422
|
+
console.log(' kk config --endpoint https://api.korekt.ai/api/review');
|
|
502
423
|
console.log(' kk config --show (view current configuration)');
|
|
503
424
|
}
|
|
504
425
|
});
|