eslint-plugin-ai-guard 1.1.13 โ 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +337 -233
- package/dist/cli/index.js +1013 -104
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.mts +23 -4
- package/dist/index.d.ts +23 -4
- package/dist/index.js +385 -55
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +375 -55
- package/dist/index.mjs.map +1 -1
- package/package.json +10 -3
package/README.md
CHANGED
|
@@ -1,233 +1,337 @@
|
|
|
1
|
-
<p align="center">
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
<a href="https://
|
|
9
|
-
<a href="https://
|
|
10
|
-
<a href="https://
|
|
11
|
-
|
|
12
|
-
</p>
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
##
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
npm
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="./assets/logo.png" alt="AI Guard Logo" width="80" />
|
|
3
|
+
<h1 align="center">eslint-plugin-ai-guard</h1>
|
|
4
|
+
<p align="center">
|
|
5
|
+
<strong>๐ก๏ธ The ESLint plugin built for the age of AI-generated code.</strong>
|
|
6
|
+
</p>
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://www.npmjs.com/package/eslint-plugin-ai-guard"><img src="https://img.shields.io/npm/v/eslint-plugin-ai-guard.svg?style=flat-square&color=7c3aed" alt="npm version"></a>
|
|
9
|
+
<a href="https://github.com/YashJadhav21/eslint-plugin-ai-guard/actions"><img src="https://img.shields.io/github/actions/workflow/status/YashJadhav21/eslint-plugin-ai-guard/ci.yml?style=flat-square&label=CI&color=10b981" alt="CI"></a>
|
|
10
|
+
<a href="https://www.npmjs.com/package/eslint-plugin-ai-guard"><img src="https://img.shields.io/npm/dm/eslint-plugin-ai-guard.svg?style=flat-square&color=3b82f6" alt="downloads"></a>
|
|
11
|
+
<a href="https://github.com/YashJadhav21/eslint-plugin-ai-guard/blob/main/LICENSE"><img src="https://img.shields.io/npm/l/eslint-plugin-ai-guard.svg?style=flat-square&color=64748b" alt="license"></a>
|
|
12
|
+
</p>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## The Problem
|
|
18
|
+
|
|
19
|
+
AI coding assistants generate code that **looks correct but isn't.** Research shows AI-generated code has **1.7ร more bugs** and **2.74ร more security vulnerabilities** than human-written code.
|
|
20
|
+
|
|
21
|
+
The patterns they get wrong are consistent and predictable:
|
|
22
|
+
|
|
23
|
+
| Pattern | Why AI Gets It Wrong |
|
|
24
|
+
|---------|---------------------|
|
|
25
|
+
| `try {} catch (e) {}` | AI adds catch blocks without thinking about error handling |
|
|
26
|
+
| `array.map(async ...)` | AI generates async callbacks that return `Promise[]`, not values |
|
|
27
|
+
| `fetch(url)` (no await) | AI forgets to await or handle promise rejection |
|
|
28
|
+
| `const apiKey = 'sk-...'` | AI uses placeholder credentials that get committed |
|
|
29
|
+
| `eval(userInput)` | AI generates dynamic evaluation without security awareness |
|
|
30
|
+
| `if (true) { ... }` | AI leaves dead scaffolding branches in generated code |
|
|
31
|
+
|
|
32
|
+
**Existing linters don't catch these** because they're designed for human coding patterns.
|
|
33
|
+
|
|
34
|
+
`ai-guard` is purpose-built to catch what AI tools consistently get wrong.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
npm install --save-dev eslint-plugin-ai-guard
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Requires: **Node.js โฅ 18**, **ESLint โฅ 8**
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Quick Start โ Zero Config Required
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# Scan your project immediately (no ESLint config needed)
|
|
52
|
+
npx ai-guard run
|
|
53
|
+
|
|
54
|
+
# Security-focused scan
|
|
55
|
+
npx ai-guard run --security
|
|
56
|
+
|
|
57
|
+
# Strict mode โ all rules at error
|
|
58
|
+
npx ai-guard run --strict
|
|
59
|
+
|
|
60
|
+
# Scan a specific directory
|
|
61
|
+
npx ai-guard run --path src/api
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**That's it.** No configuration, no setup.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## CLI Commands
|
|
69
|
+
|
|
70
|
+
| Command | Description |
|
|
71
|
+
|---------|-------------|
|
|
72
|
+
| `ai-guard run` | Scan your project with the recommended preset |
|
|
73
|
+
| `ai-guard run --strict` | All rules at error โ for CI enforcement |
|
|
74
|
+
| `ai-guard run --security` | Security rules only |
|
|
75
|
+
| `ai-guard run --json` | Output results as JSON (CI-friendly) |
|
|
76
|
+
| `ai-guard run --max-warnings 0` | Fail CI on any warning |
|
|
77
|
+
| `ai-guard init` | Auto-configure ESLint for your project |
|
|
78
|
+
| `ai-guard init-context` | Generate AI agent rules (CLAUDE.md, .cursorrules, etc.) |
|
|
79
|
+
| `ai-guard doctor` | Diagnose your ESLint setup |
|
|
80
|
+
| `ai-guard baseline` | Save current issues, track only new ones |
|
|
81
|
+
| `ai-guard report` | Generate a shareable HTML report |
|
|
82
|
+
| `ai-guard ignore` | Add patterns to suppress noise |
|
|
83
|
+
|
|
84
|
+
### Terminal Output
|
|
85
|
+
|
|
86
|
+
```
|
|
87
|
+
AI GUARD
|
|
88
|
+
|
|
89
|
+
Files scanned: 142 ยท Issues in: 7 files ยท Duration: 312ms ยท Preset: recommended
|
|
90
|
+
|
|
91
|
+
โโ Summary by Category โโ
|
|
92
|
+
|
|
93
|
+
๐ด Security 3 errors
|
|
94
|
+
๐ Reliability 2 errors
|
|
95
|
+
๐ก Async Stability 2 warnings
|
|
96
|
+
|
|
97
|
+
Total: 5 errors ยท 2 warnings
|
|
98
|
+
|
|
99
|
+
โโ By Rule โโ
|
|
100
|
+
โข no-hardcoded-secret: 3
|
|
101
|
+
โข no-empty-catch: 2
|
|
102
|
+
โข no-floating-promise: 2
|
|
103
|
+
|
|
104
|
+
โโ Next Steps โโ
|
|
105
|
+
โน Run ai-guard baseline to save these issues and track only new ones
|
|
106
|
+
โน Run ai-guard report to generate a shareable HTML report
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## Rules
|
|
112
|
+
|
|
113
|
+
### ๐ด Security
|
|
114
|
+
|
|
115
|
+
| Rule | Default | What it catches |
|
|
116
|
+
|------|---------|-----------------|
|
|
117
|
+
| `no-hardcoded-secret` | **error** | API keys, passwords, tokens in source code. Autofix: replaces with `process.env.*` |
|
|
118
|
+
| `no-eval-dynamic` | **error** | `eval()` / `new Function()` with non-literal arguments |
|
|
119
|
+
| `no-sql-string-concat` | warn | SQL queries built by string concatenation or interpolation |
|
|
120
|
+
| `no-unsafe-deserialize` | warn | `JSON.parse(req.body)` without validation |
|
|
121
|
+
| `require-auth-middleware` | warn | Express/Fastify routes without authentication middleware |
|
|
122
|
+
| `require-authz-check` | warn | Resource access without ownership checks |
|
|
123
|
+
|
|
124
|
+
### ๐ Reliability
|
|
125
|
+
|
|
126
|
+
| Rule | Default | What it catches |
|
|
127
|
+
|------|---------|-----------------|
|
|
128
|
+
| `no-empty-catch` | **error** | `catch (e) {}` โ errors vanish silently. Autofix: inserts `/* TODO: handle error */` |
|
|
129
|
+
| `no-broad-exception` | warn | `catch (e: any)` that hides the real error type |
|
|
130
|
+
| `no-catch-log-rethrow` | off* | Catch blocks that only `console.log` + rethrow |
|
|
131
|
+
| `no-catch-without-use` | off* | Catching an error and never using it |
|
|
132
|
+
|
|
133
|
+
*Enabled at `error` in `strict` preset.
|
|
134
|
+
|
|
135
|
+
### ๐ก Async Stability
|
|
136
|
+
|
|
137
|
+
| Rule | Default | What it catches |
|
|
138
|
+
|------|---------|-----------------|
|
|
139
|
+
| `no-floating-promise` | **error** | Async calls with no `await`, return, or `.catch()`. Autofix: adds `void` |
|
|
140
|
+
| `no-async-array-callback` | warn | `array.map(async ...)` returning `Promise[]` instead of values |
|
|
141
|
+
| `no-await-in-loop` | warn | Sequential `await` in loops (use `Promise.all`). Autofix available for simple cases |
|
|
142
|
+
| `no-async-without-await` | warn | `async` function that never uses `await` |
|
|
143
|
+
| `no-redundant-await` | off* | `return await` outside try/catch |
|
|
144
|
+
|
|
145
|
+
*Enabled at `error` in `strict` preset.
|
|
146
|
+
|
|
147
|
+
### ๐ต AI Patterns
|
|
148
|
+
|
|
149
|
+
| Rule | Default | What it catches |
|
|
150
|
+
|------|---------|-----------------|
|
|
151
|
+
| `no-dead-branch` | warn | `if (true)`, `if (false)`, `x && !x`, `x === x` โ scaffolding leftovers |
|
|
152
|
+
| `no-duplicate-logic-block` | off* | Consecutive duplicate code that should be extracted |
|
|
153
|
+
| `no-console-in-handler` | off* | `console.log` in route handlers (use a proper logger) |
|
|
154
|
+
|
|
155
|
+
*Enabled at `error` in `strict` preset.
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
## Presets
|
|
160
|
+
|
|
161
|
+
| Preset | Purpose | Recommended For |
|
|
162
|
+
|--------|---------|-----------------|
|
|
163
|
+
| `recommended` | Low-noise, adoption-first โ critical issues at `error`, context-sensitive at `warn` | All teams on day one |
|
|
164
|
+
| `strict` | All 18 rules at `error` | CI enforcement in mature codebases |
|
|
165
|
+
| `security` | Security rules only | Security-focused scanning |
|
|
166
|
+
|
|
167
|
+
### ESLint Config (Flat Config)
|
|
168
|
+
|
|
169
|
+
```javascript
|
|
170
|
+
// eslint.config.mjs
|
|
171
|
+
import aiGuard from 'eslint-plugin-ai-guard';
|
|
172
|
+
|
|
173
|
+
export default [
|
|
174
|
+
{
|
|
175
|
+
plugins: { 'ai-guard': aiGuard },
|
|
176
|
+
rules: { ...aiGuard.configs.recommended.rules },
|
|
177
|
+
},
|
|
178
|
+
];
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
```javascript
|
|
182
|
+
// Strict preset
|
|
183
|
+
export default [
|
|
184
|
+
{
|
|
185
|
+
plugins: { 'ai-guard': aiGuard },
|
|
186
|
+
rules: { ...aiGuard.configs.strict.rules },
|
|
187
|
+
},
|
|
188
|
+
];
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
## CI Integration
|
|
194
|
+
|
|
195
|
+
### GitHub Actions
|
|
196
|
+
|
|
197
|
+
```yaml
|
|
198
|
+
# .github/workflows/ai-guard.yml
|
|
199
|
+
name: AI Guard
|
|
200
|
+
|
|
201
|
+
on: [pull_request]
|
|
202
|
+
|
|
203
|
+
jobs:
|
|
204
|
+
scan:
|
|
205
|
+
runs-on: ubuntu-latest
|
|
206
|
+
steps:
|
|
207
|
+
- uses: actions/checkout@v4
|
|
208
|
+
- uses: actions/setup-node@v4
|
|
209
|
+
with:
|
|
210
|
+
node-version: 20
|
|
211
|
+
cache: 'npm'
|
|
212
|
+
- run: npm ci
|
|
213
|
+
- run: npx ai-guard run --max-warnings 0
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
See [`examples/ci/`](./examples/ci/) for more templates (GitLab CI, baseline mode, JSON output).
|
|
217
|
+
|
|
218
|
+
### Exit Codes
|
|
219
|
+
|
|
220
|
+
| Code | Meaning |
|
|
221
|
+
|------|---------|
|
|
222
|
+
| `0` | No issues (or only warnings below `--max-warnings` threshold) |
|
|
223
|
+
| `1` | Errors found, or warnings exceed `--max-warnings` |
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## AI Agent Rules
|
|
228
|
+
|
|
229
|
+
Generate instruction files so **Claude Code, Cursor, and GitHub Copilot** automatically avoid the 18 most common AI-generated anti-patterns:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
npx ai-guard init-context
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
This writes:
|
|
236
|
+
- `CLAUDE.md` โ read automatically by Claude Code
|
|
237
|
+
- `.cursorrules` โ read automatically by Cursor
|
|
238
|
+
- `.github/copilot-instructions.md` โ read automatically by GitHub Copilot
|
|
239
|
+
|
|
240
|
+
Your AI tools will now avoid these patterns **before** you even run the linter.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## Real-World Example
|
|
245
|
+
|
|
246
|
+
```typescript
|
|
247
|
+
// โ Common AI-generated code โ 4 issues in one function
|
|
248
|
+
async function processUserOrders(userId: string) {
|
|
249
|
+
const apiKey = 'sk-prod-1234567890abcdef'; // no-hardcoded-secret
|
|
250
|
+
|
|
251
|
+
const orders = await db.query('SELECT * FROM orders WHERE id = ' + userId); // no-sql-string-concat
|
|
252
|
+
|
|
253
|
+
for (const order of orders) {
|
|
254
|
+
await sendEmail(order.email); // no-await-in-loop
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
updateAnalytics(userId); // no-floating-promise
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// โ
After ai-guard fixes
|
|
261
|
+
async function processUserOrders(userId: string) {
|
|
262
|
+
const apiKey = process.env.API_KEY;
|
|
263
|
+
|
|
264
|
+
const orders = await db.query('SELECT * FROM orders WHERE id = $1', [userId]);
|
|
265
|
+
|
|
266
|
+
await Promise.all(orders.map(async (order) => sendEmail(order.email)));
|
|
267
|
+
|
|
268
|
+
void updateAnalytics(userId);
|
|
269
|
+
}
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Autofix Support
|
|
275
|
+
|
|
276
|
+
Run autofixes via ESLint:
|
|
277
|
+
|
|
278
|
+
```bash
|
|
279
|
+
npx eslint src --fix
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
Rules with autofix:
|
|
283
|
+
|
|
284
|
+
| Rule | Fix |
|
|
285
|
+
|------|-----|
|
|
286
|
+
| `no-hardcoded-secret` | Replaces literal with `process.env.VAR_NAME` |
|
|
287
|
+
| `no-empty-catch` | Inserts `/* TODO: handle error */` |
|
|
288
|
+
| `no-floating-promise` | Marks with `void` |
|
|
289
|
+
| `no-await-in-loop` | Rewrites simple loops to `Promise.all(...)` |
|
|
290
|
+
| `no-async-without-await` | Removes unnecessary `async` keyword |
|
|
291
|
+
|
|
292
|
+
---
|
|
293
|
+
|
|
294
|
+
## Philosophy
|
|
295
|
+
|
|
296
|
+
- **Precision over recall** โ we'd rather miss a bug than create noise
|
|
297
|
+
- **Low false positives** โ if a warning fires too often on valid code, we disable it in `recommended`
|
|
298
|
+
- **Gradual adoption** โ `recommended` is the safe default; `strict` is opt-in
|
|
299
|
+
- **Self-validating** โ `ai-guard` scans its own source code in CI
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## Development
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
git clone https://github.com/YashJadhav21/eslint-plugin-ai-guard.git
|
|
307
|
+
cd eslint-plugin-ai-guard
|
|
308
|
+
npm install
|
|
309
|
+
npm run test # Run all 436+ tests
|
|
310
|
+
npm run build # Build CJS + ESM bundles
|
|
311
|
+
npm run typecheck # TypeScript check
|
|
312
|
+
npm run lint:self # Scan own source with ai-guard
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## Contributing
|
|
318
|
+
|
|
319
|
+
Contributions are welcome! Please see [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
320
|
+
|
|
321
|
+
**Rule requests:** Open an issue โ describe the AI anti-pattern and why it's common.
|
|
322
|
+
|
|
323
|
+
**False positive reports:** We take these seriously. Open an issue with a minimal code example.
|
|
324
|
+
|
|
325
|
+
See the [Roadmap](ROADMAP.md) for planned features.
|
|
326
|
+
|
|
327
|
+
---
|
|
328
|
+
|
|
329
|
+
## License
|
|
330
|
+
|
|
331
|
+
[MIT](LICENSE) โ free forever. No rules behind a paywall.
|
|
332
|
+
|
|
333
|
+
---
|
|
334
|
+
|
|
335
|
+
<p align="center">
|
|
336
|
+
Built to make AI-assisted development safer and more trustworthy. โก
|
|
337
|
+
</p>
|