@codecora/cli 0.0.4 → 0.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.
- package/README.md +111 -9
- package/bin/cora.js +8 -0
- package/dist/commands/auth.js +5 -4
- package/dist/commands/review.js +4 -0
- package/dist/config/storage.js +3 -1
- package/dist/git/diff.js +63 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
# CORA CLI
|
|
2
2
|
|
|
3
|
-
>
|
|
3
|
+
> Catch bugs & security issues BEFORE you commit. Save 2+ hours/week on code reviews.
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
4
8
|
|
|
5
9
|
**Website:** [https://codecora.dev](https://codecora.dev) | **Docs:** [https://codecora.dev/docs/cli](https://codecora.dev/docs/cli)
|
|
6
10
|
|
|
@@ -14,9 +18,17 @@ CORA CLI brings AI code review to your local development workflow. Get instant f
|
|
|
14
18
|
- **Git Hooks** - Automatic review on every commit
|
|
15
19
|
- **Cross-platform** - Works on macOS, Linux, and Windows
|
|
16
20
|
|
|
21
|
+
## Benefits
|
|
22
|
+
|
|
23
|
+
- **Save Time** - Reduce code review time by 2+ hours per week
|
|
24
|
+
- **Catch Bugs Early** - Find issues before they reach production
|
|
25
|
+
- **Security First** - Detect vulnerabilities and security risks
|
|
26
|
+
- **Learn Best Practices** - Get AI-powered suggestions for code improvement
|
|
27
|
+
- **Zero Friction** - Works with your existing Git workflow
|
|
28
|
+
|
|
17
29
|
## Installation
|
|
18
30
|
|
|
19
|
-
###
|
|
31
|
+
### Using npm/bun (Requires Node.js 20+)
|
|
20
32
|
|
|
21
33
|
```bash
|
|
22
34
|
# Using npm
|
|
@@ -29,15 +41,63 @@ bun install -g @codecora/cli
|
|
|
29
41
|
## Quick Start
|
|
30
42
|
|
|
31
43
|
```bash
|
|
32
|
-
# 1.
|
|
44
|
+
# 1. Install CORA CLI
|
|
45
|
+
npm install -g @codecora/cli
|
|
46
|
+
|
|
47
|
+
# 2. Login to CORA
|
|
33
48
|
cora auth login
|
|
34
49
|
|
|
35
|
-
#
|
|
50
|
+
# 3. Review staged changes
|
|
36
51
|
cora review
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
**Example Output:**
|
|
37
55
|
|
|
38
|
-
# 3. Enable automatic pre-commit review (optional)
|
|
39
|
-
cora enable
|
|
40
56
|
```
|
|
57
|
+
✅ Review complete
|
|
58
|
+
|
|
59
|
+
Found 2 issues:
|
|
60
|
+
|
|
61
|
+
🔴 Critical: SQL injection risk
|
|
62
|
+
File: src/auth.ts:45
|
|
63
|
+
User input not sanitized before query
|
|
64
|
+
|
|
65
|
+
🟡 Major: Missing error handling
|
|
66
|
+
File: src/api.ts:12
|
|
67
|
+
API call lacks try-catch block
|
|
68
|
+
|
|
69
|
+
💡 Suggestions available. Run with --include-walkthrough for details.
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Use Cases
|
|
73
|
+
|
|
74
|
+
CORA CLI is perfect for:
|
|
75
|
+
|
|
76
|
+
- **Pre-commit Hooks** - Automatically review code before every commit
|
|
77
|
+
- **CI/CD Pipelines** - Integrate into GitHub Actions, GitLab CI, Jenkins
|
|
78
|
+
- **Legacy Code Audit** - Review entire codebases with `--base` flag
|
|
79
|
+
- **Pull Request Reviews** - Check feature branches before merging
|
|
80
|
+
- **Learning Projects** - Get AI feedback on code quality and best practices
|
|
81
|
+
|
|
82
|
+
## Why CORA vs Others?
|
|
83
|
+
|
|
84
|
+
| Feature | CORA | SonarQube | CodeClimate | DeepSource |
|
|
85
|
+
|---------|------|-----------|-------------|------------|
|
|
86
|
+
| **Setup Time** | 30 seconds | Hours | Hours | Hours |
|
|
87
|
+
| **Pre-commit** | ✅ Native | ❌ Plugin | ❌ Plugin | ❌ Plugin |
|
|
88
|
+
| **AI-Powered** | ✅ GPT-4/Claude | ❌ Rule-based | ❌ Rule-based | ❌ Rule-based |
|
|
89
|
+
| **Your AI Key** | ✅ Use your own | ❌ Locked in | ❌ Locked in | ❌ Locked in |
|
|
90
|
+
| **Privacy** | ✅ Code stays local | ⚠️ Cloud scan | ⚠️ Cloud scan | ⚠️ Cloud scan |
|
|
91
|
+
| **Free Tier** | ✅ 100 reviews/mo | ❌ $120/yr min | ❌ $50/yr min | ❌ Subscription |
|
|
92
|
+
| **Languages** | All languages | Limited | Limited | Limited |
|
|
93
|
+
|
|
94
|
+
**Key Differentiators:**
|
|
95
|
+
- **Fastest Setup** - Install and run in 30 seconds, no configuration needed
|
|
96
|
+
- **AI-Powered** - Uses latest GPT-4/Claude models, not outdated rule engines
|
|
97
|
+
- **Your AI Key** - Use your own OpenAI/Anthropic key, no vendor lock-in
|
|
98
|
+
- **Privacy-First** - Code analyzed by YOUR AI provider, we never see your code
|
|
99
|
+
- **Zero Maintenance** - No servers to manage, no databases to configure
|
|
100
|
+
- **Always Updated** - Automatically benefits from latest AI model improvements
|
|
41
101
|
|
|
42
102
|
## Usage
|
|
43
103
|
|
|
@@ -69,6 +129,12 @@ cora review --unstaged
|
|
|
69
129
|
# Review specific files
|
|
70
130
|
cora review --files src/app.ts src/utils.ts
|
|
71
131
|
|
|
132
|
+
# Review committed changes
|
|
133
|
+
cora review --base main # Review branch vs main
|
|
134
|
+
cora review --commits 3 # Review last 3 commits
|
|
135
|
+
cora review --revision-range abc..def # Review specific range
|
|
136
|
+
cora review --unpushed # Review unpushed commits
|
|
137
|
+
|
|
72
138
|
# JSON output for CI/CD
|
|
73
139
|
cora review --format json
|
|
74
140
|
```
|
|
@@ -100,6 +166,10 @@ cora disable # Uninstall pre-commit hook
|
|
|
100
166
|
| `-s, --staged` | Review staged changes (default) |
|
|
101
167
|
| `-u, --unstaged` | Review unstaged changes |
|
|
102
168
|
| `-f, --files <files...>` | Review specific files |
|
|
169
|
+
| `--base <ref>` | Review changes from base ref to HEAD (e.g., "main") |
|
|
170
|
+
| `--revision-range <range>` | Review specific commit range (e.g., "HEAD~3..HEAD") |
|
|
171
|
+
| `--commits <number>` | Review last N commits |
|
|
172
|
+
| `--unpushed` | Review unpushed commits |
|
|
103
173
|
| `--format <format>` | Output format (pretty, json, compact) |
|
|
104
174
|
|
|
105
175
|
## Configuration
|
|
@@ -120,9 +190,28 @@ Configuration is stored in `~/.codecora/`:
|
|
|
120
190
|
|
|
121
191
|
## CI/CD Integration
|
|
122
192
|
|
|
193
|
+
### Supported Languages
|
|
194
|
+
|
|
195
|
+
CORA CLI supports code review for all programming languages including:
|
|
196
|
+
- JavaScript / TypeScript
|
|
197
|
+
- Python
|
|
198
|
+
- Java / Kotlin
|
|
199
|
+
- Go
|
|
200
|
+
- Rust
|
|
201
|
+
- PHP
|
|
202
|
+
- Ruby
|
|
203
|
+
- C# / .NET
|
|
204
|
+
- And more...
|
|
205
|
+
|
|
123
206
|
### Using API Keys (Recommended)
|
|
124
207
|
|
|
125
|
-
For CI/CD workflows, use API Keys instead of session tokens
|
|
208
|
+
For CI/CD workflows, use API Keys instead of session tokens.
|
|
209
|
+
|
|
210
|
+
**Getting an API Key:**
|
|
211
|
+
1. Login to [codecora.dev](https://codecora.dev)
|
|
212
|
+
2. Go to Dashboard → API Keys
|
|
213
|
+
3. Click "Generate API Key"
|
|
214
|
+
4. Copy the key and use in your CI/CD pipeline
|
|
126
215
|
|
|
127
216
|
```yaml
|
|
128
217
|
# Example: GitHub Actions
|
|
@@ -181,11 +270,24 @@ CORA_SKIP=1 git commit -m "message"
|
|
|
181
270
|
- A Codecora account (sign up at https://codecora.dev)
|
|
182
271
|
- An OpenAI-compatible API key configured in your workspace
|
|
183
272
|
|
|
273
|
+
## Pricing
|
|
274
|
+
|
|
275
|
+
- **Free Tier** - 100 reviews/month during beta
|
|
276
|
+
- **Pro Tier** - Coming soon
|
|
277
|
+
- **Enterprise** - Contact us for custom solutions
|
|
278
|
+
|
|
184
279
|
## License
|
|
185
280
|
|
|
186
281
|
MIT © [CORA](https://codecora.dev)
|
|
187
282
|
|
|
188
283
|
## Support
|
|
189
284
|
|
|
190
|
-
-
|
|
191
|
-
- [
|
|
285
|
+
- 📧 **Email**: support@codecora.dev
|
|
286
|
+
- 📚 [Documentation](https://codecora.dev/docs/cli)
|
|
287
|
+
- 🌐 [Website](https://codecora.dev)
|
|
288
|
+
- 💬 [Community Discord](https://discord.gg/codecora)
|
|
289
|
+
|
|
290
|
+
**Getting Help:**
|
|
291
|
+
- Check our [Documentation](https://codecora.dev/docs/cli) for detailed guides
|
|
292
|
+
- Join our [Discord community](https://discord.gg/codecora) for quick questions
|
|
293
|
+
- Email us at support@codecora.dev for technical issues
|
package/bin/cora.js
CHANGED
|
@@ -84,6 +84,10 @@ program
|
|
|
84
84
|
.option('-s, --staged', 'Review staged changes (default: true)')
|
|
85
85
|
.option('-u, --unstaged', 'Review unstaged changes')
|
|
86
86
|
.option('-f, --files <files...>', 'Review specific files')
|
|
87
|
+
.option('--base <ref>', 'Review changes from base ref to HEAD (e.g., "main", "develop")')
|
|
88
|
+
.option('--revision-range <range>', 'Review specific commit range (e.g., "HEAD~3..HEAD", "abc123..def456")')
|
|
89
|
+
.option('--commits <number>', 'Review last N commits', parseInt)
|
|
90
|
+
.option('--unpushed', 'Review unpushed commits')
|
|
87
91
|
.option('-m, --max-tokens <number>', 'Maximum tokens to use', parseInt)
|
|
88
92
|
.option('-i, --include-walkthrough', 'Include full walkthrough')
|
|
89
93
|
.option('--mock', 'Mock mode for testing')
|
|
@@ -96,6 +100,10 @@ program
|
|
|
96
100
|
branch: options.branch,
|
|
97
101
|
staged: options.unstaged ? false : options.staged !== false,
|
|
98
102
|
files: options.files,
|
|
103
|
+
base: options.base,
|
|
104
|
+
revisionRange: options.revisionRange,
|
|
105
|
+
commits: options.commits,
|
|
106
|
+
unpushed: options.unpushed,
|
|
99
107
|
maxTokens: options.maxTokens,
|
|
100
108
|
includeWalkthrough: options.includeWalkthrough,
|
|
101
109
|
mock: options.mock,
|
package/dist/commands/auth.js
CHANGED
|
@@ -48,7 +48,7 @@ export async function login(serverUrl) {
|
|
|
48
48
|
}
|
|
49
49
|
// Store session directly from server response
|
|
50
50
|
await setAuthToken(authResult.token, targetServerUrl, authResult.userId, authResult.email, authResult.expiresAt);
|
|
51
|
-
console.log(`\nSuccessfully logged in as ${authResult.email}`);
|
|
51
|
+
console.log(`\nSuccessfully logged in${authResult.email ? ` as ${authResult.email}` : ''}`);
|
|
52
52
|
process.exit(0);
|
|
53
53
|
}
|
|
54
54
|
catch (error) {
|
|
@@ -171,7 +171,7 @@ function createCallbackServer() {
|
|
|
171
171
|
const url = new URL(req.url, `http://localhost:${FIXED_PORT}`);
|
|
172
172
|
const token = url.searchParams.get('token');
|
|
173
173
|
const userId = url.searchParams.get('userId');
|
|
174
|
-
const email = url.searchParams.get('email');
|
|
174
|
+
const email = url.searchParams.get('email'); // Optional, can be fetched via API
|
|
175
175
|
const expiresAt = url.searchParams.get('expiresAt');
|
|
176
176
|
const error = url.searchParams.get('error');
|
|
177
177
|
if (error) {
|
|
@@ -181,7 +181,8 @@ function createCallbackServer() {
|
|
|
181
181
|
server.close();
|
|
182
182
|
return;
|
|
183
183
|
}
|
|
184
|
-
|
|
184
|
+
// Email is optional - can be fetched via API after login
|
|
185
|
+
if (token && userId && expiresAt) {
|
|
185
186
|
res.writeHead(200, { 'Content-Type': 'text/html' });
|
|
186
187
|
res.end(`
|
|
187
188
|
<!DOCTYPE html>
|
|
@@ -193,7 +194,7 @@ function createCallbackServer() {
|
|
|
193
194
|
</body>
|
|
194
195
|
</html>
|
|
195
196
|
`);
|
|
196
|
-
resolvePromise({ token, userId, email, expiresAt });
|
|
197
|
+
resolvePromise({ token, userId, email: email || undefined, expiresAt });
|
|
197
198
|
server.close();
|
|
198
199
|
}
|
|
199
200
|
else {
|
package/dist/commands/review.js
CHANGED
|
@@ -36,6 +36,10 @@ export async function review(options = {}) {
|
|
|
36
36
|
staged: options.staged !== false,
|
|
37
37
|
files: options.files,
|
|
38
38
|
cwd,
|
|
39
|
+
base: options.base,
|
|
40
|
+
revisionRange: options.revisionRange,
|
|
41
|
+
commits: options.commits,
|
|
42
|
+
unpushed: options.unpushed,
|
|
39
43
|
});
|
|
40
44
|
}
|
|
41
45
|
catch (error) {
|
package/dist/config/storage.js
CHANGED
package/dist/git/diff.js
CHANGED
|
@@ -149,7 +149,21 @@ export function validateDiffSize(diff, maxSize = 10 * 1024 * 1024 // 10MB defaul
|
|
|
149
149
|
* Main function to get diff based on options.
|
|
150
150
|
*/
|
|
151
151
|
export function getReviewDiff(options) {
|
|
152
|
-
const { staged = true, files, cwd = process.cwd() } = options;
|
|
152
|
+
const { staged = true, files, cwd = process.cwd(), base, revisionRange, commits, unpushed, } = options;
|
|
153
|
+
// Commit-based review takes precedence
|
|
154
|
+
if (revisionRange) {
|
|
155
|
+
return getCommitDiff(revisionRange, cwd);
|
|
156
|
+
}
|
|
157
|
+
if (unpushed) {
|
|
158
|
+
return getUnpushedDiff(cwd);
|
|
159
|
+
}
|
|
160
|
+
if (commits !== undefined) {
|
|
161
|
+
return getLastCommitsDiff(commits, cwd);
|
|
162
|
+
}
|
|
163
|
+
if (base) {
|
|
164
|
+
return getBaseDiff(base, cwd);
|
|
165
|
+
}
|
|
166
|
+
// Default behavior: staged/unstaged/files
|
|
153
167
|
if (files && files.length > 0) {
|
|
154
168
|
return getFilesDiff(files, staged, cwd);
|
|
155
169
|
}
|
|
@@ -160,3 +174,51 @@ export function getReviewDiff(options) {
|
|
|
160
174
|
return getUnstagedDiff(cwd);
|
|
161
175
|
}
|
|
162
176
|
}
|
|
177
|
+
/**
|
|
178
|
+
* Get diff between two git refs (commits, branches, tags)
|
|
179
|
+
*
|
|
180
|
+
* Examples:
|
|
181
|
+
* - "main...HEAD" - changes from main to current branch
|
|
182
|
+
* - "abc123..def456" - changes between two commits
|
|
183
|
+
* - "v1.0.0..HEAD" - changes since tag v1.0.0
|
|
184
|
+
*/
|
|
185
|
+
export function getCommitDiff(revisionRange, cwd = process.cwd()) {
|
|
186
|
+
const result = execFileSafe('git', ['diff', revisionRange], { cwd });
|
|
187
|
+
if (result.status !== 0) {
|
|
188
|
+
throw new Error(`Failed to get commit diff: ${result.stderr || result.error?.message}`);
|
|
189
|
+
}
|
|
190
|
+
return result.stdout;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Get diff of unpushed commits
|
|
194
|
+
*
|
|
195
|
+
* Returns diff between HEAD and the remote tracking branch.
|
|
196
|
+
*/
|
|
197
|
+
export function getUnpushedDiff(cwd = process.cwd()) {
|
|
198
|
+
// First, get the remote tracking branch
|
|
199
|
+
const trackingResult = execFileSafe('git', ['rev-parse', '--abbrev-ref', '--symbolic-full-name', '@{u}'], { cwd });
|
|
200
|
+
if (trackingResult.status !== 0) {
|
|
201
|
+
throw new Error('No upstream branch found. Cannot determine unpushed commits. ' +
|
|
202
|
+
'Hint: Set upstream with `git push -u origin <branch>`');
|
|
203
|
+
}
|
|
204
|
+
const trackingBranch = trackingResult.stdout.trim();
|
|
205
|
+
return getCommitDiff(`${trackingBranch}...HEAD`, cwd);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Get diff of last N commits
|
|
209
|
+
*
|
|
210
|
+
* Returns diff between HEAD~N and HEAD.
|
|
211
|
+
*/
|
|
212
|
+
export function getLastCommitsDiff(count, cwd = process.cwd()) {
|
|
213
|
+
const revisionRange = `HEAD~${count}..HEAD`;
|
|
214
|
+
return getCommitDiff(revisionRange, cwd);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Get diff from base branch to HEAD
|
|
218
|
+
*
|
|
219
|
+
* Compares current HEAD with the specified base branch.
|
|
220
|
+
*/
|
|
221
|
+
export function getBaseDiff(base, cwd = process.cwd()) {
|
|
222
|
+
const revisionRange = `${base}...HEAD`;
|
|
223
|
+
return getCommitDiff(revisionRange, cwd);
|
|
224
|
+
}
|
package/dist/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const VERSION = '0.0.
|
|
1
|
+
export const VERSION = '0.0.5';
|