@claude-tools-i-use/ai-code-audit 0.1.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 ADDED
@@ -0,0 +1,148 @@
1
+ # ai-code-audit
2
+
3
+ Security and quality linter specifically designed for AI-generated code.
4
+
5
+ ## The Problem
6
+
7
+ AI coding assistants can introduce security vulnerabilities and quality issues:
8
+
9
+ - SQL injection through string concatenation
10
+ - Command injection via unsanitized inputs
11
+ - Hardcoded secrets and credentials
12
+ - Missing error handling
13
+ - Unsafe deserialization
14
+ - Over-complex "clever" solutions
15
+
16
+ Traditional linters catch some of these, but AI code has unique patterns that need specific attention.
17
+
18
+ ## Installation
19
+
20
+ ```bash
21
+ npm install -g ai-code-audit
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ ### Audit Files
27
+
28
+ ```bash
29
+ # Audit a single file
30
+ aca src/api.ts
31
+
32
+ # Audit multiple files
33
+ aca src/**/*.ts
34
+
35
+ # Audit a git diff
36
+ git diff HEAD~1 | aca --stdin
37
+
38
+ # Audit staged changes
39
+ git diff --cached | aca --stdin
40
+ ```
41
+
42
+ ### Options
43
+
44
+ ```
45
+ Options:
46
+ -s, --stdin Read diff from stdin
47
+ -f, --format <type> Output format: text, json, sarif (default: text)
48
+ -c, --config <file> Config file path
49
+ --severity <level> Minimum severity: info, warning, error (default: warning)
50
+ -q, --quiet Only output errors
51
+ -h, --help Show help
52
+ ```
53
+
54
+ ### Git Hook Integration
55
+
56
+ Add to `.git/hooks/pre-commit`:
57
+
58
+ ```bash
59
+ #!/bin/bash
60
+ git diff --cached | aca --stdin --severity error
61
+ if [ $? -ne 0 ]; then
62
+ echo "AI code audit found issues. Please review before committing."
63
+ exit 1
64
+ fi
65
+ ```
66
+
67
+ ### CI Integration
68
+
69
+ ```yaml
70
+ # GitHub Actions
71
+ - name: AI Code Audit
72
+ run: |
73
+ npm install -g ai-code-audit
74
+ git diff ${{ github.event.before }} ${{ github.sha }} | aca --stdin --format sarif > results.sarif
75
+
76
+ - name: Upload SARIF
77
+ uses: github/codeql-action/upload-sarif@v2
78
+ with:
79
+ sarif_file: results.sarif
80
+ ```
81
+
82
+ ## Rules
83
+
84
+ ### Security Rules
85
+
86
+ | Rule | Severity | Description |
87
+ | ------------------- | -------- | --------------------------------------------- |
88
+ | `sql-injection` | error | Detects SQL queries with string interpolation |
89
+ | `command-injection` | error | Detects shell commands with unsanitized input |
90
+ | `hardcoded-secret` | error | Detects hardcoded API keys, passwords, tokens |
91
+ | `unsafe-eval` | error | Detects use of eval() or Function() |
92
+ | `unsafe-regex` | warning | Detects potentially catastrophic regex |
93
+ | `path-traversal` | error | Detects unsanitized file path operations |
94
+ | `xss-risk` | warning | Detects potential XSS in HTML generation |
95
+
96
+ ### Quality Rules
97
+
98
+ | Rule | Severity | Description |
99
+ | ------------------------ | -------- | ---------------------------------------------- |
100
+ | `missing-error-handling` | warning | Detects async operations without try/catch |
101
+ | `empty-catch` | warning | Detects empty catch blocks that swallow errors |
102
+ | `console-log` | info | Detects console.log left in code |
103
+ | `todo-fixme` | info | Detects TODO/FIXME comments |
104
+ | `magic-number` | info | Detects unexplained numeric literals |
105
+ | `deep-nesting` | warning | Detects deeply nested code (>4 levels) |
106
+
107
+ ### AI-Specific Rules
108
+
109
+ | Rule | Severity | Description |
110
+ | -------------------- | -------- | ----------------------------------------------------- |
111
+ | `ai-placeholder` | error | Detects placeholder text like "// Add implementation" |
112
+ | `incomplete-impl` | warning | Detects `throw new Error('Not implemented')` |
113
+ | `excessive-comments` | info | Detects over-commented obvious code |
114
+ | `type-any-abuse` | warning | Detects excessive use of `any` type |
115
+
116
+ ## Configuration
117
+
118
+ Create `.ai-code-audit.json`:
119
+
120
+ ```json
121
+ {
122
+ "rules": {
123
+ "sql-injection": "error",
124
+ "console-log": "off",
125
+ "magic-number": "warning"
126
+ },
127
+ "ignore": ["**/*.test.ts", "**/fixtures/**"],
128
+ "languages": ["typescript", "javascript", "python"]
129
+ }
130
+ ```
131
+
132
+ ## Output Example
133
+
134
+ ```
135
+ src/api/users.ts
136
+ 12:5 error SQL injection risk: query uses string interpolation sql-injection
137
+ 24:3 warning Missing error handling for async operation missing-error-handling
138
+ 45:1 error Hardcoded secret detected: API_KEY = "sk-..." hardcoded-secret
139
+
140
+ src/utils/shell.ts
141
+ 8:12 error Command injection: exec() with unsanitized input command-injection
142
+
143
+ 4 problems (3 errors, 1 warning)
144
+ ```
145
+
146
+ ## License
147
+
148
+ MIT
@@ -0,0 +1,7 @@
1
+ import type { Finding, AuditResult, Config } from "./types.js";
2
+ export declare function auditFile(filename: string, config?: Config): Finding[];
3
+ export declare function auditContent(content: string, filename: string, config?: Config): Finding[];
4
+ export declare function auditDiff(diff: string, config?: Config): Finding[];
5
+ export declare function summarize(findings: Finding[]): AuditResult;
6
+ export declare function loadConfig(configPath?: string): Config;
7
+ //# sourceMappingURL=auditor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auditor.d.ts","sourceRoot":"","sources":["../src/auditor.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAsC/D,wBAAgB,SAAS,CACvB,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,MAAuB,GAC9B,OAAO,EAAE,CAmCX;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,MAAuB,GAC9B,OAAO,EAAE,CAwBX;AAED,wBAAgB,SAAS,CACvB,IAAI,EAAE,MAAM,EACZ,MAAM,GAAE,MAAuB,GAC9B,OAAO,EAAE,CAkEX;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,WAAW,CA8B1D;AAED,wBAAgB,UAAU,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAsBtD"}
@@ -0,0 +1,190 @@
1
+ import { readFileSync, existsSync } from "node:fs";
2
+ import { extname } from "node:path";
3
+ import { allRules } from "./rules/index.js";
4
+ const EXTENSION_MAP = {
5
+ ".ts": "typescript",
6
+ ".tsx": "typescript",
7
+ ".js": "javascript",
8
+ ".jsx": "javascript",
9
+ ".mjs": "javascript",
10
+ ".cjs": "javascript",
11
+ ".py": "python",
12
+ ".rb": "ruby",
13
+ ".go": "go",
14
+ };
15
+ const DEFAULT_CONFIG = {
16
+ rules: {},
17
+ ignore: [],
18
+ languages: ["typescript", "javascript", "python"],
19
+ };
20
+ function getLanguage(filename) {
21
+ const ext = extname(filename).toLowerCase();
22
+ return EXTENSION_MAP[ext] || null;
23
+ }
24
+ function shouldIgnore(finding, config) {
25
+ const ruleSeverity = config.rules[finding.rule];
26
+ return ruleSeverity === "off";
27
+ }
28
+ function adjustSeverity(finding, config) {
29
+ const ruleSeverity = config.rules[finding.rule];
30
+ if (ruleSeverity && ruleSeverity !== "off") {
31
+ return { ...finding, severity: ruleSeverity };
32
+ }
33
+ return finding;
34
+ }
35
+ export function auditFile(filename, config = DEFAULT_CONFIG) {
36
+ const language = getLanguage(filename);
37
+ if (!language) {
38
+ return [];
39
+ }
40
+ if (!config.languages.includes(language)) {
41
+ return [];
42
+ }
43
+ let content;
44
+ try {
45
+ content = readFileSync(filename, "utf-8");
46
+ }
47
+ catch {
48
+ return [];
49
+ }
50
+ const findings = [];
51
+ for (const rule of allRules) {
52
+ if (!rule.languages.includes(language)) {
53
+ continue;
54
+ }
55
+ const ruleFindings = rule.check(content, filename);
56
+ for (const finding of ruleFindings) {
57
+ if (!shouldIgnore(finding, config)) {
58
+ findings.push(adjustSeverity(finding, config));
59
+ }
60
+ }
61
+ }
62
+ return findings;
63
+ }
64
+ export function auditContent(content, filename, config = DEFAULT_CONFIG) {
65
+ const language = getLanguage(filename);
66
+ if (!language) {
67
+ return [];
68
+ }
69
+ const findings = [];
70
+ for (const rule of allRules) {
71
+ if (!rule.languages.includes(language)) {
72
+ continue;
73
+ }
74
+ const ruleFindings = rule.check(content, filename);
75
+ for (const finding of ruleFindings) {
76
+ if (!shouldIgnore(finding, config)) {
77
+ findings.push(adjustSeverity(finding, config));
78
+ }
79
+ }
80
+ }
81
+ return findings;
82
+ }
83
+ export function auditDiff(diff, config = DEFAULT_CONFIG) {
84
+ const findings = [];
85
+ let currentFile = "";
86
+ let lineOffset = 0;
87
+ const addedLines = new Map();
88
+ // Parse the diff
89
+ const lines = diff.split("\n");
90
+ for (const line of lines) {
91
+ // New file
92
+ if (line.startsWith("+++ b/")) {
93
+ currentFile = line.slice(6);
94
+ addedLines.set(currentFile, []);
95
+ continue;
96
+ }
97
+ // Hunk header
98
+ if (line.startsWith("@@")) {
99
+ const match = line.match(/@@ -\d+(?:,\d+)? \+(\d+)/);
100
+ if (match) {
101
+ lineOffset = parseInt(match[1], 10) - 1;
102
+ }
103
+ continue;
104
+ }
105
+ // Added line
106
+ if (line.startsWith("+") && !line.startsWith("+++")) {
107
+ lineOffset++;
108
+ const fileLines = addedLines.get(currentFile);
109
+ if (fileLines) {
110
+ fileLines.push({
111
+ line: lineOffset,
112
+ content: line.slice(1),
113
+ });
114
+ }
115
+ continue;
116
+ }
117
+ // Context or removed line
118
+ if (!line.startsWith("-")) {
119
+ lineOffset++;
120
+ }
121
+ }
122
+ // Audit added lines for each file
123
+ for (const [filename, lines] of addedLines) {
124
+ if (lines.length === 0)
125
+ continue;
126
+ const content = lines.map((l) => l.content).join("\n");
127
+ const contentFindings = auditContent(content, filename, config);
128
+ // Adjust line numbers back to original file
129
+ for (const finding of contentFindings) {
130
+ const originalLine = lines[finding.line - 1];
131
+ if (originalLine) {
132
+ findings.push({
133
+ ...finding,
134
+ line: originalLine.line,
135
+ });
136
+ }
137
+ }
138
+ }
139
+ return findings;
140
+ }
141
+ export function summarize(findings) {
142
+ let errorCount = 0;
143
+ let warningCount = 0;
144
+ let infoCount = 0;
145
+ const files = new Set();
146
+ for (const finding of findings) {
147
+ files.add(finding.file);
148
+ switch (finding.severity) {
149
+ case "error":
150
+ errorCount++;
151
+ break;
152
+ case "warning":
153
+ warningCount++;
154
+ break;
155
+ case "info":
156
+ infoCount++;
157
+ break;
158
+ }
159
+ }
160
+ return {
161
+ findings,
162
+ filesScanned: files.size,
163
+ errorCount,
164
+ warningCount,
165
+ infoCount,
166
+ };
167
+ }
168
+ export function loadConfig(configPath) {
169
+ const paths = configPath
170
+ ? [configPath]
171
+ : [".ai-code-audit.json", ".ai-code-audit.config.json"];
172
+ for (const path of paths) {
173
+ if (existsSync(path)) {
174
+ try {
175
+ const content = readFileSync(path, "utf-8");
176
+ const userConfig = JSON.parse(content);
177
+ return {
178
+ ...DEFAULT_CONFIG,
179
+ ...userConfig,
180
+ rules: { ...DEFAULT_CONFIG.rules, ...userConfig.rules },
181
+ };
182
+ }
183
+ catch {
184
+ // Invalid config, use defaults
185
+ }
186
+ }
187
+ }
188
+ return DEFAULT_CONFIG;
189
+ }
190
+ //# sourceMappingURL=auditor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auditor.js","sourceRoot":"","sources":["../src/auditor.ts"],"names":[],"mappings":"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"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
package/dist/cli.js ADDED
@@ -0,0 +1,233 @@
1
+ #!/usr/bin/env node
2
+ import { resolve } from "node:path";
3
+ import { auditFile, auditDiff, summarize, loadConfig } from "./auditor.js";
4
+ const VERSION = "0.1.0";
5
+ const COLORS = {
6
+ reset: "\x1b[0m",
7
+ bold: "\x1b[1m",
8
+ dim: "\x1b[2m",
9
+ red: "\x1b[31m",
10
+ yellow: "\x1b[33m",
11
+ blue: "\x1b[34m",
12
+ cyan: "\x1b[36m",
13
+ gray: "\x1b[90m",
14
+ };
15
+ const SEVERITY_COLORS = {
16
+ error: COLORS.red,
17
+ warning: COLORS.yellow,
18
+ info: COLORS.blue,
19
+ };
20
+ const HELP = `
21
+ ${COLORS.bold}ai-code-audit${COLORS.reset} v${VERSION}
22
+ Security and quality linter for AI-generated code
23
+
24
+ ${COLORS.bold}USAGE:${COLORS.reset}
25
+ aca [options] <files...>
26
+ git diff | aca --stdin
27
+
28
+ ${COLORS.bold}OPTIONS:${COLORS.reset}
29
+ -s, --stdin Read diff from stdin
30
+ -f, --format <type> Output format: text, json, sarif (default: text)
31
+ -c, --config <file> Config file path
32
+ --severity <level> Minimum severity: info, warning, error (default: warning)
33
+ -q, --quiet Only output errors
34
+ -h, --help Show help
35
+ -v, --version Show version
36
+
37
+ ${COLORS.bold}EXAMPLES:${COLORS.reset}
38
+ aca src/api.ts # Audit a single file
39
+ aca src/**/*.ts # Audit multiple files
40
+ git diff HEAD~1 | aca --stdin # Audit a diff
41
+ git diff --cached | aca --stdin # Audit staged changes
42
+
43
+ ${COLORS.bold}GIT HOOK:${COLORS.reset}
44
+ Add to .git/hooks/pre-commit:
45
+ git diff --cached | aca --stdin --severity error
46
+
47
+ `;
48
+ function parseArgs(args) {
49
+ const options = {
50
+ stdin: false,
51
+ format: "text",
52
+ severity: "warning",
53
+ quiet: false,
54
+ files: [],
55
+ };
56
+ for (let i = 0; i < args.length; i++) {
57
+ const arg = args[i];
58
+ switch (arg) {
59
+ case "-h":
60
+ case "--help":
61
+ console.log(HELP);
62
+ process.exit(0);
63
+ break;
64
+ case "-v":
65
+ case "--version":
66
+ console.log(`ai-code-audit v${VERSION}`);
67
+ process.exit(0);
68
+ break;
69
+ case "-s":
70
+ case "--stdin":
71
+ options.stdin = true;
72
+ break;
73
+ case "-f":
74
+ case "--format":
75
+ options.format = args[++i];
76
+ break;
77
+ case "-c":
78
+ case "--config":
79
+ options.configPath = args[++i];
80
+ break;
81
+ case "--severity":
82
+ options.severity = args[++i];
83
+ break;
84
+ case "-q":
85
+ case "--quiet":
86
+ options.quiet = true;
87
+ options.severity = "error";
88
+ break;
89
+ default:
90
+ if (!arg.startsWith("-")) {
91
+ options.files.push(arg);
92
+ }
93
+ break;
94
+ }
95
+ }
96
+ return options;
97
+ }
98
+ function filterBySeverity(findings, minSeverity) {
99
+ const severityOrder = ["info", "warning", "error"];
100
+ const minIndex = severityOrder.indexOf(minSeverity);
101
+ return findings.filter((f) => severityOrder.indexOf(f.severity) >= minIndex);
102
+ }
103
+ function formatText(result) {
104
+ const output = [];
105
+ // Group findings by file
106
+ const byFile = new Map();
107
+ for (const finding of result.findings) {
108
+ const existing = byFile.get(finding.file) || [];
109
+ existing.push(finding);
110
+ byFile.set(finding.file, existing);
111
+ }
112
+ for (const [file, findings] of byFile) {
113
+ output.push(`\n${COLORS.bold}${file}${COLORS.reset}`);
114
+ for (const f of findings) {
115
+ const color = SEVERITY_COLORS[f.severity];
116
+ const loc = `${f.line}:${f.column}`.padEnd(8);
117
+ const sev = f.severity.padEnd(8);
118
+ output.push(` ${COLORS.gray}${loc}${COLORS.reset} ${color}${sev}${COLORS.reset} ${f.message} ${COLORS.dim}${f.rule}${COLORS.reset}`);
119
+ }
120
+ }
121
+ output.push("");
122
+ const { errorCount, warningCount, infoCount } = result;
123
+ const total = errorCount + warningCount + infoCount;
124
+ if (total === 0) {
125
+ output.push(`${COLORS.cyan}✓ No issues found${COLORS.reset}`);
126
+ }
127
+ else {
128
+ const parts = [];
129
+ if (errorCount > 0)
130
+ parts.push(`${COLORS.red}${errorCount} error${errorCount !== 1 ? "s" : ""}${COLORS.reset}`);
131
+ if (warningCount > 0)
132
+ parts.push(`${COLORS.yellow}${warningCount} warning${warningCount !== 1 ? "s" : ""}${COLORS.reset}`);
133
+ if (infoCount > 0)
134
+ parts.push(`${COLORS.blue}${infoCount} info${COLORS.reset}`);
135
+ output.push(parts.join(", "));
136
+ }
137
+ return output.join("\n");
138
+ }
139
+ function formatJson(result) {
140
+ return JSON.stringify(result, null, 2);
141
+ }
142
+ function formatSarif(result) {
143
+ const sarif = {
144
+ $schema: "https://json.schemastore.org/sarif-2.1.0.json",
145
+ version: "2.1.0",
146
+ runs: [
147
+ {
148
+ tool: {
149
+ driver: {
150
+ name: "ai-code-audit",
151
+ version: VERSION,
152
+ rules: result.findings.map((f) => ({
153
+ id: f.rule,
154
+ shortDescription: { text: f.message },
155
+ })),
156
+ },
157
+ },
158
+ results: result.findings.map((f) => ({
159
+ ruleId: f.rule,
160
+ level: f.severity === "error"
161
+ ? "error"
162
+ : f.severity === "warning"
163
+ ? "warning"
164
+ : "note",
165
+ message: { text: f.message },
166
+ locations: [
167
+ {
168
+ physicalLocation: {
169
+ artifactLocation: { uri: f.file },
170
+ region: { startLine: f.line, startColumn: f.column },
171
+ },
172
+ },
173
+ ],
174
+ })),
175
+ },
176
+ ],
177
+ };
178
+ return JSON.stringify(sarif, null, 2);
179
+ }
180
+ async function main() {
181
+ const args = process.argv.slice(2);
182
+ if (args.length === 0) {
183
+ console.log(HELP);
184
+ process.exit(0);
185
+ }
186
+ const options = parseArgs(args);
187
+ const config = loadConfig(options.configPath);
188
+ let findings = [];
189
+ if (options.stdin) {
190
+ // Read diff from stdin
191
+ const chunks = [];
192
+ for await (const chunk of process.stdin) {
193
+ chunks.push(chunk);
194
+ }
195
+ const diff = Buffer.concat(chunks).toString("utf-8");
196
+ findings = auditDiff(diff, config);
197
+ }
198
+ else if (options.files.length > 0) {
199
+ // Audit files
200
+ for (const file of options.files) {
201
+ const filePath = resolve(file);
202
+ findings.push(...auditFile(filePath, config));
203
+ }
204
+ }
205
+ else {
206
+ console.error("Error: No files specified. Use --stdin for diff input.");
207
+ process.exit(1);
208
+ }
209
+ // Filter by severity
210
+ findings = filterBySeverity(findings, options.severity);
211
+ const result = summarize(findings);
212
+ // Output
213
+ switch (options.format) {
214
+ case "json":
215
+ console.log(formatJson(result));
216
+ break;
217
+ case "sarif":
218
+ console.log(formatSarif(result));
219
+ break;
220
+ default:
221
+ console.log(formatText(result));
222
+ break;
223
+ }
224
+ // Exit with error if there are errors
225
+ if (result.errorCount > 0) {
226
+ process.exit(1);
227
+ }
228
+ }
229
+ main().catch((err) => {
230
+ console.error("Fatal error:", err);
231
+ process.exit(1);
232
+ });
233
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG3E,MAAM,OAAO,GAAG,OAAO,CAAC;AAExB,MAAM,MAAM,GAAG;IACb,KAAK,EAAE,SAAS;IAChB,IAAI,EAAE,SAAS;IACf,GAAG,EAAE,SAAS;IACd,GAAG,EAAE,UAAU;IACf,MAAM,EAAE,UAAU;IAClB,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;IAChB,IAAI,EAAE,UAAU;CACjB,CAAC;AAEF,MAAM,eAAe,GAA6B;IAChD,KAAK,EAAE,MAAM,CAAC,GAAG;IACjB,OAAO,EAAE,MAAM,CAAC,MAAM;IACtB,IAAI,EAAE,MAAM,CAAC,IAAI;CAClB,CAAC;AAEF,MAAM,IAAI,GAAG;EACX,MAAM,CAAC,IAAI,gBAAgB,MAAM,CAAC,KAAK,KAAK,OAAO;;;EAGnD,MAAM,CAAC,IAAI,SAAS,MAAM,CAAC,KAAK;;;;EAIhC,MAAM,CAAC,IAAI,WAAW,MAAM,CAAC,KAAK;;;;;;;;;EASlC,MAAM,CAAC,IAAI,YAAY,MAAM,CAAC,KAAK;;;;;;EAMnC,MAAM,CAAC,IAAI,YAAY,MAAM,CAAC,KAAK;;;;CAIpC,CAAC;AAWF,SAAS,SAAS,CAAC,IAAc;IAC/B,MAAM,OAAO,GAAY;QACvB,KAAK,EAAE,KAAK;QACZ,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,SAAS;QACnB,KAAK,EAAE,KAAK;QACZ,KAAK,EAAE,EAAE;KACV,CAAC;IAEF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACrC,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QAEpB,QAAQ,GAAG,EAAE,CAAC;YACZ,KAAK,IAAI,CAAC;YACV,KAAK,QAAQ;gBACX,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAChB,MAAM;YAER,KAAK,IAAI,CAAC;YACV,KAAK,WAAW;gBACd,OAAO,CAAC,GAAG,CAAC,kBAAkB,OAAO,EAAE,CAAC,CAAC;gBACzC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAChB,MAAM;YAER,KAAK,IAAI,CAAC;YACV,KAAK,SAAS;gBACZ,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;gBACrB,MAAM;YAER,KAAK,IAAI,CAAC;YACV,KAAK,UAAU;gBACb,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC,CAA8B,CAAC;gBACxD,MAAM;YAER,KAAK,IAAI,CAAC;YACV,KAAK,UAAU;gBACb,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC/B,MAAM;YAER,KAAK,YAAY;gBACf,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAC,CAAa,CAAC;gBACzC,MAAM;YAER,KAAK,IAAI,CAAC;YACV,KAAK,SAAS;gBACZ,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;gBACrB,OAAO,CAAC,QAAQ,GAAG,OAAO,CAAC;gBAC3B,MAAM;YAER;gBACE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;oBACzB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAC1B,CAAC;gBACD,MAAM;QACV,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,gBAAgB,CACvB,QAAmB,EACnB,WAAqB;IAErB,MAAM,aAAa,GAAe,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;IAC/D,MAAM,QAAQ,GAAG,aAAa,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IAEpD,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,CAAC;AAC/E,CAAC;AAED,SAAS,UAAU,CAAC,MAAmB;IACrC,MAAM,MAAM,GAAa,EAAE,CAAC;IAE5B,yBAAyB;IACzB,MAAM,MAAM,GAAG,IAAI,GAAG,EAAqB,CAAC;IAC5C,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QACtC,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;QAChD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACvB,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACrC,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,MAAM,EAAE,CAAC;QACtC,MAAM,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,IAAI,GAAG,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QAEtD,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;YACzB,MAAM,KAAK,GAAG,eAAe,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;YAC1C,MAAM,GAAG,GAAG,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAC9C,MAAM,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YACjC,MAAM,CAAC,IAAI,CACT,KAAK,MAAM,CAAC,IAAI,GAAG,GAAG,GAAG,MAAM,CAAC,KAAK,IAAI,KAAK,GAAG,GAAG,GAAG,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,CAC1H,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAEhB,MAAM,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,GAAG,MAAM,CAAC;IACvD,MAAM,KAAK,GAAG,UAAU,GAAG,YAAY,GAAG,SAAS,CAAC;IAEpD,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;QAChB,MAAM,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,oBAAoB,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;IAChE,CAAC;SAAM,CAAC;QACN,MAAM,KAAK,GAAG,EAAE,CAAC;QACjB,IAAI,UAAU,GAAG,CAAC;YAChB,KAAK,CAAC,IAAI,CACR,GAAG,MAAM,CAAC,GAAG,GAAG,UAAU,SAAS,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,EAAE,CAChF,CAAC;QACJ,IAAI,YAAY,GAAG,CAAC;YAClB,KAAK,CAAC,IAAI,CACR,GAAG,MAAM,CAAC,MAAM,GAAG,YAAY,WAAW,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,KAAK,EAAE,CACzF,CAAC;QACJ,IAAI,SAAS,GAAG,CAAC;YACf,KAAK,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,IAAI,GAAG,SAAS,QAAQ,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC;QAC/D,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAChC,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC3B,CAAC;AAED,SAAS,UAAU,CAAC,MAAmB;IACrC,OAAO,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,WAAW,CAAC,MAAmB;IACtC,MAAM,KAAK,GAAG;QACZ,OAAO,EAAE,+CAA+C;QACxD,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE;YACJ;gBACE,IAAI,EAAE;oBACJ,MAAM,EAAE;wBACN,IAAI,EAAE,eAAe;wBACrB,OAAO,EAAE,OAAO;wBAChB,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;4BACjC,EAAE,EAAE,CAAC,CAAC,IAAI;4BACV,gBAAgB,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE;yBACtC,CAAC,CAAC;qBACJ;iBACF;gBACD,OAAO,EAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBACnC,MAAM,EAAE,CAAC,CAAC,IAAI;oBACd,KAAK,EACH,CAAC,CAAC,QAAQ,KAAK,OAAO;wBACpB,CAAC,CAAC,OAAO;wBACT,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS;4BACxB,CAAC,CAAC,SAAS;4BACX,CAAC,CAAC,MAAM;oBACd,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE;oBAC5B,SAAS,EAAE;wBACT;4BACE,gBAAgB,EAAE;gCAChB,gBAAgB,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE;gCACjC,MAAM,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;6BACrD;yBACF;qBACF;iBACF,CAAC,CAAC;aACJ;SACF;KACF,CAAC;IAEF,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACxC,CAAC;AAED,KAAK,UAAU,IAAI;IACjB,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAEnC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;IAChC,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAE9C,IAAI,QAAQ,GAAc,EAAE,CAAC;IAE7B,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,uBAAuB;QACvB,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;QACD,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;QACrD,QAAQ,GAAG,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACrC,CAAC;SAAM,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpC,cAAc;QACd,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YACjC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;YAC/B,QAAQ,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,wDAAwD,CAAC,CAAC;QACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,qBAAqB;IACrB,QAAQ,GAAG,gBAAgB,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAExD,MAAM,MAAM,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IAEnC,SAAS;IACT,QAAQ,OAAO,CAAC,MAAM,EAAE,CAAC;QACvB,KAAK,MAAM;YACT,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;YAChC,MAAM;QACR,KAAK,OAAO;YACV,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;YACjC,MAAM;QACR;YACE,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;YAChC,MAAM;IACV,CAAC;IAED,sCAAsC;IACtC,IAAI,MAAM,CAAC,UAAU,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACnB,OAAO,CAAC,KAAK,CAAC,cAAc,EAAE,GAAG,CAAC,CAAC;IACnC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ export { auditFile, auditContent, auditDiff, summarize, loadConfig, } from "./auditor.js";
2
+ export { allRules, securityRules, qualityRules, aiSpecificRules, } from "./rules/index.js";
3
+ export type { Finding, Rule, AuditResult, Config, Severity } from "./types.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,SAAS,EACT,YAAY,EACZ,SAAS,EACT,SAAS,EACT,UAAU,GACX,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,QAAQ,EACR,aAAa,EACb,YAAY,EACZ,eAAe,GAChB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,4 @@
1
+ // ai-code-audit - Security and quality linter for AI-generated code
2
+ export { auditFile, auditContent, auditDiff, summarize, loadConfig, } from "./auditor.js";
3
+ export { allRules, securityRules, qualityRules, aiSpecificRules, } from "./rules/index.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,oEAAoE;AAEpE,OAAO,EACL,SAAS,EACT,YAAY,EACZ,SAAS,EACT,SAAS,EACT,UAAU,GACX,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,QAAQ,EACR,aAAa,EACb,YAAY,EACZ,eAAe,GAChB,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { Rule } from "../types.js";
2
+ export declare const aiPlaceholder: Rule;
3
+ export declare const incompleteImpl: Rule;
4
+ export declare const typeAnyAbuse: Rule;
5
+ export declare const excessiveComments: Rule;
6
+ export declare const aiSpecificRules: Rule[];
7
+ //# sourceMappingURL=ai-specific.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-specific.d.ts","sourceRoot":"","sources":["../../src/rules/ai-specific.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAW,MAAM,aAAa,CAAC;AAqCjD,eAAO,MAAM,aAAa,EAAE,IA+B3B,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,IA4B5B,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,IA0B1B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,IAsC/B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,IAAI,EAKjC,CAAC"}
@@ -0,0 +1,124 @@
1
+ function findMatches(content, pattern, rule, severity, message, filename) {
2
+ const findings = [];
3
+ const lines = content.split("\n");
4
+ for (let i = 0; i < lines.length; i++) {
5
+ const line = lines[i];
6
+ let match;
7
+ pattern.lastIndex = 0;
8
+ while ((match = pattern.exec(line)) !== null) {
9
+ findings.push({
10
+ rule,
11
+ severity,
12
+ message,
13
+ file: filename,
14
+ line: i + 1,
15
+ column: match.index + 1,
16
+ snippet: line.trim(),
17
+ });
18
+ if (!pattern.global)
19
+ break;
20
+ }
21
+ }
22
+ return findings;
23
+ }
24
+ export const aiPlaceholder = {
25
+ name: "ai-placeholder",
26
+ description: "Detects placeholder text left by AI",
27
+ severity: "error",
28
+ languages: ["javascript", "typescript", "python", "ruby", "go"],
29
+ check: (content, filename) => {
30
+ const patterns = [
31
+ /\/\/\s*(?:Add|TODO:?\s*add|Implement)\s+(?:your|the)\s+/gi,
32
+ /\/\/\s*(?:Replace|Update)\s+(?:this|with)\s+/gi,
33
+ /#\s*(?:Add|TODO:?\s*add|Implement)\s+(?:your|the)\s+/gi,
34
+ /\/\/\s*\.\.\.\s*(?:rest|more|additional|other)/gi,
35
+ /\/\*\s*(?:Add|Implement|Your)\s+.*\s+here\s*\*\//gi,
36
+ /['"](?:your-api-key|YOUR_API_KEY|api-key-here|replace-me|CHANGE_ME)['"]/gi,
37
+ /(?:example|placeholder|dummy)[@.](?:com|org|io)/gi,
38
+ ];
39
+ const findings = [];
40
+ for (const pattern of patterns) {
41
+ findings.push(...findMatches(content, pattern, "ai-placeholder", "error", "AI placeholder text detected - needs implementation", filename));
42
+ }
43
+ return findings;
44
+ },
45
+ };
46
+ export const incompleteImpl = {
47
+ name: "incomplete-impl",
48
+ description: "Detects incomplete implementations",
49
+ severity: "warning",
50
+ languages: ["javascript", "typescript", "python"],
51
+ check: (content, filename) => {
52
+ const patterns = [
53
+ /throw\s+new\s+Error\s*\(\s*['"](?:Not\s+implemented|TODO|FIXME)['"]/gi,
54
+ /raise\s+NotImplementedError/gi,
55
+ /pass\s*#\s*(?:TODO|FIXME)/gi,
56
+ /return\s+(?:null|undefined|None)\s*;?\s*\/\/\s*(?:TODO|FIXME)/gi,
57
+ ];
58
+ const findings = [];
59
+ for (const pattern of patterns) {
60
+ findings.push(...findMatches(content, pattern, "incomplete-impl", "warning", "Incomplete implementation detected", filename));
61
+ }
62
+ return findings;
63
+ },
64
+ };
65
+ export const typeAnyAbuse = {
66
+ name: "type-any-abuse",
67
+ description: "Detects excessive use of any type",
68
+ severity: "warning",
69
+ languages: ["typescript"],
70
+ check: (content, filename) => {
71
+ if (!filename.endsWith(".ts") && !filename.endsWith(".tsx")) {
72
+ return [];
73
+ }
74
+ const pattern = /:\s*any\b/g;
75
+ const findings = findMatches(content, pattern, "type-any-abuse", "warning", 'Unsafe "any" type usage - consider using a specific type', filename);
76
+ // Only report if there are many instances
77
+ if (findings.length > 3) {
78
+ return findings;
79
+ }
80
+ return [];
81
+ },
82
+ };
83
+ export const excessiveComments = {
84
+ name: "excessive-comments",
85
+ description: "Detects over-commented obvious code",
86
+ severity: "info",
87
+ languages: ["javascript", "typescript"],
88
+ check: (content, filename) => {
89
+ const findings = [];
90
+ const lines = content.split("\n");
91
+ let commentLines = 0;
92
+ let codeLines = 0;
93
+ for (const line of lines) {
94
+ const trimmed = line.trim();
95
+ if (trimmed.startsWith("//") ||
96
+ trimmed.startsWith("/*") ||
97
+ trimmed.startsWith("*")) {
98
+ commentLines++;
99
+ }
100
+ else if (trimmed.length > 0) {
101
+ codeLines++;
102
+ }
103
+ }
104
+ // If comments exceed 50% of code, flag it
105
+ if (codeLines > 10 && commentLines > codeLines * 0.5) {
106
+ findings.push({
107
+ rule: "excessive-comments",
108
+ severity: "info",
109
+ message: `High comment ratio (${commentLines} comments / ${codeLines} code lines) - may be over-documented`,
110
+ file: filename,
111
+ line: 1,
112
+ column: 1,
113
+ });
114
+ }
115
+ return findings;
116
+ },
117
+ };
118
+ export const aiSpecificRules = [
119
+ aiPlaceholder,
120
+ incompleteImpl,
121
+ typeAnyAbuse,
122
+ excessiveComments,
123
+ ];
124
+ //# sourceMappingURL=ai-specific.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-specific.js","sourceRoot":"","sources":["../../src/rules/ai-specific.ts"],"names":[],"mappings":"AAEA,SAAS,WAAW,CAClB,OAAe,EACf,OAAe,EACf,IAAY,EACZ,QAAsC,EACtC,OAAe,EACf,QAAgB;IAEhB,MAAM,QAAQ,GAAc,EAAE,CAAC;IAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAElC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,KAAK,CAAC;QAEV,OAAO,CAAC,SAAS,GAAG,CAAC,CAAC;QAEtB,OAAO,CAAC,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;YAC7C,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI;gBACJ,QAAQ;gBACR,OAAO;gBACP,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC,GAAG,CAAC;gBACX,MAAM,EAAE,KAAK,CAAC,KAAK,GAAG,CAAC;gBACvB,OAAO,EAAE,IAAI,CAAC,IAAI,EAAE;aACrB,CAAC,CAAC;YAEH,IAAI,CAAC,OAAO,CAAC,MAAM;gBAAE,MAAM;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,MAAM,aAAa,GAAS;IACjC,IAAI,EAAE,gBAAgB;IACtB,WAAW,EAAE,qCAAqC;IAClD,QAAQ,EAAE,OAAO;IACjB,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC;IAC/D,KAAK,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE;QAC3B,MAAM,QAAQ,GAAG;YACf,2DAA2D;YAC3D,gDAAgD;YAChD,wDAAwD;YACxD,kDAAkD;YAClD,oDAAoD;YACpD,2EAA2E;YAC3E,mDAAmD;SACpD,CAAC;QAEF,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,QAAQ,CAAC,IAAI,CACX,GAAG,WAAW,CACZ,OAAO,EACP,OAAO,EACP,gBAAgB,EAChB,OAAO,EACP,qDAAqD,EACrD,QAAQ,CACT,CACF,CAAC;QACJ,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,cAAc,GAAS;IAClC,IAAI,EAAE,iBAAiB;IACvB,WAAW,EAAE,oCAAoC;IACjD,QAAQ,EAAE,SAAS;IACnB,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,QAAQ,CAAC;IACjD,KAAK,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE;QAC3B,MAAM,QAAQ,GAAG;YACf,uEAAuE;YACvE,+BAA+B;YAC/B,6BAA6B;YAC7B,iEAAiE;SAClE,CAAC;QAEF,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,QAAQ,CAAC,IAAI,CACX,GAAG,WAAW,CACZ,OAAO,EACP,OAAO,EACP,iBAAiB,EACjB,SAAS,EACT,oCAAoC,EACpC,QAAQ,CACT,CACF,CAAC;QACJ,CAAC;QACD,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,YAAY,GAAS;IAChC,IAAI,EAAE,gBAAgB;IACtB,WAAW,EAAE,mCAAmC;IAChD,QAAQ,EAAE,SAAS;IACnB,SAAS,EAAE,CAAC,YAAY,CAAC;IACzB,KAAK,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE;QAC3B,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YAC5D,OAAO,EAAE,CAAC;QACZ,CAAC;QAED,MAAM,OAAO,GAAG,YAAY,CAAC;QAC7B,MAAM,QAAQ,GAAG,WAAW,CAC1B,OAAO,EACP,OAAO,EACP,gBAAgB,EAChB,SAAS,EACT,0DAA0D,EAC1D,QAAQ,CACT,CAAC;QAEF,0CAA0C;QAC1C,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,OAAO,QAAQ,CAAC;QAClB,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAS;IACrC,IAAI,EAAE,oBAAoB;IAC1B,WAAW,EAAE,qCAAqC;IAClD,QAAQ,EAAE,MAAM;IAChB,SAAS,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;IACvC,KAAK,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,EAAE;QAC3B,MAAM,QAAQ,GAAc,EAAE,CAAC;QAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,YAAY,GAAG,CAAC,CAAC;QACrB,IAAI,SAAS,GAAG,CAAC,CAAC;QAElB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;YAC5B,IACE,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;gBACxB,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;gBACxB,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EACvB,CAAC;gBACD,YAAY,EAAE,CAAC;YACjB,CAAC;iBAAM,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC9B,SAAS,EAAE,CAAC;YACd,CAAC;QACH,CAAC;QAED,0CAA0C;QAC1C,IAAI,SAAS,GAAG,EAAE,IAAI,YAAY,GAAG,SAAS,GAAG,GAAG,EAAE,CAAC;YACrD,QAAQ,CAAC,IAAI,CAAC;gBACZ,IAAI,EAAE,oBAAoB;gBAC1B,QAAQ,EAAE,MAAM;gBAChB,OAAO,EAAE,uBAAuB,YAAY,eAAe,SAAS,uCAAuC;gBAC3G,IAAI,EAAE,QAAQ;gBACd,IAAI,EAAE,CAAC;gBACP,MAAM,EAAE,CAAC;aACV,CAAC,CAAC;QACL,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAW;IACrC,aAAa;IACb,cAAc;IACd,YAAY;IACZ,iBAAiB;CAClB,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { securityRules } from "./security.js";
2
+ import { qualityRules } from "./quality.js";
3
+ import { aiSpecificRules } from "./ai-specific.js";
4
+ import type { Rule } from "../types.js";
5
+ export declare const allRules: Rule[];
6
+ export { securityRules, qualityRules, aiSpecificRules };
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAExC,eAAO,MAAM,QAAQ,EAAE,IAAI,EAI1B,CAAC;AAEF,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { securityRules } from "./security.js";
2
+ import { qualityRules } from "./quality.js";
3
+ import { aiSpecificRules } from "./ai-specific.js";
4
+ export const allRules = [
5
+ ...securityRules,
6
+ ...qualityRules,
7
+ ...aiSpecificRules,
8
+ ];
9
+ export { securityRules, qualityRules, aiSpecificRules };
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/rules/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGnD,MAAM,CAAC,MAAM,QAAQ,GAAW;IAC9B,GAAG,aAAa;IAChB,GAAG,YAAY;IACf,GAAG,eAAe;CACnB,CAAC;AAEF,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { Rule } from "../types.js";
2
+ export declare const missingErrorHandling: Rule;
3
+ export declare const emptyCatch: Rule;
4
+ export declare const consoleLog: Rule;
5
+ export declare const todoFixme: Rule;
6
+ export declare const deepNesting: Rule;
7
+ export declare const qualityRules: Rule[];
8
+ //# sourceMappingURL=quality.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality.d.ts","sourceRoot":"","sources":["../../src/rules/quality.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAW,MAAM,aAAa,CAAC;AAqCjD,eAAO,MAAM,oBAAoB,EAAE,IAkClC,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,IAgBxB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,IAgBxB,CAAC;AAEF,eAAO,MAAM,SAAS,EAAE,IAgBvB,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,IAiCzB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,IAAI,EAM9B,CAAC"}
@@ -0,0 +1,123 @@
1
+ function findMatches(content, pattern, rule, severity, message, filename) {
2
+ const findings = [];
3
+ const lines = content.split("\n");
4
+ for (let i = 0; i < lines.length; i++) {
5
+ const line = lines[i];
6
+ let match;
7
+ pattern.lastIndex = 0;
8
+ while ((match = pattern.exec(line)) !== null) {
9
+ findings.push({
10
+ rule,
11
+ severity,
12
+ message,
13
+ file: filename,
14
+ line: i + 1,
15
+ column: match.index + 1,
16
+ snippet: line.trim(),
17
+ });
18
+ if (!pattern.global)
19
+ break;
20
+ }
21
+ }
22
+ return findings;
23
+ }
24
+ export const missingErrorHandling = {
25
+ name: "missing-error-handling",
26
+ description: "Detects async operations without try/catch",
27
+ severity: "warning",
28
+ languages: ["javascript", "typescript"],
29
+ check: (content, filename) => {
30
+ const findings = [];
31
+ const lines = content.split("\n");
32
+ // Look for await outside of try blocks
33
+ let inTry = 0;
34
+ for (let i = 0; i < lines.length; i++) {
35
+ const line = lines[i];
36
+ if (/\btry\s*\{/.test(line))
37
+ inTry++;
38
+ if (/\}\s*catch/.test(line))
39
+ inTry = Math.max(0, inTry - 1);
40
+ if (inTry === 0 && /\bawait\s+/.test(line)) {
41
+ // Check if it's in an async function without surrounding try
42
+ findings.push({
43
+ rule: "missing-error-handling",
44
+ severity: "warning",
45
+ message: "Async operation without error handling",
46
+ file: filename,
47
+ line: i + 1,
48
+ column: line.indexOf("await") + 1,
49
+ snippet: line.trim(),
50
+ });
51
+ }
52
+ }
53
+ return findings;
54
+ },
55
+ };
56
+ export const emptyCatch = {
57
+ name: "empty-catch",
58
+ description: "Detects empty catch blocks that swallow errors",
59
+ severity: "warning",
60
+ languages: ["javascript", "typescript"],
61
+ check: (content, filename) => {
62
+ const pattern = /catch\s*\([^)]*\)\s*\{\s*\}/g;
63
+ return findMatches(content, pattern, "empty-catch", "warning", "Empty catch block swallows errors", filename);
64
+ },
65
+ };
66
+ export const consoleLog = {
67
+ name: "console-log",
68
+ description: "Detects console.log left in code",
69
+ severity: "info",
70
+ languages: ["javascript", "typescript"],
71
+ check: (content, filename) => {
72
+ const pattern = /console\.log\s*\(/g;
73
+ return findMatches(content, pattern, "console-log", "info", "console.log statement found", filename);
74
+ },
75
+ };
76
+ export const todoFixme = {
77
+ name: "todo-fixme",
78
+ description: "Detects TODO/FIXME comments",
79
+ severity: "info",
80
+ languages: ["javascript", "typescript", "python", "ruby", "go"],
81
+ check: (content, filename) => {
82
+ const pattern = /\/\/\s*(?:TODO|FIXME|HACK|XXX|BUG)[\s:]/gi;
83
+ return findMatches(content, pattern, "todo-fixme", "info", "TODO/FIXME comment found", filename);
84
+ },
85
+ };
86
+ export const deepNesting = {
87
+ name: "deep-nesting",
88
+ description: "Detects deeply nested code (>4 levels)",
89
+ severity: "warning",
90
+ languages: ["javascript", "typescript"],
91
+ check: (content, filename) => {
92
+ const findings = [];
93
+ const lines = content.split("\n");
94
+ let depth = 0;
95
+ const MAX_DEPTH = 4;
96
+ for (let i = 0; i < lines.length; i++) {
97
+ const line = lines[i];
98
+ const opens = (line.match(/\{/g) || []).length;
99
+ const closes = (line.match(/\}/g) || []).length;
100
+ depth += opens - closes;
101
+ if (depth > MAX_DEPTH && opens > 0) {
102
+ findings.push({
103
+ rule: "deep-nesting",
104
+ severity: "warning",
105
+ message: `Code nested ${depth} levels deep (max: ${MAX_DEPTH})`,
106
+ file: filename,
107
+ line: i + 1,
108
+ column: 1,
109
+ snippet: line.trim(),
110
+ });
111
+ }
112
+ }
113
+ return findings;
114
+ },
115
+ };
116
+ export const qualityRules = [
117
+ missingErrorHandling,
118
+ emptyCatch,
119
+ consoleLog,
120
+ todoFixme,
121
+ deepNesting,
122
+ ];
123
+ //# sourceMappingURL=quality.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quality.js","sourceRoot":"","sources":["../../src/rules/quality.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ import type { Rule } from "../types.js";
2
+ export declare const sqlInjection: Rule;
3
+ export declare const commandInjection: Rule;
4
+ export declare const hardcodedSecret: Rule;
5
+ export declare const unsafeEval: Rule;
6
+ export declare const pathTraversal: Rule;
7
+ export declare const xssRisk: Rule;
8
+ export declare const securityRules: Rule[];
9
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../src/rules/security.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAW,MAAM,aAAa,CAAC;AAuCjD,eAAO,MAAM,YAAY,EAAE,IA8B1B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,IAgC9B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,IAsC7B,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,IA4BxB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,IA8B3B,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,IA8BrB,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,IAAI,EAO/B,CAAC"}
@@ -0,0 +1,168 @@
1
+ function findMatches(content, pattern, rule, severity, message, filename) {
2
+ const findings = [];
3
+ const lines = content.split("\n");
4
+ for (let i = 0; i < lines.length; i++) {
5
+ const line = lines[i];
6
+ let match;
7
+ // Reset regex for global patterns
8
+ pattern.lastIndex = 0;
9
+ while ((match = pattern.exec(line)) !== null) {
10
+ findings.push({
11
+ rule,
12
+ severity,
13
+ message,
14
+ file: filename,
15
+ line: i + 1,
16
+ column: match.index + 1,
17
+ snippet: line.trim(),
18
+ });
19
+ // Prevent infinite loop for non-global regex
20
+ if (!pattern.global)
21
+ break;
22
+ }
23
+ }
24
+ return findings;
25
+ }
26
+ export const sqlInjection = {
27
+ name: "sql-injection",
28
+ description: "Detects SQL queries with string interpolation",
29
+ severity: "error",
30
+ languages: ["javascript", "typescript", "python"],
31
+ check: (content, filename) => {
32
+ const patterns = [
33
+ // Template literals in SQL
34
+ /(?:query|execute|sql)\s*\(\s*`[^`]*\$\{/gi,
35
+ // String concatenation in SQL
36
+ /(?:query|execute|sql)\s*\(\s*['"][^'"]*['"]\s*\+/gi,
37
+ // Python f-strings in SQL
38
+ /(?:execute|cursor\.execute)\s*\(\s*f['"][^'"]*\{/gi,
39
+ ];
40
+ const findings = [];
41
+ for (const pattern of patterns) {
42
+ findings.push(...findMatches(content, pattern, "sql-injection", "error", "SQL injection risk: query uses string interpolation", filename));
43
+ }
44
+ return findings;
45
+ },
46
+ };
47
+ export const commandInjection = {
48
+ name: "command-injection",
49
+ description: "Detects shell commands with unsanitized input",
50
+ severity: "error",
51
+ languages: ["javascript", "typescript", "python"],
52
+ check: (content, filename) => {
53
+ const patterns = [
54
+ // exec with template literal
55
+ /(?:exec|execSync|spawn|spawnSync)\s*\(\s*`[^`]*\$\{/gi,
56
+ // exec with concatenation
57
+ /(?:exec|execSync|spawn|spawnSync)\s*\(\s*['"][^'"]*['"]\s*\+/gi,
58
+ // Python subprocess with f-string
59
+ /subprocess\.(?:run|call|Popen)\s*\(\s*f['"][^'"]*\{/gi,
60
+ // shell=True in Python
61
+ /subprocess\.(?:run|call|Popen)\s*\([^)]*shell\s*=\s*True/gi,
62
+ ];
63
+ const findings = [];
64
+ for (const pattern of patterns) {
65
+ findings.push(...findMatches(content, pattern, "command-injection", "error", "Command injection risk: shell command with unsanitized input", filename));
66
+ }
67
+ return findings;
68
+ },
69
+ };
70
+ export const hardcodedSecret = {
71
+ name: "hardcoded-secret",
72
+ description: "Detects hardcoded API keys, passwords, tokens",
73
+ severity: "error",
74
+ languages: ["javascript", "typescript", "python", "ruby", "go"],
75
+ check: (content, filename) => {
76
+ const patterns = [
77
+ // API keys
78
+ /(?:api[_-]?key|apikey)\s*[:=]\s*['"][a-zA-Z0-9_\-]{20,}['"]/gi,
79
+ // AWS keys
80
+ /(?:AKIA|ABIA|ACCA|ASIA)[A-Z0-9]{16}/g,
81
+ // Generic secrets
82
+ /(?:password|passwd|pwd|secret|token)\s*[:=]\s*['"][^'"]{8,}['"]/gi,
83
+ // Bearer tokens
84
+ /['"]Bearer\s+[a-zA-Z0-9_\-\.]+['"]/g,
85
+ // Private keys
86
+ /-----BEGIN\s+(?:RSA\s+)?PRIVATE\s+KEY-----/g,
87
+ // GitHub tokens
88
+ /gh[pousr]_[A-Za-z0-9_]{36,}/g,
89
+ // Slack tokens
90
+ /xox[baprs]-[A-Za-z0-9-]+/g,
91
+ ];
92
+ const findings = [];
93
+ for (const pattern of patterns) {
94
+ findings.push(...findMatches(content, pattern, "hardcoded-secret", "error", "Hardcoded secret detected", filename));
95
+ }
96
+ return findings;
97
+ },
98
+ };
99
+ export const unsafeEval = {
100
+ name: "unsafe-eval",
101
+ description: "Detects use of eval() or Function()",
102
+ severity: "error",
103
+ languages: ["javascript", "typescript"],
104
+ check: (content, filename) => {
105
+ const patterns = [
106
+ /\beval\s*\(/g,
107
+ /new\s+Function\s*\(/g,
108
+ /setTimeout\s*\(\s*['"`]/g,
109
+ /setInterval\s*\(\s*['"`]/g,
110
+ ];
111
+ const findings = [];
112
+ for (const pattern of patterns) {
113
+ findings.push(...findMatches(content, pattern, "unsafe-eval", "error", "Unsafe eval() or Function() usage detected", filename));
114
+ }
115
+ return findings;
116
+ },
117
+ };
118
+ export const pathTraversal = {
119
+ name: "path-traversal",
120
+ description: "Detects unsanitized file path operations",
121
+ severity: "error",
122
+ languages: ["javascript", "typescript", "python"],
123
+ check: (content, filename) => {
124
+ const patterns = [
125
+ // Direct path concatenation
126
+ /(?:readFile|writeFile|unlink|rmdir|mkdir)(?:Sync)?\s*\(\s*(?:req\.|request\.|params\.|query\.)/gi,
127
+ // Python path with user input
128
+ /open\s*\(\s*(?:request\.|args\.|kwargs\.)/gi,
129
+ // Path join with user input
130
+ /path\.join\s*\([^)]*(?:req\.|request\.|params\.|query\.)/gi,
131
+ ];
132
+ const findings = [];
133
+ for (const pattern of patterns) {
134
+ findings.push(...findMatches(content, pattern, "path-traversal", "error", "Path traversal risk: file operation with user input", filename));
135
+ }
136
+ return findings;
137
+ },
138
+ };
139
+ export const xssRisk = {
140
+ name: "xss-risk",
141
+ description: "Detects potential XSS in HTML generation",
142
+ severity: "warning",
143
+ languages: ["javascript", "typescript"],
144
+ check: (content, filename) => {
145
+ const patterns = [
146
+ // innerHTML with variable
147
+ /\.innerHTML\s*=\s*[^'"]/g,
148
+ // document.write
149
+ /document\.write\s*\(/g,
150
+ // dangerouslySetInnerHTML
151
+ /dangerouslySetInnerHTML\s*=\s*\{\s*\{\s*__html\s*:/g,
152
+ ];
153
+ const findings = [];
154
+ for (const pattern of patterns) {
155
+ findings.push(...findMatches(content, pattern, "xss-risk", "warning", "Potential XSS risk: unsafe HTML manipulation", filename));
156
+ }
157
+ return findings;
158
+ },
159
+ };
160
+ export const securityRules = [
161
+ sqlInjection,
162
+ commandInjection,
163
+ hardcodedSecret,
164
+ unsafeEval,
165
+ pathTraversal,
166
+ xssRisk,
167
+ ];
168
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/rules/security.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ export type Severity = "info" | "warning" | "error";
2
+ export interface Finding {
3
+ rule: string;
4
+ severity: Severity;
5
+ message: string;
6
+ file: string;
7
+ line: number;
8
+ column: number;
9
+ snippet?: string;
10
+ }
11
+ export interface Rule {
12
+ name: string;
13
+ description: string;
14
+ severity: Severity;
15
+ languages: string[];
16
+ check: (content: string, filename: string) => Finding[];
17
+ }
18
+ export interface Config {
19
+ rules: Record<string, Severity | "off">;
20
+ ignore: string[];
21
+ languages: string[];
22
+ }
23
+ export interface AuditResult {
24
+ findings: Finding[];
25
+ filesScanned: number;
26
+ errorCount: number;
27
+ warningCount: number;
28
+ infoCount: number;
29
+ }
30
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;AAEpD,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,IAAI;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,OAAO,EAAE,CAAC;CACzD;AAED,MAAM,WAAW,MAAM;IACrB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,KAAK,CAAC,CAAC;IACxC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;CACnB"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@claude-tools-i-use/ai-code-audit",
3
+ "version": "0.1.0",
4
+ "description": "Security and quality linter for AI-generated code",
5
+ "type": "module",
6
+ "main": "dist/index.js",
7
+ "bin": {
8
+ "ai-code-audit": "dist/cli.js",
9
+ "aca": "dist/cli.js"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "build": "tsc",
16
+ "dev": "tsc --watch",
17
+ "start": "node dist/cli.js",
18
+ "test": "node --test",
19
+ "clean": "rm -rf dist",
20
+ "prepublishOnly": "npm run build"
21
+ },
22
+ "keywords": [
23
+ "ai",
24
+ "security",
25
+ "lint",
26
+ "audit",
27
+ "code-review",
28
+ "owasp"
29
+ ],
30
+ "author": "Josh Duffy",
31
+ "license": "MIT",
32
+ "repository": {
33
+ "type": "git",
34
+ "url": "https://github.com/joshduffy/claude-tools.git",
35
+ "directory": "packages/ai-code-audit"
36
+ },
37
+ "homepage": "https://joshduffy.dev/tools",
38
+ "devDependencies": {
39
+ "@types/node": "^22.10.0",
40
+ "typescript": "^5.7.0"
41
+ },
42
+ "engines": {
43
+ "node": ">=18.0.0"
44
+ }
45
+ }