roast-cli 1.0.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/BUILD-SUMMARY.md +251 -0
- package/CHECKLIST.md +107 -0
- package/LICENSE +21 -0
- package/README.md +1530 -0
- package/SETUP.md +108 -0
- package/bin/roast.js +39 -0
- package/docs/style-guide.md +70 -0
- package/examples/bad-react.jsx +28 -0
- package/examples/bubble-sort.js +16 -0
- package/examples/sql-injection.py +18 -0
- package/examples/test.js +39 -0
- package/lib/roast.js +199 -0
- package/package.json +39 -0
- package/test-code.js +12 -0
package/SETUP.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Setup Guide
|
|
2
|
+
|
|
3
|
+
## Quick Start
|
|
4
|
+
|
|
5
|
+
1. **Install dependencies**
|
|
6
|
+
```bash
|
|
7
|
+
cd ~/muin/projects/roast
|
|
8
|
+
npm install
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
2. **Set up API key**
|
|
12
|
+
```bash
|
|
13
|
+
export ANTHROPIC_API_KEY="your-key-here"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Get your key at: https://console.anthropic.com/settings/keys
|
|
17
|
+
|
|
18
|
+
3. **Test it out**
|
|
19
|
+
```bash
|
|
20
|
+
# Try the bubble sort example
|
|
21
|
+
node bin/roast.js examples/bubble-sort.js
|
|
22
|
+
|
|
23
|
+
# Try serious mode
|
|
24
|
+
node bin/roast.js --serious examples/sql-injection.py
|
|
25
|
+
|
|
26
|
+
# Try the bad React code
|
|
27
|
+
node bin/roast.js examples/bad-react.jsx
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
4. **Install globally (optional)**
|
|
31
|
+
```bash
|
|
32
|
+
npm link
|
|
33
|
+
# Now you can use `roast` anywhere
|
|
34
|
+
roast examples/bubble-sort.js
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Development
|
|
38
|
+
|
|
39
|
+
### Project Structure
|
|
40
|
+
```
|
|
41
|
+
roast/
|
|
42
|
+
├── bin/roast.js # CLI entry point
|
|
43
|
+
├── lib/roast.js # Core logic
|
|
44
|
+
├── examples/ # Test files
|
|
45
|
+
│ ├── bubble-sort.js
|
|
46
|
+
│ ├── bad-react.jsx
|
|
47
|
+
│ └── sql-injection.py
|
|
48
|
+
├── docs/
|
|
49
|
+
│ └── style-guide.md # Output guidelines
|
|
50
|
+
├── package.json
|
|
51
|
+
└── README.md
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Testing
|
|
55
|
+
|
|
56
|
+
Run the CLI on different files:
|
|
57
|
+
```bash
|
|
58
|
+
node bin/roast.js examples/bubble-sort.js
|
|
59
|
+
node bin/roast.js examples/bad-react.jsx --serious
|
|
60
|
+
node bin/roast.js examples/sql-injection.py
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Making Changes
|
|
64
|
+
|
|
65
|
+
1. Edit `lib/roast.js` for core logic
|
|
66
|
+
2. Edit `bin/roast.js` for CLI options
|
|
67
|
+
3. Update prompts in `ROAST_PROMPT` or `SERIOUS_PROMPT`
|
|
68
|
+
4. Test with examples before committing
|
|
69
|
+
|
|
70
|
+
## Publishing to npm
|
|
71
|
+
|
|
72
|
+
1. **Create npm account** (if needed)
|
|
73
|
+
```bash
|
|
74
|
+
npm login
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
2. **Update version**
|
|
78
|
+
```bash
|
|
79
|
+
npm version patch # 0.1.0 → 0.1.1
|
|
80
|
+
npm version minor # 0.1.0 → 0.2.0
|
|
81
|
+
npm version major # 0.1.0 → 1.0.0
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
3. **Publish**
|
|
85
|
+
```bash
|
|
86
|
+
npm publish --access public
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
4. **Test installation**
|
|
90
|
+
```bash
|
|
91
|
+
npm install -g @muin/roast
|
|
92
|
+
roast --version
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
## Tips
|
|
96
|
+
|
|
97
|
+
- Keep prompts under 500 tokens for speed
|
|
98
|
+
- Test with various languages
|
|
99
|
+
- Screenshots for README examples
|
|
100
|
+
- Update style guide as you refine the tone
|
|
101
|
+
|
|
102
|
+
## Next Steps
|
|
103
|
+
|
|
104
|
+
- [ ] Git repo initialization
|
|
105
|
+
- [ ] Push to GitHub
|
|
106
|
+
- [ ] Create demo GIF/video
|
|
107
|
+
- [ ] Tweet about it
|
|
108
|
+
- [ ] Publish to npm
|
package/bin/roast.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { program } from 'commander';
|
|
4
|
+
import { roastFile } from '../lib/roast.js';
|
|
5
|
+
import chalk from 'chalk';
|
|
6
|
+
import { readFileSync } from 'fs';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
8
|
+
import { dirname, join } from 'path';
|
|
9
|
+
|
|
10
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
11
|
+
const __dirname = dirname(__filename);
|
|
12
|
+
const packageJson = JSON.parse(readFileSync(join(__dirname, '../package.json'), 'utf-8'));
|
|
13
|
+
|
|
14
|
+
program
|
|
15
|
+
.name('roast')
|
|
16
|
+
.description('AI code reviewer that roasts your code (with love)')
|
|
17
|
+
.version(packageJson.version)
|
|
18
|
+
.argument('<file>', 'code file to roast')
|
|
19
|
+
.option('-s, --serious', 'serious mode (professional review)')
|
|
20
|
+
.option('--severity <level>', 'roast severity: mild, medium, harsh', 'medium')
|
|
21
|
+
.option('-m, --model <model>', 'AI model to use', 'claude-sonnet-4-5-20250929')
|
|
22
|
+
.option('--no-color', 'disable colors')
|
|
23
|
+
.action(async (file, options) => {
|
|
24
|
+
try {
|
|
25
|
+
// Validate severity level
|
|
26
|
+
const validSeverities = ['mild', 'medium', 'harsh'];
|
|
27
|
+
if (options.severity && !validSeverities.includes(options.severity)) {
|
|
28
|
+
console.error(chalk.red(`Invalid severity level: ${options.severity}`));
|
|
29
|
+
console.error(chalk.gray(`Valid options: ${validSeverities.join(', ')}`));
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
await roastFile(file, options);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error(chalk.red('💥 Error:'), error.message);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
program.parse();
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Style Guide
|
|
2
|
+
|
|
3
|
+
## The "No AI Vibes" Rule
|
|
4
|
+
|
|
5
|
+
This tool is built with AI, but it shouldn't **feel** like AI slop. Here's what that means:
|
|
6
|
+
|
|
7
|
+
### ❌ Avoid
|
|
8
|
+
|
|
9
|
+
- **Corporate cheerleading**: "Great job! 🎉" "You're doing amazing!"
|
|
10
|
+
- **Generic platitudes**: "Consider following best practices"
|
|
11
|
+
- **Emoji overload**: Every sentence doesn't need 5 emojis
|
|
12
|
+
- **Fake enthusiasm**: "I'm so excited to help you with..."
|
|
13
|
+
- **Robotic language**: "As an AI language model..."
|
|
14
|
+
- **Hedge words**: "Perhaps maybe you might consider possibly..."
|
|
15
|
+
|
|
16
|
+
### ✅ Do
|
|
17
|
+
|
|
18
|
+
- **Be direct**: Say what's wrong, why it matters, how to fix it
|
|
19
|
+
- **Be specific**: Quote actual code, reference line numbers
|
|
20
|
+
- **Be funny naturally**: Like a human developer would
|
|
21
|
+
- **Be useful**: Every roast should have actionable feedback
|
|
22
|
+
- **Be respectful**: Roast the code, not the person
|
|
23
|
+
|
|
24
|
+
## Tone Examples
|
|
25
|
+
|
|
26
|
+
**Bad (AI vibes):**
|
|
27
|
+
> "Great effort! 🌟 However, I noticed that perhaps you might want to consider using async/await instead of callbacks. It would be more modern! Keep up the good work! 💪"
|
|
28
|
+
|
|
29
|
+
**Good (human dev):**
|
|
30
|
+
> "🔥 Callback hell called, it wants its code back. Switch to async/await unless you enjoy debugging spaghetti."
|
|
31
|
+
|
|
32
|
+
**Bad (too mean):**
|
|
33
|
+
> "🔥 Did you write this with your eyes closed? This is the worst code I've ever seen."
|
|
34
|
+
|
|
35
|
+
**Good (roast with love):**
|
|
36
|
+
> "🔥 This function has more side effects than a pharmaceutical commercial. Let's make it pure."
|
|
37
|
+
|
|
38
|
+
## Output Structure
|
|
39
|
+
|
|
40
|
+
1. **Hook** - Start with the most interesting/funny issue
|
|
41
|
+
2. **Issues** - 2-4 specific problems with solutions
|
|
42
|
+
3. **Compliment** - End with something genuinely good or a useful tip
|
|
43
|
+
|
|
44
|
+
## Emoji Usage
|
|
45
|
+
|
|
46
|
+
Use emojis as **markers**, not decoration:
|
|
47
|
+
- 🔥 = Issue/roast
|
|
48
|
+
- 💡 = Suggestion
|
|
49
|
+
- ✨ = Compliment
|
|
50
|
+
- 🚨 = Serious bug
|
|
51
|
+
|
|
52
|
+
Don't: "This is so cool! 😎🚀✨💯🔥"
|
|
53
|
+
|
|
54
|
+
## Length
|
|
55
|
+
|
|
56
|
+
- **Roast mode**: 200-400 words
|
|
57
|
+
- **Serious mode**: 250-400 words
|
|
58
|
+
- Too short = not useful
|
|
59
|
+
- Too long = nobody reads it
|
|
60
|
+
|
|
61
|
+
## Shareability
|
|
62
|
+
|
|
63
|
+
Every roast should be:
|
|
64
|
+
- **Screenshot-friendly** - Fits in one image
|
|
65
|
+
- **Self-contained** - Makes sense without context
|
|
66
|
+
- **Quotable** - Has at least one memorable line
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
Remember: We're building a tool developers **want** to use, not one that feels like homework.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
// A React component with several issues
|
|
4
|
+
function UserProfile(props) {
|
|
5
|
+
const [data, setData] = React.useState(null);
|
|
6
|
+
|
|
7
|
+
// Fetching in render - bad idea
|
|
8
|
+
fetch('/api/user/' + props.userId)
|
|
9
|
+
.then(res => res.json())
|
|
10
|
+
.then(json => setData(json));
|
|
11
|
+
|
|
12
|
+
// No loading state
|
|
13
|
+
return (
|
|
14
|
+
<div onClick={() => {
|
|
15
|
+
// Inline function in render - creates new function every time
|
|
16
|
+
console.log('clicked');
|
|
17
|
+
}}>
|
|
18
|
+
<h1>{data.name}</h1>
|
|
19
|
+
<p>{data.email}</p>
|
|
20
|
+
{/* Rendering array without keys */}
|
|
21
|
+
{data.posts.map(post => (
|
|
22
|
+
<div>{post.title}</div>
|
|
23
|
+
))}
|
|
24
|
+
</div>
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export default UserProfile;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Classic bubble sort - perfect roast target
|
|
2
|
+
function bubbleSort(arr) {
|
|
3
|
+
for (let i = 0; i < arr.length; i++) {
|
|
4
|
+
for (let j = 0; j < arr.length - 1; j++) {
|
|
5
|
+
if (arr[j] > arr[j + 1]) {
|
|
6
|
+
let temp = arr[j];
|
|
7
|
+
arr[j] = arr[j + 1];
|
|
8
|
+
arr[j + 1] = temp;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
return arr;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const numbers = [64, 34, 25, 12, 22, 11, 90];
|
|
16
|
+
console.log(bubbleSort(numbers));
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# SQL injection vulnerability example
|
|
2
|
+
import sqlite3
|
|
3
|
+
|
|
4
|
+
def get_user(username):
|
|
5
|
+
conn = sqlite3.connect('users.db')
|
|
6
|
+
cursor = conn.cursor()
|
|
7
|
+
|
|
8
|
+
# DANGER: String concatenation with user input
|
|
9
|
+
query = f"SELECT * FROM users WHERE username = '{username}'"
|
|
10
|
+
cursor.execute(query)
|
|
11
|
+
|
|
12
|
+
result = cursor.fetchone()
|
|
13
|
+
conn.close()
|
|
14
|
+
return result
|
|
15
|
+
|
|
16
|
+
# This could be exploited with: username = "admin' OR '1'='1"
|
|
17
|
+
user = get_user(input("Enter username: "))
|
|
18
|
+
print(user)
|
package/examples/test.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// Quick test script to verify the CLI works
|
|
4
|
+
import { exec } from 'child_process';
|
|
5
|
+
import { promisify } from 'util';
|
|
6
|
+
|
|
7
|
+
const execAsync = promisify(exec);
|
|
8
|
+
|
|
9
|
+
console.log('🧪 Testing roast CLI...\n');
|
|
10
|
+
|
|
11
|
+
async function test() {
|
|
12
|
+
// Check if ANTHROPIC_API_KEY is set
|
|
13
|
+
if (!process.env.ANTHROPIC_API_KEY) {
|
|
14
|
+
console.error('❌ ANTHROPIC_API_KEY not set');
|
|
15
|
+
console.log('Set it with: export ANTHROPIC_API_KEY="your-key-here"');
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
// Test version
|
|
21
|
+
const { stdout: version } = await execAsync('node bin/roast.js --version');
|
|
22
|
+
console.log('✅ Version:', version.trim());
|
|
23
|
+
|
|
24
|
+
// Test help
|
|
25
|
+
const { stdout: help } = await execAsync('node bin/roast.js --help');
|
|
26
|
+
console.log('✅ Help command works');
|
|
27
|
+
|
|
28
|
+
console.log('\n📝 To test actual roasting, run:');
|
|
29
|
+
console.log(' node bin/roast.js examples/bubble-sort.js');
|
|
30
|
+
console.log(' node bin/roast.js --serious examples/sql-injection.py');
|
|
31
|
+
console.log(' node bin/roast.js examples/bad-react.jsx');
|
|
32
|
+
|
|
33
|
+
} catch (error) {
|
|
34
|
+
console.error('❌ Test failed:', error.message);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
test();
|
package/lib/roast.js
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import Anthropic from '@anthropic-ai/sdk';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
import { readFileSync } from 'fs';
|
|
4
|
+
import { basename, extname } from 'path';
|
|
5
|
+
|
|
6
|
+
const LANGUAGE_MAP = {
|
|
7
|
+
'.js': 'JavaScript',
|
|
8
|
+
'.ts': 'TypeScript',
|
|
9
|
+
'.jsx': 'React/JSX',
|
|
10
|
+
'.tsx': 'React/TSX',
|
|
11
|
+
'.py': 'Python',
|
|
12
|
+
'.go': 'Go',
|
|
13
|
+
'.rs': 'Rust',
|
|
14
|
+
'.java': 'Java',
|
|
15
|
+
'.c': 'C',
|
|
16
|
+
'.cpp': 'C++',
|
|
17
|
+
'.rb': 'Ruby',
|
|
18
|
+
'.php': 'PHP',
|
|
19
|
+
'.swift': 'Swift',
|
|
20
|
+
'.kt': 'Kotlin',
|
|
21
|
+
'.sh': 'Shell',
|
|
22
|
+
'.sql': 'SQL',
|
|
23
|
+
'.html': 'HTML',
|
|
24
|
+
'.css': 'CSS',
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const MILD_ROAST_PROMPT = `You're a friendly senior developer reviewing code. Your job:
|
|
28
|
+
|
|
29
|
+
1. Point out real issues gently (bugs, anti-patterns, performance problems)
|
|
30
|
+
2. Be encouraging and constructive - focus on learning opportunities
|
|
31
|
+
3. Use light humor, keep it warm and supportive
|
|
32
|
+
4. Be specific - quote the actual code you're mentioning
|
|
33
|
+
5. End with genuine compliments and helpful tips
|
|
34
|
+
|
|
35
|
+
Style: Like a supportive mentor at code review. Constructive feedback with a smile.
|
|
36
|
+
|
|
37
|
+
Format your response with:
|
|
38
|
+
- 💡 for suggestions and improvements
|
|
39
|
+
- ✨ for compliments and good practices
|
|
40
|
+
- 🚨 for serious bugs (if any)
|
|
41
|
+
- 💪 for encouragement
|
|
42
|
+
|
|
43
|
+
Keep it under 400 words. Keep it positive.`;
|
|
44
|
+
|
|
45
|
+
const MEDIUM_ROAST_PROMPT = `You're a senior developer with a sharp wit reviewing code. Your job:
|
|
46
|
+
|
|
47
|
+
1. Point out real issues (bugs, anti-patterns, performance problems, security holes)
|
|
48
|
+
2. Be funny but not mean - roast the code, not the person
|
|
49
|
+
3. Use developer humor (not corporate AI cheerleader vibes)
|
|
50
|
+
4. Be specific - quote the actual code you're roasting
|
|
51
|
+
5. End with 1-2 genuine compliments or useful tips
|
|
52
|
+
|
|
53
|
+
Style: Like a sarcastic but helpful senior dev at code review. Think "Gordon Ramsay for code" but constructive.
|
|
54
|
+
|
|
55
|
+
Format your response with:
|
|
56
|
+
- 🔥 for roasts/issues
|
|
57
|
+
- 💡 for suggestions
|
|
58
|
+
- ✨ for compliments
|
|
59
|
+
- 🚨 for serious bugs
|
|
60
|
+
|
|
61
|
+
Keep it under 400 words. Make it shareable.`;
|
|
62
|
+
|
|
63
|
+
const HARSH_ROAST_PROMPT = `You're a brutally honest senior developer with zero patience for bad code. Your job:
|
|
64
|
+
|
|
65
|
+
1. Ruthlessly point out every issue (bugs, anti-patterns, performance disasters, security nightmares)
|
|
66
|
+
2. Be savage - this code needs to know what it did wrong
|
|
67
|
+
3. Use cutting developer humor (think "your code is so bad, it makes PHP look elegant")
|
|
68
|
+
4. Be specific - quote the crimes against programming
|
|
69
|
+
5. Maybe end with ONE backhanded compliment if you can find something
|
|
70
|
+
|
|
71
|
+
Style: Like Gordon Ramsay at his angriest, but for code. No mercy. Pure fire.
|
|
72
|
+
|
|
73
|
+
Format your response with:
|
|
74
|
+
- 🔥🔥🔥 for roasts (triple fire for triple pain)
|
|
75
|
+
- 💀 for code that should be deleted
|
|
76
|
+
- 🚨 for serious bugs
|
|
77
|
+
- 💡 for "how did you not know this?"
|
|
78
|
+
|
|
79
|
+
Keep it savage. Keep it under 400 words. No holding back.`;
|
|
80
|
+
|
|
81
|
+
const SERIOUS_PROMPT = `You're a senior developer conducting a professional code review. Analyze this code for:
|
|
82
|
+
|
|
83
|
+
1. Bugs and potential runtime errors
|
|
84
|
+
2. Security vulnerabilities
|
|
85
|
+
3. Performance issues
|
|
86
|
+
4. Code quality and maintainability
|
|
87
|
+
5. Best practices for the language/framework
|
|
88
|
+
|
|
89
|
+
Be thorough but concise. Format your response with:
|
|
90
|
+
- 🚨 Critical issues (security, bugs)
|
|
91
|
+
- ⚠️ Warnings (performance, code smell)
|
|
92
|
+
- 💡 Suggestions (improvements, best practices)
|
|
93
|
+
- ✅ Good practices observed
|
|
94
|
+
|
|
95
|
+
Keep it actionable and under 400 words.`;
|
|
96
|
+
|
|
97
|
+
export async function roastFile(filePath, options = {}) {
|
|
98
|
+
// Read file
|
|
99
|
+
const code = readFileSync(filePath, 'utf-8');
|
|
100
|
+
const fileName = basename(filePath);
|
|
101
|
+
const ext = extname(filePath);
|
|
102
|
+
const language = LANGUAGE_MAP[ext] || 'code';
|
|
103
|
+
|
|
104
|
+
// Check for API key
|
|
105
|
+
const apiKey = process.env.ANTHROPIC_API_KEY;
|
|
106
|
+
if (!apiKey) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
'ANTHROPIC_API_KEY not found in environment.\n' +
|
|
109
|
+
'Get your key at: https://console.anthropic.com/settings/keys\n' +
|
|
110
|
+
'Then run: export ANTHROPIC_API_KEY="your-key-here"'
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Display header
|
|
115
|
+
console.log('');
|
|
116
|
+
if (options.serious) {
|
|
117
|
+
console.log(chalk.blue.bold('📋 Professional Code Review'));
|
|
118
|
+
console.log(chalk.gray(`File: ${fileName} (${language})`));
|
|
119
|
+
} else {
|
|
120
|
+
const severity = options.severity || 'medium';
|
|
121
|
+
const headers = {
|
|
122
|
+
mild: chalk.yellow.bold('😊 CODE REVIEW (Be Nice Mode)'),
|
|
123
|
+
medium: chalk.red.bold('🔥 CODE ROAST 🔥'),
|
|
124
|
+
harsh: chalk.red.bold('💀 CODE EXECUTION 💀')
|
|
125
|
+
};
|
|
126
|
+
console.log(headers[severity]);
|
|
127
|
+
console.log(chalk.gray(`Victim: ${fileName} (${language})`));
|
|
128
|
+
if (severity === 'harsh') {
|
|
129
|
+
console.log(chalk.red('⚠️ WARNING: Brutally honest mode enabled'));
|
|
130
|
+
} else if (severity === 'mild') {
|
|
131
|
+
console.log(chalk.green('✨ Friendly feedback mode'));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
135
|
+
console.log('');
|
|
136
|
+
|
|
137
|
+
// Call Anthropic API
|
|
138
|
+
const client = new Anthropic({ apiKey });
|
|
139
|
+
|
|
140
|
+
const spinner = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
|
|
141
|
+
let i = 0;
|
|
142
|
+
const interval = setInterval(() => {
|
|
143
|
+
process.stdout.write(`\r${chalk.cyan(spinner[i++ % spinner.length])} Analyzing...`);
|
|
144
|
+
}, 80);
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
let prompt;
|
|
148
|
+
if (options.serious) {
|
|
149
|
+
prompt = SERIOUS_PROMPT;
|
|
150
|
+
} else {
|
|
151
|
+
const severity = options.severity || 'medium';
|
|
152
|
+
const prompts = {
|
|
153
|
+
mild: MILD_ROAST_PROMPT,
|
|
154
|
+
medium: MEDIUM_ROAST_PROMPT,
|
|
155
|
+
harsh: HARSH_ROAST_PROMPT
|
|
156
|
+
};
|
|
157
|
+
prompt = prompts[severity];
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const message = await client.messages.create({
|
|
161
|
+
model: options.model,
|
|
162
|
+
max_tokens: 2048,
|
|
163
|
+
messages: [{
|
|
164
|
+
role: 'user',
|
|
165
|
+
content: `${prompt}\n\n\`\`\`${language}\n${code}\n\`\`\``
|
|
166
|
+
}]
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
clearInterval(interval);
|
|
170
|
+
process.stdout.write('\r' + ' '.repeat(20) + '\r');
|
|
171
|
+
|
|
172
|
+
const review = message.content[0].text;
|
|
173
|
+
|
|
174
|
+
// Colorize output
|
|
175
|
+
const colorized = review
|
|
176
|
+
.replace(/🔥/g, chalk.red('🔥'))
|
|
177
|
+
.replace(/💡/g, chalk.yellow('💡'))
|
|
178
|
+
.replace(/✨/g, chalk.green('✨'))
|
|
179
|
+
.replace(/🚨/g, chalk.red.bold('🚨'))
|
|
180
|
+
.replace(/⚠️/g, chalk.yellow('⚠️'))
|
|
181
|
+
.replace(/✅/g, chalk.green('✅'))
|
|
182
|
+
.replace(/💀/g, chalk.red.bold('💀'))
|
|
183
|
+
.replace(/💪/g, chalk.cyan('💪'));
|
|
184
|
+
|
|
185
|
+
console.log(colorized);
|
|
186
|
+
console.log('');
|
|
187
|
+
console.log(chalk.gray('─'.repeat(50)));
|
|
188
|
+
|
|
189
|
+
if (!options.serious) {
|
|
190
|
+
console.log(chalk.gray.italic('Roasted with ❤️ by Claude'));
|
|
191
|
+
}
|
|
192
|
+
console.log('');
|
|
193
|
+
|
|
194
|
+
} catch (error) {
|
|
195
|
+
clearInterval(interval);
|
|
196
|
+
process.stdout.write('\r' + ' '.repeat(20) + '\r');
|
|
197
|
+
throw error;
|
|
198
|
+
}
|
|
199
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "roast-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "AI code reviewer that roasts your code (with love)",
|
|
5
|
+
"main": "lib/roast.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"roast": "bin/roast.js",
|
|
8
|
+
"roast-cli": "bin/roast.js"
|
|
9
|
+
},
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "node examples/test.js"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"code-review",
|
|
15
|
+
"ai",
|
|
16
|
+
"cli",
|
|
17
|
+
"developer-tools",
|
|
18
|
+
"humor"
|
|
19
|
+
],
|
|
20
|
+
"homepage": "https://github.com/muin-company/roast#readme",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/muin-company/roast.git"
|
|
24
|
+
},
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/muin-company/roast/issues"
|
|
27
|
+
},
|
|
28
|
+
"author": "muin",
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=18.0.0"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@anthropic-ai/sdk": "^0.32.1",
|
|
35
|
+
"chalk": "^5.3.0",
|
|
36
|
+
"commander": "^12.0.0"
|
|
37
|
+
},
|
|
38
|
+
"type": "module"
|
|
39
|
+
}
|
package/test-code.js
ADDED