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/README.md
ADDED
|
@@ -0,0 +1,1530 @@
|
|
|
1
|
+
# roast
|
|
2
|
+
|
|
3
|
+
AI code reviewer that roasts your code with humor and honesty.
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/@muin/roast)
|
|
6
|
+
[](https://www.npmjs.com/package/@muin/roast)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
[](https://nodejs.org)
|
|
9
|
+
[](https://github.com/muinmomin/roast)
|
|
10
|
+
[](https://github.com/muinmomin/roast/issues)
|
|
11
|
+
[](https://github.com/muinmomin/roast/pulls)
|
|
12
|
+
|
|
13
|
+
## What is this?
|
|
14
|
+
|
|
15
|
+
`roast` is a CLI tool that uses Claude to review your code and deliver feedback that's accurate, funny, and useful. Think Gordon Ramsay meets your senior developer.
|
|
16
|
+
|
|
17
|
+
## Why use this?
|
|
18
|
+
|
|
19
|
+
**Before:**
|
|
20
|
+
```
|
|
21
|
+
You: "Is this code good?"
|
|
22
|
+
Brain: "Probably fine..."
|
|
23
|
+
*ships to production*
|
|
24
|
+
*everything breaks*
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
**After:**
|
|
28
|
+
```bash
|
|
29
|
+
$ roast bubble-sort.js
|
|
30
|
+
```
|
|
31
|
+
```
|
|
32
|
+
🔥 Oh boy, bubble sort in 2026? What's next, a floppy disk driver?
|
|
33
|
+
|
|
34
|
+
🔥 This function mutates the input array. That's like borrowing
|
|
35
|
+
someone's car and returning it as a motorcycle.
|
|
36
|
+
|
|
37
|
+
💡 Use Array.prototype.toSorted() if you're on Node 20+
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Real problems:**
|
|
41
|
+
- Code reviews take days
|
|
42
|
+
- Teammates are too nice to be honest
|
|
43
|
+
- You're working solo with no feedback
|
|
44
|
+
- CI catches bugs after you commit
|
|
45
|
+
- Writing tests doesn't catch design issues
|
|
46
|
+
|
|
47
|
+
`roast` gives you instant, brutally honest feedback before you commit. Use roast mode for your own code, serious mode for team reviews.
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npm install -g @muin/roast
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Or run without installing:
|
|
56
|
+
```bash
|
|
57
|
+
npx @muin/roast your-file.js
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Setup
|
|
61
|
+
|
|
62
|
+
Get your Anthropic API key at [console.anthropic.com](https://console.anthropic.com/settings/keys)
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
export ANTHROPIC_API_KEY="your-key-here"
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Add to `~/.bashrc` or `~/.zshrc` to make it permanent.
|
|
69
|
+
|
|
70
|
+
## Usage
|
|
71
|
+
|
|
72
|
+
### Roast mode (default)
|
|
73
|
+
```bash
|
|
74
|
+
roast src/app.js
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Output:
|
|
78
|
+
```
|
|
79
|
+
🔥 CODE ROAST 🔥
|
|
80
|
+
Victim: bubble-sort.js (JavaScript)
|
|
81
|
+
──────────────────────────────────────────────────
|
|
82
|
+
|
|
83
|
+
🔥 Oh boy, bubble sort in 2026? What's next, a floppy disk driver?
|
|
84
|
+
|
|
85
|
+
🔥 This function mutates the input array. That's like borrowing
|
|
86
|
+
someone's car and returning it as a motorcycle.
|
|
87
|
+
|
|
88
|
+
💡 Use Array.prototype.toSorted() if you're on Node 20+, or
|
|
89
|
+
at least clone the array first: const sorted = [...arr]
|
|
90
|
+
|
|
91
|
+
🔥 No input validation. Passing a string? Enjoy your runtime error.
|
|
92
|
+
|
|
93
|
+
✨ At least you got the algorithm right. It's bad, but it's
|
|
94
|
+
correctly bad.
|
|
95
|
+
|
|
96
|
+
──────────────────────────────────────────────────
|
|
97
|
+
Roasted with ❤️ by Claude
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Serious mode
|
|
101
|
+
```bash
|
|
102
|
+
roast --serious src/app.js
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Output:
|
|
106
|
+
```
|
|
107
|
+
📋 Professional Code Review
|
|
108
|
+
File: api-handler.js (JavaScript)
|
|
109
|
+
──────────────────────────────────────────────────
|
|
110
|
+
|
|
111
|
+
🚨 No input sanitization on user data - SQL injection risk
|
|
112
|
+
|
|
113
|
+
⚠️ Synchronous file operations will block the event loop
|
|
114
|
+
|
|
115
|
+
💡 Consider using async/await with fs.promises
|
|
116
|
+
|
|
117
|
+
✅ Good error handling structure
|
|
118
|
+
|
|
119
|
+
──────────────────────────────────────────────────
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Custom model
|
|
123
|
+
```bash
|
|
124
|
+
roast --model claude-opus-4 src/app.js
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## Supported Languages
|
|
128
|
+
|
|
129
|
+
JavaScript, TypeScript, Python, Go, Rust, Java, C, C++, Ruby, PHP, Swift, Kotlin, Shell, SQL, HTML, CSS, and more.
|
|
130
|
+
|
|
131
|
+
## Options
|
|
132
|
+
|
|
133
|
+
```
|
|
134
|
+
-s, --serious Professional review mode (no humor)
|
|
135
|
+
--severity <level> Roast severity: mild, medium, harsh (default: medium)
|
|
136
|
+
-m, --model <model> AI model to use (default: claude-sonnet-4-5)
|
|
137
|
+
--no-color Disable colors
|
|
138
|
+
-V, --version Output version
|
|
139
|
+
-h, --help Display help
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### Severity Levels
|
|
143
|
+
|
|
144
|
+
**Mild** (😊 Be Nice Mode): Friendly, encouraging feedback. Perfect for beginners or when you want constructive criticism with a supportive tone.
|
|
145
|
+
```bash
|
|
146
|
+
roast --severity mild src/app.js
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
**Medium** (🔥 Default): Balanced mix of humor and criticism. Sarcastic but helpful, like a senior dev at code review.
|
|
150
|
+
```bash
|
|
151
|
+
roast src/app.js
|
|
152
|
+
# or explicitly:
|
|
153
|
+
roast --severity medium src/app.js
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
**Harsh** (💀 No Mercy): Brutally honest, savage roasts. Only use this if you can handle the truth. Gordon Ramsay mode.
|
|
157
|
+
```bash
|
|
158
|
+
roast --severity harsh src/app.js
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Examples
|
|
162
|
+
|
|
163
|
+
### Example 1: Quick file roast
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
$ roast src/utils/array-helpers.js
|
|
167
|
+
|
|
168
|
+
🔥 CODE ROAST 🔥
|
|
169
|
+
Victim: array-helpers.js (JavaScript)
|
|
170
|
+
──────────────────────────────────────────────────
|
|
171
|
+
|
|
172
|
+
🔥 You wrote a custom array flatten function? Array.flat()
|
|
173
|
+
has been in JavaScript since 2019. ES2019 is not "too new."
|
|
174
|
+
|
|
175
|
+
🔥 uniqueArray uses indexOf in a loop - O(n²) complexity.
|
|
176
|
+
Set([...arr]) is O(n) and already built in.
|
|
177
|
+
|
|
178
|
+
💡 Half these functions are one-liners with modern JS:
|
|
179
|
+
flatten: arr.flat()
|
|
180
|
+
unique: [...new Set(arr)]
|
|
181
|
+
last: arr.at(-1)
|
|
182
|
+
|
|
183
|
+
✨ At least they work correctly. But you've essentially
|
|
184
|
+
reinvented lodash, poorly.
|
|
185
|
+
|
|
186
|
+
──────────────────────────────────────────────────
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Example 2: Serious mode for team PR review
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
$ roast --serious src/api/auth.ts
|
|
193
|
+
|
|
194
|
+
📋 Professional Code Review
|
|
195
|
+
File: auth.ts (TypeScript)
|
|
196
|
+
──────────────────────────────────────────────────
|
|
197
|
+
|
|
198
|
+
🚨 Password comparison using === instead of timing-safe compare
|
|
199
|
+
Risk: Timing attacks could leak password information
|
|
200
|
+
|
|
201
|
+
⚠️ JWT secret loaded from process.env without fallback check
|
|
202
|
+
Will crash on startup if JWT_SECRET is not set
|
|
203
|
+
|
|
204
|
+
💡 Consider using express-validator for input sanitization
|
|
205
|
+
|
|
206
|
+
✅ Good: Proper async/await usage throughout
|
|
207
|
+
✅ Good: TypeScript types are well-defined
|
|
208
|
+
|
|
209
|
+
⚠️ Token expiration set to 30 days - consider shorter duration
|
|
210
|
+
for sensitive operations
|
|
211
|
+
|
|
212
|
+
──────────────────────────────────────────────────
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Example 3: Review from stdin (pipe or paste)
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
$ cat suspicious-code.py | roast
|
|
219
|
+
|
|
220
|
+
🔥 CODE ROAST 🔥
|
|
221
|
+
Victim: stdin (Python)
|
|
222
|
+
──────────────────────────────────────────────────
|
|
223
|
+
|
|
224
|
+
🔥 eval() on user input? That's not a security vulnerability,
|
|
225
|
+
that's a welcome mat for hackers.
|
|
226
|
+
|
|
227
|
+
🔥 Bare except: catches everything including KeyboardInterrupt.
|
|
228
|
+
You can't even Ctrl+C out of this disaster.
|
|
229
|
+
|
|
230
|
+
🔥 Global variables modified inside functions with no documentation.
|
|
231
|
+
Reading this code is like a mystery novel where the butler did it,
|
|
232
|
+
but also the gardener, and maybe the protagonist.
|
|
233
|
+
|
|
234
|
+
💡 Use ast.literal_eval() for safe evaluation, or better yet,
|
|
235
|
+
json.loads() if you're parsing data.
|
|
236
|
+
|
|
237
|
+
──────────────────────────────────────────────────
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Example 4: Git diff review before commit
|
|
241
|
+
|
|
242
|
+
```bash
|
|
243
|
+
$ git diff src/payment-processor.js | roast --serious
|
|
244
|
+
|
|
245
|
+
📋 Professional Code Review
|
|
246
|
+
──────────────────────────────────────────────────
|
|
247
|
+
|
|
248
|
+
🚨 Changed error handling to swallow exceptions silently
|
|
249
|
+
Original code logged errors, new code hides them
|
|
250
|
+
|
|
251
|
+
⚠️ Removed input validation for transaction amount
|
|
252
|
+
Could now process negative or NaN values
|
|
253
|
+
|
|
254
|
+
🚨 API timeout increased from 5s to 60s
|
|
255
|
+
May cause cascading failures under load
|
|
256
|
+
|
|
257
|
+
Recommendation: These changes reduce system reliability.
|
|
258
|
+
Suggest reverting the exception handling changes.
|
|
259
|
+
|
|
260
|
+
──────────────────────────────────────────────────
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
### Example 5: Custom model for complex code
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
$ roast --model claude-opus-4 src/distributed-lock.go
|
|
267
|
+
|
|
268
|
+
🔥 CODE ROAST 🔥
|
|
269
|
+
Victim: distributed-lock.go (Go)
|
|
270
|
+
──────────────────────────────────────────────────
|
|
271
|
+
|
|
272
|
+
🔥 Your distributed lock implementation has a race condition
|
|
273
|
+
between checking and acquiring. Classic "check-then-act" bug.
|
|
274
|
+
|
|
275
|
+
🔥 Lock timeout is hardcoded to 10 seconds. Production load
|
|
276
|
+
spikes will turn this into a deadlock factory.
|
|
277
|
+
|
|
278
|
+
💡 Redis SETNX is atomic - use it directly instead of GET + SET.
|
|
279
|
+
Or better yet, use Redlock algorithm for multi-node safety.
|
|
280
|
+
|
|
281
|
+
🔥 Panic on Redis connection error. In distributed systems,
|
|
282
|
+
network failures are features, not exceptions.
|
|
283
|
+
|
|
284
|
+
✨ Good use of context for cancellation. That's the one part
|
|
285
|
+
that won't cause a 3 AM page.
|
|
286
|
+
|
|
287
|
+
──────────────────────────────────────────────────
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
---
|
|
291
|
+
|
|
292
|
+
### Example 6: Mild severity for learning
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
$ roast --severity mild beginner-script.py
|
|
296
|
+
|
|
297
|
+
😊 Friendly Code Review
|
|
298
|
+
Victim: beginner-script.py (Python)
|
|
299
|
+
──────────────────────────────────────────────────
|
|
300
|
+
|
|
301
|
+
💡 Great start! Your code works, which is the most important part.
|
|
302
|
+
|
|
303
|
+
💛 Small improvement: Instead of opening files without 'with',
|
|
304
|
+
try using context managers:
|
|
305
|
+
|
|
306
|
+
with open('file.txt', 'r') as f:
|
|
307
|
+
data = f.read()
|
|
308
|
+
|
|
309
|
+
This automatically closes the file for you!
|
|
310
|
+
|
|
311
|
+
💡 You're using global variables. As your program grows,
|
|
312
|
+
consider passing data as function parameters instead.
|
|
313
|
+
|
|
314
|
+
✨ Your variable names are clear and descriptive. Keep that up!
|
|
315
|
+
|
|
316
|
+
──────────────────────────────────────────────────
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
---
|
|
320
|
+
|
|
321
|
+
### Example 7: Harsh mode for reality check
|
|
322
|
+
|
|
323
|
+
```bash
|
|
324
|
+
$ roast --severity harsh legacy-spaghetti.php
|
|
325
|
+
|
|
326
|
+
💀 BRUTAL CODE ROAST 💀
|
|
327
|
+
Victim: legacy-spaghetti.php (PHP)
|
|
328
|
+
──────────────────────────────────────────────────
|
|
329
|
+
|
|
330
|
+
💀 This code is a war crime. The Geneva Convention should cover this.
|
|
331
|
+
|
|
332
|
+
💀 mysql_* functions were deprecated 11 years ago. This isn't
|
|
333
|
+
legacy code, it's a fossil.
|
|
334
|
+
|
|
335
|
+
💀 SQL injection vulnerabilities everywhere. You're concatenating
|
|
336
|
+
user input into queries like it's 1999. It was bad in 1999 too.
|
|
337
|
+
|
|
338
|
+
💀 Password stored in plaintext. Just... why? WHY?!
|
|
339
|
+
|
|
340
|
+
💀 4 levels of nested if statements with no clear logic. This is
|
|
341
|
+
a crime scene where the detective gave up and went home.
|
|
342
|
+
|
|
343
|
+
💀 Variable names like $a, $tmp, $data2. Were descriptive names
|
|
344
|
+
too expensive?
|
|
345
|
+
|
|
346
|
+
Reality check: This needs a complete rewrite. I'm not even sure
|
|
347
|
+
where to start. Maybe with fire.
|
|
348
|
+
|
|
349
|
+
──────────────────────────────────────────────────
|
|
350
|
+
Roasted with absolute honesty by Claude
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
### Example 8: TypeScript React component
|
|
356
|
+
|
|
357
|
+
```bash
|
|
358
|
+
$ roast src/components/UserDashboard.tsx
|
|
359
|
+
|
|
360
|
+
🔥 CODE ROAST 🔥
|
|
361
|
+
Victim: UserDashboard.tsx (TypeScript/React)
|
|
362
|
+
──────────────────────────────────────────────────
|
|
363
|
+
|
|
364
|
+
🔥 850 lines in one component. This isn't a component, it's a
|
|
365
|
+
monolith. Break it down before it breaks you.
|
|
366
|
+
|
|
367
|
+
🔥 useEffect with 12 dependencies? That's not reactive programming,
|
|
368
|
+
that's chaos with extra steps.
|
|
369
|
+
|
|
370
|
+
💡 Extract at least 4 sub-components:
|
|
371
|
+
- UserHeader
|
|
372
|
+
- ActivityFeed
|
|
373
|
+
- SettingsPanel
|
|
374
|
+
- NotificationCenter
|
|
375
|
+
|
|
376
|
+
🔥 Inline styles everywhere instead of styled-components or CSS modules.
|
|
377
|
+
Your future self will hate present you.
|
|
378
|
+
|
|
379
|
+
✨ Props are properly typed. That's good! Now use that discipline
|
|
380
|
+
everywhere else.
|
|
381
|
+
|
|
382
|
+
──────────────────────────────────────────────────
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
---
|
|
386
|
+
|
|
387
|
+
### Example 9: Shell script review
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
$ roast deploy.sh
|
|
391
|
+
|
|
392
|
+
🔥 CODE ROAST 🔥
|
|
393
|
+
Victim: deploy.sh (Shell)
|
|
394
|
+
──────────────────────────────────────────────────
|
|
395
|
+
|
|
396
|
+
🔥 No 'set -e' at the top. If step 1 fails, steps 2-10 will
|
|
397
|
+
still run and cause chaos.
|
|
398
|
+
|
|
399
|
+
🔥 rm -rf without any confirmation? Living dangerously, I see.
|
|
400
|
+
|
|
401
|
+
💡 Add error handling:
|
|
402
|
+
set -euo pipefail
|
|
403
|
+
|
|
404
|
+
This will:
|
|
405
|
+
- Exit on error (e)
|
|
406
|
+
- Fail on undefined variables (u)
|
|
407
|
+
- Catch errors in pipes (pipefail)
|
|
408
|
+
|
|
409
|
+
🔥 Hardcoded paths and credentials. Use environment variables:
|
|
410
|
+
${DB_HOST:-localhost}
|
|
411
|
+
|
|
412
|
+
✨ At least you have comments. That's rare for shell scripts.
|
|
413
|
+
|
|
414
|
+
──────────────────────────────────────────────────
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
---
|
|
418
|
+
|
|
419
|
+
### Example 10: SQL query review
|
|
420
|
+
|
|
421
|
+
```bash
|
|
422
|
+
$ roast db/queries.sql
|
|
423
|
+
|
|
424
|
+
🔥 CODE ROAST 🔥
|
|
425
|
+
Victim: queries.sql (SQL)
|
|
426
|
+
──────────────────────────────────────────────────
|
|
427
|
+
|
|
428
|
+
🔥 SELECT * in production queries. Your DBA is crying somewhere.
|
|
429
|
+
List the exact columns you need.
|
|
430
|
+
|
|
431
|
+
🔥 No indexes on the WHERE clause columns. This will be fast now
|
|
432
|
+
with 100 rows. With 1,000,000 rows? Enjoy your 30-second queries.
|
|
433
|
+
|
|
434
|
+
💡 Add indexes:
|
|
435
|
+
CREATE INDEX idx_users_email ON users(email);
|
|
436
|
+
CREATE INDEX idx_orders_user_created ON orders(user_id, created_at);
|
|
437
|
+
|
|
438
|
+
🔥 LEFT JOIN without understanding why. If you need all rows from
|
|
439
|
+
both tables, that's a FULL JOIN (or you don't actually need all rows).
|
|
440
|
+
|
|
441
|
+
✨ Query is at least readable and properly formatted.
|
|
442
|
+
|
|
443
|
+
──────────────────────────────────────────────────
|
|
444
|
+
```
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
### Example 11: Rust code review
|
|
449
|
+
|
|
450
|
+
```bash
|
|
451
|
+
$ roast src/main.rs
|
|
452
|
+
|
|
453
|
+
🔥 CODE ROAST 🔥
|
|
454
|
+
Victim: main.rs (Rust)
|
|
455
|
+
──────────────────────────────────────────────────
|
|
456
|
+
|
|
457
|
+
🔥 .unwrap() everywhere. You learned Rust yesterday, didn't you?
|
|
458
|
+
|
|
459
|
+
💡 Use proper error handling:
|
|
460
|
+
// Instead of:
|
|
461
|
+
let file = File::open("data.txt").unwrap();
|
|
462
|
+
|
|
463
|
+
// Use:
|
|
464
|
+
let file = File::open("data.txt")?;
|
|
465
|
+
// or
|
|
466
|
+
let file = File::open("data.txt")
|
|
467
|
+
.expect("Failed to open data.txt");
|
|
468
|
+
|
|
469
|
+
🔥 Cloning everything to avoid fighting the borrow checker.
|
|
470
|
+
That's like buying a sports car and only driving in first gear.
|
|
471
|
+
|
|
472
|
+
✨ You're using match instead of if-let. Good! Pattern matching
|
|
473
|
+
is the way.
|
|
474
|
+
|
|
475
|
+
💡 Learn lifetimes. They're scary at first, but they'll save you
|
|
476
|
+
from these clones.
|
|
477
|
+
|
|
478
|
+
──────────────────────────────────────────────────
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
## Real-World Scenarios
|
|
482
|
+
|
|
483
|
+
### Pre-commit sanity check
|
|
484
|
+
```bash
|
|
485
|
+
# About to commit that refactor you've been working on
|
|
486
|
+
$ git diff HEAD src/auth.js | roast
|
|
487
|
+
|
|
488
|
+
🔥 You're exporting the private key in plaintext? Bold strategy.
|
|
489
|
+
|
|
490
|
+
🔥 This regex will match "admin@evil.com" as a valid admin email.
|
|
491
|
+
Better tighten that up unless you're running a very open company.
|
|
492
|
+
|
|
493
|
+
💡 hash.compare() is async but you're not awaiting it. This will
|
|
494
|
+
always return true. Always. Every time. 100% authentication success rate!
|
|
495
|
+
|
|
496
|
+
# ...okay maybe I should test this first
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
### Reviewing that "quick fix" from 2am
|
|
500
|
+
```bash
|
|
501
|
+
$ roast src/hotfix-do-not-touch.js
|
|
502
|
+
|
|
503
|
+
🔥 File name is literally "do-not-touch.js" - that's a red flag
|
|
504
|
+
wrapped in another red flag
|
|
505
|
+
|
|
506
|
+
🔥 You're catching errors and logging "it broke lol". When production
|
|
507
|
+
is on fire, your logs will just say "it broke lol" repeated 50,000 times.
|
|
508
|
+
|
|
509
|
+
🔥 This setTimeout is set to 86400000ms. That's 24 hours. Hope nobody's
|
|
510
|
+
waiting for this response.
|
|
511
|
+
|
|
512
|
+
✨ The actual logic is... fine? But please, for the love of debugging,
|
|
513
|
+
add better error messages.
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### Checking tutorial code before copy-paste
|
|
517
|
+
```bash
|
|
518
|
+
$ curl -s https://example.com/tutorial.js | roast
|
|
519
|
+
|
|
520
|
+
🔥 This tutorial is using var in 2026. It was written during the
|
|
521
|
+
Mesozoic Era and hasn't been updated since.
|
|
522
|
+
|
|
523
|
+
⚠️ jQuery is loaded from an HTTP URL. That's a mixed content warning
|
|
524
|
+
waiting to happen.
|
|
525
|
+
|
|
526
|
+
💡 Modern replacement using fetch() would be 10 lines and zero
|
|
527
|
+
dependencies. Just saying.
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### The "I learned this yesterday" review
|
|
531
|
+
```bash
|
|
532
|
+
# Just picked up Rust, wrote first program
|
|
533
|
+
$ roast hello.rs --serious
|
|
534
|
+
|
|
535
|
+
📋 Professional Code Review
|
|
536
|
+
──────────────────────────────────────────────────
|
|
537
|
+
|
|
538
|
+
✅ Proper error handling with Result type
|
|
539
|
+
|
|
540
|
+
⚠️ .unwrap() on line 8 will panic on error. Consider using
|
|
541
|
+
expect() with a meaningful message, or propagate with ?
|
|
542
|
+
|
|
543
|
+
💡 String ownership is correct, but you're cloning unnecessarily
|
|
544
|
+
on line 12. Use a reference: &user_name
|
|
545
|
+
|
|
546
|
+
✅ Good use of match for control flow
|
|
547
|
+
|
|
548
|
+
Overall: Solid first program. Remove the unwrap() and you're good to go.
|
|
549
|
+
```
|
|
550
|
+
|
|
551
|
+
### Legacy code archaeology
|
|
552
|
+
```bash
|
|
553
|
+
$ roast legacy/customer-import-final-v3-NEW-USE-THIS.php
|
|
554
|
+
|
|
555
|
+
🔥 Based on the filename, this has been "final" at least 3 times.
|
|
556
|
+
That's not a good sign.
|
|
557
|
+
|
|
558
|
+
🔥 mysql_connect() was deprecated in PHP 5.5 (2013) and removed in
|
|
559
|
+
PHP 7 (2015). This code is old enough to vote.
|
|
560
|
+
|
|
561
|
+
🔥 SQL query is concatenating user input directly. This is how
|
|
562
|
+
Little Bobby Tables drops your database.
|
|
563
|
+
|
|
564
|
+
🔥 No password hashing - passwords stored in plaintext. In the
|
|
565
|
+
event of a breach, this is "directly to jail, do not pass go" territory.
|
|
566
|
+
|
|
567
|
+
💡 Complete rewrite recommended. Start fresh with PDO and password_hash().
|
|
568
|
+
This is beyond roasting, this needs a Viking funeral.
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
### Team code style check
|
|
572
|
+
```bash
|
|
573
|
+
# Check if the new junior's code matches your style
|
|
574
|
+
$ roast --serious src/components/UserCard.jsx
|
|
575
|
+
|
|
576
|
+
📋 Professional Code Review
|
|
577
|
+
──────────────────────────────────────────────────
|
|
578
|
+
|
|
579
|
+
⚠️ Component is 450 lines long. Consider splitting into smaller pieces.
|
|
580
|
+
|
|
581
|
+
⚠️ Inline styles instead of CSS modules/styled-components
|
|
582
|
+
|
|
583
|
+
💡 Three useState hooks could be combined into useReducer
|
|
584
|
+
|
|
585
|
+
✅ Proper PropTypes definitions
|
|
586
|
+
|
|
587
|
+
✅ Good accessibility attributes (aria-labels, roles)
|
|
588
|
+
|
|
589
|
+
⚠️ useEffect missing dependency 'userId' - will cause stale closures
|
|
590
|
+
|
|
591
|
+
Recommendation: Works, but needs refactoring before it grows larger.
|
|
592
|
+
```
|
|
593
|
+
|
|
594
|
+
## Use Cases
|
|
595
|
+
|
|
596
|
+
### 1. **Solo Developer - Be Your Own Code Reviewer**
|
|
597
|
+
|
|
598
|
+
Working alone? No team to review your code? `roast` fills that gap.
|
|
599
|
+
|
|
600
|
+
```bash
|
|
601
|
+
$ roast src/new-feature.js
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
**Benefit:** Catch bugs, security issues, and bad patterns before they hit production. Get a second pair of (AI) eyes on your work.
|
|
605
|
+
|
|
606
|
+
**When to use:**
|
|
607
|
+
- Before committing new features
|
|
608
|
+
- After refactoring
|
|
609
|
+
- When learning a new language/framework
|
|
610
|
+
- Before deploying to production
|
|
611
|
+
|
|
612
|
+
---
|
|
613
|
+
|
|
614
|
+
### 2. **Learning & Skill Building**
|
|
615
|
+
|
|
616
|
+
Picked up a new language? `roast` teaches by critiquing.
|
|
617
|
+
|
|
618
|
+
```bash
|
|
619
|
+
# First Python script
|
|
620
|
+
$ roast my_first_app.py
|
|
621
|
+
|
|
622
|
+
# First Rust program
|
|
623
|
+
$ roast --serious main.rs
|
|
624
|
+
```
|
|
625
|
+
|
|
626
|
+
**Benefit:** Learn best practices, idioms, and common pitfalls by seeing them in your own code. Use `--severity mild` for encouragement while learning.
|
|
627
|
+
|
|
628
|
+
---
|
|
629
|
+
|
|
630
|
+
### 3. **Pre-Commit Quality Gate**
|
|
631
|
+
|
|
632
|
+
Add `roast` to your git hooks to enforce quality before commits.
|
|
633
|
+
|
|
634
|
+
```bash
|
|
635
|
+
# .git/hooks/pre-commit
|
|
636
|
+
#!/bin/bash
|
|
637
|
+
git diff --cached --name-only --diff-filter=ACM | \
|
|
638
|
+
grep -E '\.(js|ts|py|go)$' | \
|
|
639
|
+
xargs -I {} roast --serious {} || exit 1
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
**Benefit:** Automate code quality checks. Catch issues before CI, before code review, before your team sees them.
|
|
643
|
+
|
|
644
|
+
---
|
|
645
|
+
|
|
646
|
+
### 4. **Onboarding to New Codebases**
|
|
647
|
+
|
|
648
|
+
Just joined a team with a large codebase? Use `roast` to understand patterns.
|
|
649
|
+
|
|
650
|
+
```bash
|
|
651
|
+
$ roast src/core/auth-handler.js --serious
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
The AI will explain what the code does, highlight concerns, and suggest improvements. It's like having a senior dev walk you through the code.
|
|
655
|
+
|
|
656
|
+
**Benefit:** Faster onboarding. Understand existing patterns and anti-patterns.
|
|
657
|
+
|
|
658
|
+
---
|
|
659
|
+
|
|
660
|
+
### 5. **Legacy Code Assessment**
|
|
661
|
+
|
|
662
|
+
Inherited a legacy project? Get an honest assessment of what you're dealing with.
|
|
663
|
+
|
|
664
|
+
```bash
|
|
665
|
+
$ roast legacy/modules/payment-v1.php --severity harsh
|
|
666
|
+
```
|
|
667
|
+
|
|
668
|
+
**Benefit:** Prioritize refactoring. Know what's salvageable and what needs rewriting.
|
|
669
|
+
|
|
670
|
+
---
|
|
671
|
+
|
|
672
|
+
### 6. **Teaching & Mentoring**
|
|
673
|
+
|
|
674
|
+
Teaching someone to code? Show them what good vs. bad looks like.
|
|
675
|
+
|
|
676
|
+
```bash
|
|
677
|
+
# Student's code
|
|
678
|
+
$ roast student-assignment.py --severity mild
|
|
679
|
+
|
|
680
|
+
# Show them both roast and serious mode
|
|
681
|
+
$ roast --serious student-assignment.py
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
**Benefit:** Consistent, patient feedback. Teaches best practices without judgment.
|
|
685
|
+
|
|
686
|
+
---
|
|
687
|
+
|
|
688
|
+
### 7. **Code Review Prep (Before Human Review)**
|
|
689
|
+
|
|
690
|
+
Before requesting a PR review from teammates, run `roast` to catch obvious issues.
|
|
691
|
+
|
|
692
|
+
```bash
|
|
693
|
+
$ git diff main...feature-branch | roast --serious
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
Fix the issues `roast` finds, THEN request human review.
|
|
697
|
+
|
|
698
|
+
**Benefit:** Don't waste teammates' time on trivial issues. Submit cleaner PRs. Build a reputation for quality.
|
|
699
|
+
|
|
700
|
+
## Performance Tips
|
|
701
|
+
|
|
702
|
+
### 1. **Use Shell Aliases for Common Workflows**
|
|
703
|
+
|
|
704
|
+
Create shortcuts for frequent roast scenarios:
|
|
705
|
+
|
|
706
|
+
```bash
|
|
707
|
+
# Add to ~/.bashrc or ~/.zshrc
|
|
708
|
+
alias roast-js='roast --serious'
|
|
709
|
+
alias roast-diff='git diff | roast --serious'
|
|
710
|
+
alias roast-mild='roast --severity mild'
|
|
711
|
+
alias roast-harsh='roast --severity harsh'
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
Now just type:
|
|
715
|
+
```bash
|
|
716
|
+
$ roast-diff # Review uncommitted changes
|
|
717
|
+
$ roast-js src/app.js # Serious review
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
---
|
|
721
|
+
|
|
722
|
+
### 2. **Batch Review Multiple Files**
|
|
723
|
+
|
|
724
|
+
Use shell loops for bulk reviews:
|
|
725
|
+
|
|
726
|
+
```bash
|
|
727
|
+
# Review all JavaScript files in src/
|
|
728
|
+
for file in src/**/*.js; do
|
|
729
|
+
echo "=== $file ==="
|
|
730
|
+
roast --serious "$file"
|
|
731
|
+
done
|
|
732
|
+
|
|
733
|
+
# Or with find
|
|
734
|
+
find src -name "*.py" -exec roast --serious {} \;
|
|
735
|
+
```
|
|
736
|
+
|
|
737
|
+
**Save results:**
|
|
738
|
+
```bash
|
|
739
|
+
for file in src/**/*.js; do
|
|
740
|
+
roast --serious "$file" > "reviews/$(basename $file).review.txt"
|
|
741
|
+
done
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
---
|
|
745
|
+
|
|
746
|
+
### 3. **Optimize API Costs**
|
|
747
|
+
|
|
748
|
+
Roasting uses Anthropic's API. To reduce costs:
|
|
749
|
+
|
|
750
|
+
**a) Review only changed files:**
|
|
751
|
+
```bash
|
|
752
|
+
git diff --name-only | grep -E '\.(js|ts|py)$' | xargs -I {} roast {}
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
**b) Use haiku model for simple reviews** (modify source code):
|
|
756
|
+
```javascript
|
|
757
|
+
// In lib/roast.js, change:
|
|
758
|
+
model: 'claude-haiku-4-5' // Faster, cheaper, less detailed
|
|
759
|
+
```
|
|
760
|
+
|
|
761
|
+
**c) Review smaller code sections:**
|
|
762
|
+
```bash
|
|
763
|
+
# Instead of entire 1000-line file
|
|
764
|
+
$ head -100 large-file.js | roast
|
|
765
|
+
```
|
|
766
|
+
|
|
767
|
+
---
|
|
768
|
+
|
|
769
|
+
### 4. **Cache Reviews Locally (Manual)**
|
|
770
|
+
|
|
771
|
+
For files you review repeatedly:
|
|
772
|
+
|
|
773
|
+
```bash
|
|
774
|
+
# Save review for later reference
|
|
775
|
+
$ roast src/utils.js > reviews/utils-2026-02-08.txt
|
|
776
|
+
|
|
777
|
+
# Compare with previous review
|
|
778
|
+
$ diff reviews/utils-2026-02-01.txt reviews/utils-2026-02-08.txt
|
|
779
|
+
```
|
|
780
|
+
|
|
781
|
+
---
|
|
782
|
+
|
|
783
|
+
### 5. **Combine with Git Hooks for Automation**
|
|
784
|
+
|
|
785
|
+
**Pre-commit hook** (review before committing):
|
|
786
|
+
```bash
|
|
787
|
+
#!/bin/bash
|
|
788
|
+
# .git/hooks/pre-commit
|
|
789
|
+
git diff --cached --name-only | \
|
|
790
|
+
grep -E '\.(js|ts)$' | \
|
|
791
|
+
xargs -I {} roast --serious {}
|
|
792
|
+
|
|
793
|
+
read -p "Proceed with commit? (y/n) " -n 1 -r
|
|
794
|
+
echo
|
|
795
|
+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
796
|
+
exit 1
|
|
797
|
+
fi
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
**Pre-push hook** (final check before pushing):
|
|
801
|
+
```bash
|
|
802
|
+
#!/bin/bash
|
|
803
|
+
# .git/hooks/pre-push
|
|
804
|
+
git diff origin/main...HEAD --name-only | \
|
|
805
|
+
grep -E '\.(py|js|go)$' | \
|
|
806
|
+
xargs -I {} roast --serious {} > /tmp/pre-push-review.txt
|
|
807
|
+
|
|
808
|
+
cat /tmp/pre-push-review.txt
|
|
809
|
+
```
|
|
810
|
+
|
|
811
|
+
---
|
|
812
|
+
|
|
813
|
+
### 6. **Parallel Processing for Large Projects**
|
|
814
|
+
|
|
815
|
+
Use GNU parallel for speed:
|
|
816
|
+
|
|
817
|
+
```bash
|
|
818
|
+
# Install: brew install parallel (macOS) or apt-get install parallel (Linux)
|
|
819
|
+
|
|
820
|
+
# Review all files in parallel (4 at a time)
|
|
821
|
+
find src -name "*.js" | parallel -j 4 roast --serious {} > reviews.txt
|
|
822
|
+
```
|
|
823
|
+
|
|
824
|
+
---
|
|
825
|
+
|
|
826
|
+
### 7. **Smart File Selection**
|
|
827
|
+
|
|
828
|
+
Don't roast everything. Focus on:
|
|
829
|
+
|
|
830
|
+
**New/changed files:**
|
|
831
|
+
```bash
|
|
832
|
+
git diff --name-only main | xargs -I {} roast {}
|
|
833
|
+
```
|
|
834
|
+
|
|
835
|
+
**Complex files (high line count):**
|
|
836
|
+
```bash
|
|
837
|
+
find src -name "*.js" -exec wc -l {} \; | \
|
|
838
|
+
sort -rn | head -10 | \
|
|
839
|
+
awk '{print $2}' | xargs -I {} roast {}
|
|
840
|
+
```
|
|
841
|
+
|
|
842
|
+
**Files with recent bugs (from git history):**
|
|
843
|
+
```bash
|
|
844
|
+
git log --format=format: --name-only | \
|
|
845
|
+
sort | uniq -c | sort -rn | \
|
|
846
|
+
head -10 | awk '{print $2}' | \
|
|
847
|
+
xargs -I {} roast --serious {}
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
## Troubleshooting
|
|
851
|
+
|
|
852
|
+
### 1. **"ANTHROPIC_API_KEY not set" error**
|
|
853
|
+
|
|
854
|
+
**Problem:**
|
|
855
|
+
```bash
|
|
856
|
+
$ roast src/app.js
|
|
857
|
+
💥 Error: ANTHROPIC_API_KEY environment variable is required
|
|
858
|
+
```
|
|
859
|
+
|
|
860
|
+
**Solutions:**
|
|
861
|
+
|
|
862
|
+
a) Set for current session:
|
|
863
|
+
```bash
|
|
864
|
+
export ANTHROPIC_API_KEY="sk-ant-your-key-here"
|
|
865
|
+
```
|
|
866
|
+
|
|
867
|
+
b) Make it permanent (add to shell config):
|
|
868
|
+
```bash
|
|
869
|
+
# For bash
|
|
870
|
+
echo 'export ANTHROPIC_API_KEY="sk-ant-your-key"' >> ~/.bashrc
|
|
871
|
+
source ~/.bashrc
|
|
872
|
+
|
|
873
|
+
# For zsh
|
|
874
|
+
echo 'export ANTHROPIC_API_KEY="sk-ant-your-key"' >> ~/.zshrc
|
|
875
|
+
source ~/.zshrc
|
|
876
|
+
```
|
|
877
|
+
|
|
878
|
+
c) Get your API key:
|
|
879
|
+
Visit [console.anthropic.com/settings/keys](https://console.anthropic.com/settings/keys)
|
|
880
|
+
|
|
881
|
+
---
|
|
882
|
+
|
|
883
|
+
### 2. **"Cannot find file" error**
|
|
884
|
+
|
|
885
|
+
**Problem:**
|
|
886
|
+
```bash
|
|
887
|
+
$ roast src/app.js
|
|
888
|
+
💥 Error: ENOENT: no such file or directory
|
|
889
|
+
```
|
|
890
|
+
|
|
891
|
+
**Solutions:**
|
|
892
|
+
|
|
893
|
+
a) Check the file path:
|
|
894
|
+
```bash
|
|
895
|
+
$ ls -la src/app.js # Verify file exists
|
|
896
|
+
```
|
|
897
|
+
|
|
898
|
+
b) Use absolute path:
|
|
899
|
+
```bash
|
|
900
|
+
$ roast /full/path/to/src/app.js
|
|
901
|
+
```
|
|
902
|
+
|
|
903
|
+
c) Check current directory:
|
|
904
|
+
```bash
|
|
905
|
+
$ pwd
|
|
906
|
+
$ roast ./src/app.js
|
|
907
|
+
```
|
|
908
|
+
|
|
909
|
+
---
|
|
910
|
+
|
|
911
|
+
### 3. **Empty or generic roast output**
|
|
912
|
+
|
|
913
|
+
**Problem:**
|
|
914
|
+
```bash
|
|
915
|
+
$ roast my-code.js
|
|
916
|
+
|
|
917
|
+
🔥 CODE ROAST 🔥
|
|
918
|
+
──────────────────────────────────────────────────
|
|
919
|
+
This code looks fine.
|
|
920
|
+
──────────────────────────────────────────────────
|
|
921
|
+
```
|
|
922
|
+
|
|
923
|
+
**Solutions:**
|
|
924
|
+
|
|
925
|
+
a) File might be too small/simple:
|
|
926
|
+
```bash
|
|
927
|
+
# The code might genuinely be fine!
|
|
928
|
+
$ wc -l my-code.js # Check line count
|
|
929
|
+
```
|
|
930
|
+
|
|
931
|
+
b) Language not detected. Rename file with proper extension:
|
|
932
|
+
```bash
|
|
933
|
+
$ mv script script.py # Add .py extension
|
|
934
|
+
$ roast script.py
|
|
935
|
+
```
|
|
936
|
+
|
|
937
|
+
c) Use verbose mode (if available) or try serious mode:
|
|
938
|
+
```bash
|
|
939
|
+
$ roast --serious my-code.js
|
|
940
|
+
```
|
|
941
|
+
|
|
942
|
+
---
|
|
943
|
+
|
|
944
|
+
### 4. **"Invalid severity level" error**
|
|
945
|
+
|
|
946
|
+
**Problem:**
|
|
947
|
+
```bash
|
|
948
|
+
$ roast --severity extreme src/app.js
|
|
949
|
+
💥 Error: Invalid severity level: extreme
|
|
950
|
+
Valid options: mild, medium, harsh
|
|
951
|
+
```
|
|
952
|
+
|
|
953
|
+
**Solutions:**
|
|
954
|
+
|
|
955
|
+
a) Use valid severity:
|
|
956
|
+
```bash
|
|
957
|
+
$ roast --severity harsh src/app.js
|
|
958
|
+
```
|
|
959
|
+
|
|
960
|
+
b) Check available options:
|
|
961
|
+
```bash
|
|
962
|
+
$ roast --help
|
|
963
|
+
```
|
|
964
|
+
|
|
965
|
+
---
|
|
966
|
+
|
|
967
|
+
### 5. **Command not found: roast**
|
|
968
|
+
|
|
969
|
+
**Problem:**
|
|
970
|
+
```bash
|
|
971
|
+
$ npm install -g @muin/roast
|
|
972
|
+
$ roast src/app.js
|
|
973
|
+
zsh: command not found: roast
|
|
974
|
+
```
|
|
975
|
+
|
|
976
|
+
**Solutions:**
|
|
977
|
+
|
|
978
|
+
a) Check npm global bin directory is in PATH:
|
|
979
|
+
```bash
|
|
980
|
+
$ npm config get prefix
|
|
981
|
+
# Should show something like /usr/local or ~/.npm-global
|
|
982
|
+
|
|
983
|
+
$ echo $PATH
|
|
984
|
+
# Should include the bin directory from above
|
|
985
|
+
```
|
|
986
|
+
|
|
987
|
+
b) Fix PATH (add to ~/.bashrc or ~/.zshrc):
|
|
988
|
+
```bash
|
|
989
|
+
export PATH="$PATH:$(npm config get prefix)/bin"
|
|
990
|
+
source ~/.bashrc # or ~/.zshrc
|
|
991
|
+
```
|
|
992
|
+
|
|
993
|
+
c) Use npx instead (doesn't require global install):
|
|
994
|
+
```bash
|
|
995
|
+
$ npx @muin/roast src/app.js
|
|
996
|
+
```
|
|
997
|
+
|
|
998
|
+
---
|
|
999
|
+
|
|
1000
|
+
### 6. **API rate limit errors**
|
|
1001
|
+
|
|
1002
|
+
**Problem:**
|
|
1003
|
+
```bash
|
|
1004
|
+
$ roast src/app.js
|
|
1005
|
+
💥 Error: rate_limit_error: You have exceeded your API rate limit
|
|
1006
|
+
```
|
|
1007
|
+
|
|
1008
|
+
**Solutions:**
|
|
1009
|
+
|
|
1010
|
+
a) Wait a minute and retry (Anthropic has per-minute limits)
|
|
1011
|
+
|
|
1012
|
+
b) Check your rate limits:
|
|
1013
|
+
Visit [console.anthropic.com/settings/limits](https://console.anthropic.com/settings/limits)
|
|
1014
|
+
|
|
1015
|
+
c) For batch processing, add delays:
|
|
1016
|
+
```bash
|
|
1017
|
+
for file in src/*.js; do
|
|
1018
|
+
roast "$file"
|
|
1019
|
+
sleep 3 # Wait 3 seconds between calls
|
|
1020
|
+
done
|
|
1021
|
+
```
|
|
1022
|
+
|
|
1023
|
+
d) Upgrade to higher tier if you hit limits regularly
|
|
1024
|
+
|
|
1025
|
+
---
|
|
1026
|
+
|
|
1027
|
+
### 7. **Colored output broken / weird characters**
|
|
1028
|
+
|
|
1029
|
+
**Problem:**
|
|
1030
|
+
```bash
|
|
1031
|
+
$ roast src/app.js
|
|
1032
|
+
[31m🔥[0m [1mCODE ROAST[0m...
|
|
1033
|
+
```
|
|
1034
|
+
|
|
1035
|
+
**Solutions:**
|
|
1036
|
+
|
|
1037
|
+
a) Disable colors:
|
|
1038
|
+
```bash
|
|
1039
|
+
$ roast --no-color src/app.js
|
|
1040
|
+
```
|
|
1041
|
+
|
|
1042
|
+
b) Check terminal color support:
|
|
1043
|
+
```bash
|
|
1044
|
+
$ echo $TERM
|
|
1045
|
+
# Should be xterm-256color or similar
|
|
1046
|
+
|
|
1047
|
+
# If it's 'dumb', set it:
|
|
1048
|
+
export TERM=xterm-256color
|
|
1049
|
+
```
|
|
1050
|
+
|
|
1051
|
+
c) Redirect to file (colors auto-disabled):
|
|
1052
|
+
```bash
|
|
1053
|
+
$ roast src/app.js > review.txt
|
|
1054
|
+
```
|
|
1055
|
+
|
|
1056
|
+
---
|
|
1057
|
+
|
|
1058
|
+
### 8. **Very slow responses (>30 seconds)**
|
|
1059
|
+
|
|
1060
|
+
**Problem:**
|
|
1061
|
+
```bash
|
|
1062
|
+
$ roast very-large-file.js
|
|
1063
|
+
# ...waiting forever...
|
|
1064
|
+
```
|
|
1065
|
+
|
|
1066
|
+
**Solutions:**
|
|
1067
|
+
|
|
1068
|
+
a) File might be too large. Claude has token limits (~100k tokens ≈ 75k words).
|
|
1069
|
+
|
|
1070
|
+
Check file size:
|
|
1071
|
+
```bash
|
|
1072
|
+
$ wc -l very-large-file.js
|
|
1073
|
+
5000 very-large-file.js # Too large!
|
|
1074
|
+
```
|
|
1075
|
+
|
|
1076
|
+
b) Split into smaller files:
|
|
1077
|
+
```bash
|
|
1078
|
+
$ split -l 500 large-file.js part-
|
|
1079
|
+
$ roast part-aa
|
|
1080
|
+
$ roast part-ab
|
|
1081
|
+
```
|
|
1082
|
+
|
|
1083
|
+
c) Review only a section:
|
|
1084
|
+
```bash
|
|
1085
|
+
$ head -300 large-file.js | roast # First 300 lines
|
|
1086
|
+
```
|
|
1087
|
+
|
|
1088
|
+
d) Check Anthropic API status:
|
|
1089
|
+
```bash
|
|
1090
|
+
$ curl -I https://api.anthropic.com
|
|
1091
|
+
```
|
|
1092
|
+
|
|
1093
|
+
---
|
|
1094
|
+
|
|
1095
|
+
### 9. **Model not found error**
|
|
1096
|
+
|
|
1097
|
+
**Problem:**
|
|
1098
|
+
```bash
|
|
1099
|
+
$ roast --model claude-opus-99 src/app.js
|
|
1100
|
+
💥 Error: model 'claude-opus-99' not found
|
|
1101
|
+
```
|
|
1102
|
+
|
|
1103
|
+
**Solutions:**
|
|
1104
|
+
|
|
1105
|
+
a) Use a valid model name:
|
|
1106
|
+
```bash
|
|
1107
|
+
$ roast --model claude-sonnet-4-5 src/app.js
|
|
1108
|
+
$ roast --model claude-opus-4 src/app.js
|
|
1109
|
+
$ roast --model claude-haiku-4-5 src/app.js
|
|
1110
|
+
```
|
|
1111
|
+
|
|
1112
|
+
b) Check available models at [docs.anthropic.com](https://docs.anthropic.com/en/docs/models-overview)
|
|
1113
|
+
|
|
1114
|
+
c) Omit the flag to use default:
|
|
1115
|
+
```bash
|
|
1116
|
+
$ roast src/app.js # Uses default model
|
|
1117
|
+
```
|
|
1118
|
+
|
|
1119
|
+
---
|
|
1120
|
+
|
|
1121
|
+
### 10. **Network/connection errors**
|
|
1122
|
+
|
|
1123
|
+
**Problem:**
|
|
1124
|
+
```bash
|
|
1125
|
+
$ roast src/app.js
|
|
1126
|
+
💥 Error: connect ETIMEDOUT
|
|
1127
|
+
```
|
|
1128
|
+
|
|
1129
|
+
**Solutions:**
|
|
1130
|
+
|
|
1131
|
+
a) Check internet connection:
|
|
1132
|
+
```bash
|
|
1133
|
+
$ ping api.anthropic.com
|
|
1134
|
+
```
|
|
1135
|
+
|
|
1136
|
+
b) Check if firewall/VPN is blocking:
|
|
1137
|
+
```bash
|
|
1138
|
+
$ curl https://api.anthropic.com
|
|
1139
|
+
```
|
|
1140
|
+
|
|
1141
|
+
c) Set proxy if behind corporate firewall:
|
|
1142
|
+
```bash
|
|
1143
|
+
export HTTP_PROXY=http://proxy.company.com:8080
|
|
1144
|
+
export HTTPS_PROXY=http://proxy.company.com:8080
|
|
1145
|
+
```
|
|
1146
|
+
|
|
1147
|
+
---
|
|
1148
|
+
|
|
1149
|
+
### 11. **Permission errors on Windows**
|
|
1150
|
+
|
|
1151
|
+
**Problem:**
|
|
1152
|
+
```bash
|
|
1153
|
+
C:\> npm install -g @muin/roast
|
|
1154
|
+
Error: EACCES: permission denied
|
|
1155
|
+
```
|
|
1156
|
+
|
|
1157
|
+
**Solutions:**
|
|
1158
|
+
|
|
1159
|
+
a) Run as Administrator (PowerShell):
|
|
1160
|
+
```powershell
|
|
1161
|
+
# Right-click PowerShell → "Run as Administrator"
|
|
1162
|
+
PS> npm install -g @muin/roast
|
|
1163
|
+
```
|
|
1164
|
+
|
|
1165
|
+
b) Or use npx (no install needed):
|
|
1166
|
+
```powershell
|
|
1167
|
+
PS> npx @muin/roast src/app.js
|
|
1168
|
+
```
|
|
1169
|
+
|
|
1170
|
+
---
|
|
1171
|
+
|
|
1172
|
+
### 12. **File encoding issues (non-UTF8)**
|
|
1173
|
+
|
|
1174
|
+
**Problem:**
|
|
1175
|
+
```bash
|
|
1176
|
+
$ roast legacy-code.php
|
|
1177
|
+
💥 Error: Invalid UTF-8 sequence
|
|
1178
|
+
```
|
|
1179
|
+
|
|
1180
|
+
**Solutions:**
|
|
1181
|
+
|
|
1182
|
+
a) Convert file to UTF-8:
|
|
1183
|
+
```bash
|
|
1184
|
+
$ iconv -f ISO-8859-1 -t UTF-8 legacy-code.php > legacy-code-utf8.php
|
|
1185
|
+
$ roast legacy-code-utf8.php
|
|
1186
|
+
```
|
|
1187
|
+
|
|
1188
|
+
b) Check current encoding:
|
|
1189
|
+
```bash
|
|
1190
|
+
$ file legacy-code.php
|
|
1191
|
+
legacy-code.php: PHP script, ISO-8859 text
|
|
1192
|
+
```
|
|
1193
|
+
|
|
1194
|
+
## Frequently Asked Questions (FAQ)
|
|
1195
|
+
|
|
1196
|
+
### 1. **Is my code sent to Anthropic's servers?**
|
|
1197
|
+
|
|
1198
|
+
**Yes.** When you run `roast`, the file contents are sent to Anthropic's Claude API for analysis.
|
|
1199
|
+
|
|
1200
|
+
**Security note:** Do NOT roast files containing:
|
|
1201
|
+
- API keys, passwords, or secrets
|
|
1202
|
+
- Proprietary algorithms (if you have strict confidentiality agreements)
|
|
1203
|
+
- PII (personally identifiable information) in test data
|
|
1204
|
+
- Anything you wouldn't share with a third party
|
|
1205
|
+
|
|
1206
|
+
Anthropic's privacy policy: https://www.anthropic.com/legal/privacy
|
|
1207
|
+
|
|
1208
|
+
---
|
|
1209
|
+
|
|
1210
|
+
### 2. **How much does it cost to use?**
|
|
1211
|
+
|
|
1212
|
+
`roast` itself is free and open-source. However, it uses Anthropic's Claude API which has usage costs:
|
|
1213
|
+
|
|
1214
|
+
- **Free tier:** $5 credit (enough for ~100-300 roasts depending on file size)
|
|
1215
|
+
- **After that:** ~$0.01-0.05 per roast (1-5 cents)
|
|
1216
|
+
- **Monthly estimate:** If you roast 20 files/day: ~$10-30/month
|
|
1217
|
+
|
|
1218
|
+
Check pricing: https://www.anthropic.com/pricing
|
|
1219
|
+
|
|
1220
|
+
---
|
|
1221
|
+
|
|
1222
|
+
### 3. **Can I use this offline?**
|
|
1223
|
+
|
|
1224
|
+
**No.** `roast` requires internet connection to reach Anthropic's API.
|
|
1225
|
+
|
|
1226
|
+
**Alternatives for offline:**
|
|
1227
|
+
- Set up a local LLM (complex, beyond scope)
|
|
1228
|
+
- Use traditional linters (eslint, pylint, etc.)
|
|
1229
|
+
- Manual code review
|
|
1230
|
+
|
|
1231
|
+
---
|
|
1232
|
+
|
|
1233
|
+
### 4. **Is the humor offensive?**
|
|
1234
|
+
|
|
1235
|
+
**Roast mode:** Sarcastic and blunt, but never personal. It criticizes code, not people.
|
|
1236
|
+
|
|
1237
|
+
**Serious mode:** Professional, no humor.
|
|
1238
|
+
|
|
1239
|
+
**Severity levels:**
|
|
1240
|
+
- **Mild:** Friendly and encouraging
|
|
1241
|
+
- **Medium:** Sarcastic but constructive (default)
|
|
1242
|
+
- **Harsh:** Very direct, can be brutal
|
|
1243
|
+
|
|
1244
|
+
Use `--serious` for team PRs or `--severity mild` for beginners.
|
|
1245
|
+
|
|
1246
|
+
---
|
|
1247
|
+
|
|
1248
|
+
### 5. **Does it actually improve code quality?**
|
|
1249
|
+
|
|
1250
|
+
**Yes, when used correctly:**
|
|
1251
|
+
|
|
1252
|
+
✅ Catches security issues (SQL injection, XSS, unsafe eval)
|
|
1253
|
+
✅ Identifies performance problems (O(n²) loops, memory leaks)
|
|
1254
|
+
✅ Highlights maintainability issues (long functions, tight coupling)
|
|
1255
|
+
✅ Suggests modern best practices
|
|
1256
|
+
✅ Teaches by explaining WHY something is bad
|
|
1257
|
+
|
|
1258
|
+
**But:**
|
|
1259
|
+
- AI can miss context-specific issues
|
|
1260
|
+
- It's a tool, not a replacement for human review
|
|
1261
|
+
- Always verify suggestions before applying
|
|
1262
|
+
|
|
1263
|
+
---
|
|
1264
|
+
|
|
1265
|
+
### 6. **Can I customize the roast style?**
|
|
1266
|
+
|
|
1267
|
+
**Currently:** Severity levels (mild/medium/harsh) and serious mode.
|
|
1268
|
+
|
|
1269
|
+
**Not yet:** Custom roast personas (e.g., "roast like Linus Torvalds" or "review like Uncle Bob").
|
|
1270
|
+
|
|
1271
|
+
**Future:** Customizable prompts/styles are on the roadmap.
|
|
1272
|
+
|
|
1273
|
+
---
|
|
1274
|
+
|
|
1275
|
+
### 7. **What languages are supported?**
|
|
1276
|
+
|
|
1277
|
+
✅ JavaScript / TypeScript / Node.js
|
|
1278
|
+
✅ Python
|
|
1279
|
+
✅ Go
|
|
1280
|
+
✅ Rust
|
|
1281
|
+
✅ Java / Kotlin
|
|
1282
|
+
✅ C / C++
|
|
1283
|
+
✅ Ruby
|
|
1284
|
+
✅ PHP
|
|
1285
|
+
✅ Swift
|
|
1286
|
+
✅ Shell / Bash
|
|
1287
|
+
✅ SQL
|
|
1288
|
+
✅ HTML / CSS
|
|
1289
|
+
✅ And more...
|
|
1290
|
+
|
|
1291
|
+
Claude has broad training, so even niche languages often get good results.
|
|
1292
|
+
|
|
1293
|
+
---
|
|
1294
|
+
|
|
1295
|
+
### 8. **Does it work with frameworks (React, Django, etc.)?**
|
|
1296
|
+
|
|
1297
|
+
**Yes!** The AI understands framework-specific patterns:
|
|
1298
|
+
|
|
1299
|
+
- **React:** Hooks, component structure, props, state management
|
|
1300
|
+
- **Django:** ORM patterns, views, middleware
|
|
1301
|
+
- **Express:** Route handlers, middleware, error handling
|
|
1302
|
+
- **Rails:** ActiveRecord, controllers, migrations
|
|
1303
|
+
- etc.
|
|
1304
|
+
|
|
1305
|
+
It will roast framework-specific anti-patterns (e.g., prop drilling in React, N+1 queries in ORMs).
|
|
1306
|
+
|
|
1307
|
+
---
|
|
1308
|
+
|
|
1309
|
+
### 9. **Can I use this for production code reviews?**
|
|
1310
|
+
|
|
1311
|
+
**Yes, but:**
|
|
1312
|
+
|
|
1313
|
+
✅ Great for initial screening
|
|
1314
|
+
✅ Catches obvious bugs and security issues
|
|
1315
|
+
✅ Ensures code meets basic quality standards
|
|
1316
|
+
|
|
1317
|
+
⚠️ Should NOT replace human code review for:
|
|
1318
|
+
- Business logic validation
|
|
1319
|
+
- Architecture decisions
|
|
1320
|
+
- Team-specific conventions
|
|
1321
|
+
- Nuanced judgment calls
|
|
1322
|
+
|
|
1323
|
+
**Best practice:** Use `roast --serious` BEFORE requesting human review. Fix what it finds, then get human eyes on it.
|
|
1324
|
+
|
|
1325
|
+
---
|
|
1326
|
+
|
|
1327
|
+
### 10. **Will it give different results each time?**
|
|
1328
|
+
|
|
1329
|
+
**Yes, slightly.** AI models have some randomness (temperature setting).
|
|
1330
|
+
|
|
1331
|
+
**Typically:**
|
|
1332
|
+
- Core issues will always be flagged
|
|
1333
|
+
- Phrasing may vary
|
|
1334
|
+
- Severity of roast may differ slightly
|
|
1335
|
+
|
|
1336
|
+
For consistent results, use `--serious` mode which is more deterministic.
|
|
1337
|
+
|
|
1338
|
+
---
|
|
1339
|
+
|
|
1340
|
+
### 11. **Can I contribute to the project?**
|
|
1341
|
+
|
|
1342
|
+
**Absolutely!** Contributions are very welcome:
|
|
1343
|
+
|
|
1344
|
+
- Report bugs via GitHub Issues
|
|
1345
|
+
- Suggest features
|
|
1346
|
+
- Submit pull requests
|
|
1347
|
+
- Improve roast quality
|
|
1348
|
+
- Add language support
|
|
1349
|
+
- Write tests
|
|
1350
|
+
|
|
1351
|
+
See [Contributing](#contributing) section.
|
|
1352
|
+
|
|
1353
|
+
---
|
|
1354
|
+
|
|
1355
|
+
### 12. **Does it store my code or reviews?**
|
|
1356
|
+
|
|
1357
|
+
**No local storage.** `roast` doesn't save files or reviews on your machine (unless you manually redirect output).
|
|
1358
|
+
|
|
1359
|
+
**API-side:** Anthropic may temporarily log requests for abuse prevention. Check their privacy policy for retention details.
|
|
1360
|
+
|
|
1361
|
+
## Tips
|
|
1362
|
+
|
|
1363
|
+
- **Share your roasts** - They're designed to be screenshot-friendly
|
|
1364
|
+
- **Use serious mode for PRs** - Save the humor for your own code
|
|
1365
|
+
- **Review before committing** - Catch bugs before your CI does
|
|
1366
|
+
- **Roast legacy code** - Therapeutic and educational
|
|
1367
|
+
- **Pipe from git diff** - Review only what changed: `git diff | roast`
|
|
1368
|
+
- **Works with stdin** - `cat sketch.py | roast` or `pbpaste | roast`
|
|
1369
|
+
|
|
1370
|
+
**Create project-specific wrappers:**
|
|
1371
|
+
```bash
|
|
1372
|
+
# scripts/review.sh
|
|
1373
|
+
#!/bin/bash
|
|
1374
|
+
find src -name "*.js" -mtime -1 | xargs -I {} roast --serious {}
|
|
1375
|
+
```
|
|
1376
|
+
|
|
1377
|
+
**Combine with other tools:**
|
|
1378
|
+
```bash
|
|
1379
|
+
# Lint first, then roast
|
|
1380
|
+
$ eslint src/app.js && roast src/app.js
|
|
1381
|
+
|
|
1382
|
+
# Roast, then test
|
|
1383
|
+
$ roast src/app.js && npm test
|
|
1384
|
+
```
|
|
1385
|
+
|
|
1386
|
+
**Team usage:**
|
|
1387
|
+
```bash
|
|
1388
|
+
# Add to CI pipeline
|
|
1389
|
+
- name: AI Code Review
|
|
1390
|
+
run: |
|
|
1391
|
+
git diff origin/main...HEAD --name-only | \
|
|
1392
|
+
grep -E '\.(js|ts|py)$' | \
|
|
1393
|
+
xargs -I {} npx @muin/roast --serious {}
|
|
1394
|
+
```
|
|
1395
|
+
|
|
1396
|
+
## Roadmap
|
|
1397
|
+
|
|
1398
|
+
### v0.2 (Next Release)
|
|
1399
|
+
- [ ] **JSON output mode** - Structured output for CI integration
|
|
1400
|
+
- [ ] **Config file support** - `.roastrc` for defaults (severity, model, etc.)
|
|
1401
|
+
- [ ] **Multi-file batch mode** - `roast src/*.js` in one API call
|
|
1402
|
+
- [ ] **Ignore patterns** - `.roastignore` like `.gitignore`
|
|
1403
|
+
- [ ] **Diff mode** - Compare changes: `roast --diff main...feature`
|
|
1404
|
+
|
|
1405
|
+
### v0.3
|
|
1406
|
+
- [ ] **Custom roast personalities** - "Roast like Linus", "Review like Uncle Bob"
|
|
1407
|
+
- [ ] **Fix suggestions with diffs** - Show exact code changes to apply
|
|
1408
|
+
- [ ] **Performance scoring** - Rate code quality 0-100
|
|
1409
|
+
- [ ] **Security scan mode** - Focus on vulnerabilities only
|
|
1410
|
+
- [ ] **HTML report generation** - `roast --html src/ > report.html`
|
|
1411
|
+
|
|
1412
|
+
### v1.0 (Future)
|
|
1413
|
+
- [ ] **Auto-fix mode** - Apply suggested changes automatically
|
|
1414
|
+
- [ ] **IDE plugins** - VS Code, IntelliJ, Vim
|
|
1415
|
+
- [ ] **Team dashboard** - Track code quality over time
|
|
1416
|
+
- [ ] **Learning mode** - Personalized feedback based on your skill level
|
|
1417
|
+
- [ ] **Multi-model support** - Use GPT-4, Gemini, local models
|
|
1418
|
+
- [ ] **Offline mode** - Local model integration
|
|
1419
|
+
|
|
1420
|
+
### Community Requests
|
|
1421
|
+
- [ ] Web UI for drag-and-drop file roasting
|
|
1422
|
+
- [ ] Slack/Discord bot integration
|
|
1423
|
+
- [ ] GitHub PR comment automation
|
|
1424
|
+
- [ ] GitLab CI/CD integration
|
|
1425
|
+
- [ ] Pre-commit hook generator
|
|
1426
|
+
- [ ] Support for Jupyter notebooks (.ipynb)
|
|
1427
|
+
|
|
1428
|
+
**Want a feature?** Open a GitHub issue or +1 existing ones!
|
|
1429
|
+
|
|
1430
|
+
## Development
|
|
1431
|
+
|
|
1432
|
+
```bash
|
|
1433
|
+
# Clone repo
|
|
1434
|
+
git clone https://github.com/muinmomin/roast.git
|
|
1435
|
+
cd roast
|
|
1436
|
+
|
|
1437
|
+
# Install dependencies
|
|
1438
|
+
npm install
|
|
1439
|
+
|
|
1440
|
+
# Link locally for testing
|
|
1441
|
+
npm link
|
|
1442
|
+
|
|
1443
|
+
# Test with sample file
|
|
1444
|
+
roast examples/bad-code.js
|
|
1445
|
+
|
|
1446
|
+
# Run tests (if available)
|
|
1447
|
+
npm test
|
|
1448
|
+
```
|
|
1449
|
+
|
|
1450
|
+
**Project structure:**
|
|
1451
|
+
```
|
|
1452
|
+
roast/
|
|
1453
|
+
├── bin/
|
|
1454
|
+
│ └── roast.js # CLI entry point
|
|
1455
|
+
├── lib/
|
|
1456
|
+
│ └── roast.js # Core logic
|
|
1457
|
+
├── examples/
|
|
1458
|
+
│ └── bad-code.js # Test cases
|
|
1459
|
+
├── package.json
|
|
1460
|
+
└── README.md
|
|
1461
|
+
```
|
|
1462
|
+
|
|
1463
|
+
**Testing:**
|
|
1464
|
+
```bash
|
|
1465
|
+
# Create test file
|
|
1466
|
+
cat > test.js << 'EOF'
|
|
1467
|
+
var x = 1;
|
|
1468
|
+
eval(userInput);
|
|
1469
|
+
EOF
|
|
1470
|
+
|
|
1471
|
+
$ roast test.js
|
|
1472
|
+
```
|
|
1473
|
+
|
|
1474
|
+
## Contributing
|
|
1475
|
+
|
|
1476
|
+
Found a bug? Want to add a feature?
|
|
1477
|
+
|
|
1478
|
+
```bash
|
|
1479
|
+
# Clone the repo
|
|
1480
|
+
git clone https://github.com/muinmomin/roast.git
|
|
1481
|
+
cd roast
|
|
1482
|
+
|
|
1483
|
+
# Install dependencies
|
|
1484
|
+
npm install
|
|
1485
|
+
|
|
1486
|
+
# Test locally
|
|
1487
|
+
npm link
|
|
1488
|
+
roast test-file.js
|
|
1489
|
+
|
|
1490
|
+
# Run tests (if available)
|
|
1491
|
+
npm test
|
|
1492
|
+
```
|
|
1493
|
+
|
|
1494
|
+
Pull requests welcome! Please:
|
|
1495
|
+
- Keep the humor sharp but not mean
|
|
1496
|
+
- Add tests for new features
|
|
1497
|
+
- Follow existing code style (ESLint config included)
|
|
1498
|
+
- Update README if adding options
|
|
1499
|
+
|
|
1500
|
+
**Code style:**
|
|
1501
|
+
- Use ESLint
|
|
1502
|
+
- Follow existing patterns
|
|
1503
|
+
- Add JSDoc comments for functions
|
|
1504
|
+
- Keep roasts clever, not cruel
|
|
1505
|
+
|
|
1506
|
+
**Ideas for contributions:**
|
|
1507
|
+
- Better language detection
|
|
1508
|
+
- Framework-specific roasting (React, Django, Rails patterns)
|
|
1509
|
+
- Security vulnerability detection
|
|
1510
|
+
- Performance analysis
|
|
1511
|
+
- Custom roast templates
|
|
1512
|
+
|
|
1513
|
+
## License
|
|
1514
|
+
|
|
1515
|
+
MIT
|
|
1516
|
+
|
|
1517
|
+
## Credits
|
|
1518
|
+
|
|
1519
|
+
Built with:
|
|
1520
|
+
- [Anthropic Claude](https://anthropic.com) - The AI doing the roasting
|
|
1521
|
+
- [Commander.js](https://github.com/tj/commander.js) - CLI framework
|
|
1522
|
+
- [Chalk](https://github.com/chalk/chalk) - Terminal colors
|
|
1523
|
+
|
|
1524
|
+
Inspired by every brutally honest code review you've ever received (or given).
|
|
1525
|
+
|
|
1526
|
+
---
|
|
1527
|
+
|
|
1528
|
+
Made by [muin](https://github.com/muinmomin)
|
|
1529
|
+
|
|
1530
|
+
*Roast responsibly. Don't roast production code in public without permission.*
|