truss-code-review-mcp 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.
Files changed (77) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +60 -0
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +88 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/lib/ai-review.d.ts +21 -0
  8. package/dist/lib/ai-review.d.ts.map +1 -0
  9. package/dist/lib/ai-review.js +185 -0
  10. package/dist/lib/ai-review.js.map +1 -0
  11. package/dist/lib/complexity.d.ts +20 -0
  12. package/dist/lib/complexity.d.ts.map +1 -0
  13. package/dist/lib/complexity.js +272 -0
  14. package/dist/lib/complexity.js.map +1 -0
  15. package/dist/lib/license.d.ts +15 -0
  16. package/dist/lib/license.d.ts.map +1 -0
  17. package/dist/lib/license.js +72 -0
  18. package/dist/lib/license.js.map +1 -0
  19. package/dist/lib/patterns.d.ts +27 -0
  20. package/dist/lib/patterns.d.ts.map +1 -0
  21. package/dist/lib/patterns.js +102 -0
  22. package/dist/lib/patterns.js.map +1 -0
  23. package/dist/tools/check-complexity.d.ts +6 -0
  24. package/dist/tools/check-complexity.d.ts.map +1 -0
  25. package/dist/tools/check-complexity.js +34 -0
  26. package/dist/tools/check-complexity.js.map +1 -0
  27. package/dist/tools/deep-review.d.ts +6 -0
  28. package/dist/tools/deep-review.d.ts.map +1 -0
  29. package/dist/tools/deep-review.js +58 -0
  30. package/dist/tools/deep-review.js.map +1 -0
  31. package/dist/tools/detect-antipatterns.d.ts +6 -0
  32. package/dist/tools/detect-antipatterns.d.ts.map +1 -0
  33. package/dist/tools/detect-antipatterns.js +44 -0
  34. package/dist/tools/detect-antipatterns.js.map +1 -0
  35. package/dist/tools/explain-code.d.ts +6 -0
  36. package/dist/tools/explain-code.d.ts.map +1 -0
  37. package/dist/tools/explain-code.js +56 -0
  38. package/dist/tools/explain-code.js.map +1 -0
  39. package/dist/tools/optimize-code.d.ts +6 -0
  40. package/dist/tools/optimize-code.d.ts.map +1 -0
  41. package/dist/tools/optimize-code.js +57 -0
  42. package/dist/tools/optimize-code.js.map +1 -0
  43. package/dist/tools/review-diff.d.ts +8 -0
  44. package/dist/tools/review-diff.d.ts.map +1 -0
  45. package/dist/tools/review-diff.js +333 -0
  46. package/dist/tools/review-diff.js.map +1 -0
  47. package/dist/tools/security-review.d.ts +6 -0
  48. package/dist/tools/security-review.d.ts.map +1 -0
  49. package/dist/tools/security-review.js +57 -0
  50. package/dist/tools/security-review.js.map +1 -0
  51. package/dist/tools/suggest-tests.d.ts +6 -0
  52. package/dist/tools/suggest-tests.d.ts.map +1 -0
  53. package/dist/tools/suggest-tests.js +78 -0
  54. package/dist/tools/suggest-tests.js.map +1 -0
  55. package/evals/eval-complexity.ts +202 -0
  56. package/evals/eval-review.ts +196 -0
  57. package/evals/run-evals.ts +51 -0
  58. package/glama.json +4 -0
  59. package/package.json +36 -0
  60. package/smithery.yaml +15 -0
  61. package/src/data/antipatterns/go.json +98 -0
  62. package/src/data/antipatterns/javascript.json +122 -0
  63. package/src/data/antipatterns/python.json +98 -0
  64. package/src/index.ts +109 -0
  65. package/src/lib/ai-review.ts +220 -0
  66. package/src/lib/complexity.ts +284 -0
  67. package/src/lib/license.ts +95 -0
  68. package/src/lib/patterns.ts +131 -0
  69. package/src/tools/check-complexity.ts +43 -0
  70. package/src/tools/deep-review.ts +67 -0
  71. package/src/tools/detect-antipatterns.ts +54 -0
  72. package/src/tools/explain-code.ts +65 -0
  73. package/src/tools/optimize-code.ts +66 -0
  74. package/src/tools/review-diff.ts +374 -0
  75. package/src/tools/security-review.ts +66 -0
  76. package/src/tools/suggest-tests.ts +90 -0
  77. package/tsconfig.json +19 -0
@@ -0,0 +1,272 @@
1
+ /**
2
+ * Cyclomatic complexity calculator.
3
+ * Uses regex-based analysis (not AST) for JS/TS, Python, Go.
4
+ * Counts decision points: if, else if, for, while, switch case, &&, ||, ternary, catch, etc.
5
+ */
6
+ function rateComplexity(complexity) {
7
+ if (complexity <= 5)
8
+ return 'simple';
9
+ if (complexity <= 10)
10
+ return 'moderate';
11
+ if (complexity <= 20)
12
+ return 'complex';
13
+ return 'very_complex';
14
+ }
15
+ // Count decision points in a block of code
16
+ function countDecisionPoints(code, language) {
17
+ let count = 0;
18
+ const lines = code.split('\n');
19
+ for (const line of lines) {
20
+ const trimmed = line.trim();
21
+ // Skip comments
22
+ if (language === 'python') {
23
+ if (trimmed.startsWith('#'))
24
+ continue;
25
+ }
26
+ else {
27
+ if (trimmed.startsWith('//') || trimmed.startsWith('/*') || trimmed.startsWith('*'))
28
+ continue;
29
+ }
30
+ // Count branching keywords
31
+ if (language === 'python') {
32
+ // Python decision points
33
+ if (/\bif\b/.test(trimmed) && !trimmed.startsWith('#'))
34
+ count++;
35
+ if (/\belif\b/.test(trimmed))
36
+ count++;
37
+ if (/\bfor\b/.test(trimmed))
38
+ count++;
39
+ if (/\bwhile\b/.test(trimmed))
40
+ count++;
41
+ if (/\bexcept\b/.test(trimmed))
42
+ count++;
43
+ // Boolean operators in conditions
44
+ const andMatches = trimmed.match(/\band\b/g);
45
+ if (andMatches)
46
+ count += andMatches.length;
47
+ const orMatches = trimmed.match(/\bor\b/g);
48
+ if (orMatches)
49
+ count += orMatches.length;
50
+ // Ternary (x if condition else y)
51
+ if (/\bif\b.*\belse\b/.test(trimmed) && !trimmed.startsWith('if') && !trimmed.startsWith('elif'))
52
+ count++;
53
+ }
54
+ else if (language === 'go') {
55
+ // Go decision points — count 'else if' separately from plain 'if'
56
+ if (/\belse\s+if\b/.test(trimmed)) {
57
+ count++; // else if
58
+ }
59
+ else if (/\bif\b/.test(trimmed)) {
60
+ count++; // plain if
61
+ }
62
+ if (/\bfor\b/.test(trimmed))
63
+ count++;
64
+ if (/\bcase\b/.test(trimmed) && !trimmed.startsWith('//'))
65
+ count++;
66
+ // Catch (Go doesn't have catch, but has recover pattern)
67
+ // Boolean operators
68
+ const andMatches = trimmed.match(/&&/g);
69
+ if (andMatches)
70
+ count += andMatches.length;
71
+ const orMatches = trimmed.match(/\|\|/g);
72
+ if (orMatches)
73
+ count += orMatches.length;
74
+ }
75
+ else {
76
+ // JavaScript / TypeScript decision points
77
+ // Count 'else if' separately — don't double-count with plain 'if'
78
+ if (/\belse\s+if\s*\(/.test(trimmed)) {
79
+ count++; // else if
80
+ }
81
+ else if (/\bif\s*\(/.test(trimmed)) {
82
+ count++; // plain if
83
+ }
84
+ if (/\bfor\s*\(/.test(trimmed))
85
+ count++;
86
+ if (/\bwhile\s*\(/.test(trimmed))
87
+ count++;
88
+ if (/\bcase\s+/.test(trimmed))
89
+ count++;
90
+ if (/\bcatch\s*\(/.test(trimmed))
91
+ count++;
92
+ // Ternary operator (? :) — count ? that aren't part of optional chaining (?.)
93
+ const ternaryMatches = trimmed.match(/\?\s*(?!\.)/g);
94
+ if (ternaryMatches)
95
+ count += ternaryMatches.length;
96
+ // Boolean operators
97
+ const andMatches = trimmed.match(/&&/g);
98
+ if (andMatches)
99
+ count += andMatches.length;
100
+ const orMatches = trimmed.match(/\|\|/g);
101
+ if (orMatches)
102
+ count += orMatches.length;
103
+ // Nullish coalescing doesn't count as a decision point
104
+ }
105
+ }
106
+ return count;
107
+ }
108
+ // Extract functions from JavaScript/TypeScript
109
+ function extractJsFunctions(code) {
110
+ const lines = code.split('\n');
111
+ const functions = [];
112
+ const funcPatterns = [
113
+ // function declarations: function name(...)
114
+ /(?:export\s+)?(?:async\s+)?function\s+(\w+)\s*\(/,
115
+ // arrow functions assigned: const name = (...) =>
116
+ /(?:const|let|var)\s+(\w+)\s*=\s*(?:async\s+)?(?:\([^)]*\)|[^=])\s*=>/,
117
+ // method definitions: name(...) { or async name(...)
118
+ /^\s*(?:async\s+)?(\w+)\s*\([^)]*\)\s*(?::\s*\w+[<>\[\],\s]*)?\s*\{/,
119
+ // class method: public/private/protected name(
120
+ /^\s*(?:public|private|protected|static|readonly|async|get|set)\s+(\w+)\s*\(/,
121
+ ];
122
+ for (let i = 0; i < lines.length; i++) {
123
+ const line = lines[i];
124
+ for (const pattern of funcPatterns) {
125
+ const match = line.match(pattern);
126
+ if (match && match[1] && match[1] !== 'if' && match[1] !== 'for' && match[1] !== 'while' && match[1] !== 'switch') {
127
+ // Find the function body by tracking braces
128
+ let braceCount = 0;
129
+ let started = false;
130
+ let endLine = i;
131
+ for (let j = i; j < lines.length; j++) {
132
+ for (const ch of lines[j]) {
133
+ if (ch === '{') {
134
+ braceCount++;
135
+ started = true;
136
+ }
137
+ else if (ch === '}') {
138
+ braceCount--;
139
+ }
140
+ }
141
+ if (started && braceCount <= 0) {
142
+ endLine = j;
143
+ break;
144
+ }
145
+ }
146
+ // For arrow functions without braces, body is just the line
147
+ if (!started) {
148
+ endLine = i;
149
+ // Check next few lines for the expression
150
+ for (let j = i; j < Math.min(i + 5, lines.length); j++) {
151
+ if (lines[j].includes(';') || lines[j].trim() === '') {
152
+ endLine = j;
153
+ break;
154
+ }
155
+ endLine = j;
156
+ }
157
+ }
158
+ const body = lines.slice(i, endLine + 1).join('\n');
159
+ functions.push({ name: match[1], startLine: i + 1, body, endLine: endLine + 1 });
160
+ break;
161
+ }
162
+ }
163
+ }
164
+ return functions;
165
+ }
166
+ // Extract functions from Python
167
+ function extractPythonFunctions(code) {
168
+ const lines = code.split('\n');
169
+ const functions = [];
170
+ for (let i = 0; i < lines.length; i++) {
171
+ const match = lines[i].match(/^(\s*)(?:async\s+)?def\s+(\w+)\s*\(/);
172
+ if (match) {
173
+ const indent = match[1].length;
174
+ const name = match[2];
175
+ let endLine = i;
176
+ // Find end of function by indentation
177
+ for (let j = i + 1; j < lines.length; j++) {
178
+ const trimmed = lines[j].trim();
179
+ if (trimmed === '' || trimmed.startsWith('#')) {
180
+ endLine = j;
181
+ continue;
182
+ }
183
+ const lineIndent = lines[j].match(/^(\s*)/)?.[1].length ?? 0;
184
+ if (lineIndent <= indent && trimmed !== '') {
185
+ break;
186
+ }
187
+ endLine = j;
188
+ }
189
+ const body = lines.slice(i, endLine + 1).join('\n');
190
+ functions.push({ name, startLine: i + 1, body, endLine: endLine + 1 });
191
+ }
192
+ }
193
+ return functions;
194
+ }
195
+ // Extract functions from Go
196
+ function extractGoFunctions(code) {
197
+ const lines = code.split('\n');
198
+ const functions = [];
199
+ for (let i = 0; i < lines.length; i++) {
200
+ const match = lines[i].match(/^func\s+(?:\(\s*\w+\s+\*?\w+\s*\)\s+)?(\w+)\s*\(/);
201
+ if (match) {
202
+ const name = match[1];
203
+ let braceCount = 0;
204
+ let started = false;
205
+ let endLine = i;
206
+ for (let j = i; j < lines.length; j++) {
207
+ for (const ch of lines[j]) {
208
+ if (ch === '{') {
209
+ braceCount++;
210
+ started = true;
211
+ }
212
+ else if (ch === '}') {
213
+ braceCount--;
214
+ }
215
+ }
216
+ if (started && braceCount <= 0) {
217
+ endLine = j;
218
+ break;
219
+ }
220
+ }
221
+ const body = lines.slice(i, endLine + 1).join('\n');
222
+ functions.push({ name, startLine: i + 1, body, endLine: endLine + 1 });
223
+ }
224
+ }
225
+ return functions;
226
+ }
227
+ export function calculateComplexity(code, language) {
228
+ const lang = language.toLowerCase().replace('typescript', 'javascript').replace('ts', 'javascript').replace('jsx', 'javascript').replace('tsx', 'javascript');
229
+ let extractedFunctions;
230
+ if (lang === 'python' || lang === 'py') {
231
+ extractedFunctions = extractPythonFunctions(code);
232
+ }
233
+ else if (lang === 'go' || lang === 'golang') {
234
+ extractedFunctions = extractGoFunctions(code);
235
+ }
236
+ else {
237
+ // Default to JS/TS extraction
238
+ extractedFunctions = extractJsFunctions(code);
239
+ }
240
+ const effectiveLang = (lang === 'py') ? 'python' : (lang === 'golang') ? 'go' : lang;
241
+ const functions = extractedFunctions.map(fn => {
242
+ // Base complexity is 1 (the function itself is one path)
243
+ const complexity = 1 + countDecisionPoints(fn.body, effectiveLang);
244
+ return {
245
+ name: fn.name,
246
+ startLine: fn.startLine,
247
+ endLine: fn.endLine,
248
+ complexity,
249
+ rating: rateComplexity(complexity),
250
+ };
251
+ });
252
+ // If no functions found, analyze the entire code as one unit
253
+ if (functions.length === 0) {
254
+ const complexity = 1 + countDecisionPoints(code, effectiveLang);
255
+ functions.push({
256
+ name: '<module>',
257
+ startLine: 1,
258
+ endLine: code.split('\n').length,
259
+ complexity,
260
+ rating: rateComplexity(complexity),
261
+ });
262
+ }
263
+ const overall = functions.reduce((sum, f) => sum + f.complexity, 0);
264
+ const averagePerFunction = functions.length > 0 ? Math.round((overall / functions.length) * 10) / 10 : 0;
265
+ return {
266
+ functions,
267
+ overall,
268
+ averagePerFunction,
269
+ rating: rateComplexity(averagePerFunction),
270
+ };
271
+ }
272
+ //# sourceMappingURL=complexity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"complexity.js","sourceRoot":"","sources":["../../src/lib/complexity.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * TRUSS License validation.
3
+ * Free tier: no key needed.
4
+ * Pro tier: requires TRUSS_LICENSE_KEY env var.
5
+ */
6
+ export interface LicenseStatus {
7
+ tier: 'free' | 'pro';
8
+ valid: boolean;
9
+ expiresAt: string | null;
10
+ }
11
+ export declare function getLicenseStatus(): Promise<LicenseStatus>;
12
+ export declare function requirePro(): Promise<void>;
13
+ export declare function hasAiKey(): boolean;
14
+ export declare function requireAiKey(): void;
15
+ //# sourceMappingURL=license.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"license.d.ts","sourceRoot":"","sources":["../../src/lib/license.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IACrB,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAqCD,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,aAAa,CAAC,CAyB/D;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAQhD;AAED,wBAAgB,QAAQ,IAAI,OAAO,CAElC;AAED,wBAAgB,YAAY,IAAI,IAAI,CAMnC"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * TRUSS License validation.
3
+ * Free tier: no key needed.
4
+ * Pro tier: requires TRUSS_LICENSE_KEY env var.
5
+ */
6
+ const TRUSS_API_BASE = 'https://api.truss.dev/v1/license';
7
+ function isValidKeyFormat(key) {
8
+ return /^truss_[0-9a-f]{32}$/.test(key);
9
+ }
10
+ let cachedStatus = null;
11
+ const CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour
12
+ async function validateRemote(key) {
13
+ try {
14
+ const response = await fetch(`${TRUSS_API_BASE}/validate/${key}`, {
15
+ method: 'GET',
16
+ headers: {
17
+ 'Accept': 'application/json',
18
+ 'User-Agent': 'truss-code-review-mcp/1.0.0',
19
+ },
20
+ signal: AbortSignal.timeout(5000),
21
+ });
22
+ if (!response.ok) {
23
+ return { valid: false, expiresAt: null };
24
+ }
25
+ const body = await response.json();
26
+ return {
27
+ valid: body.valid === true,
28
+ expiresAt: body.expires_at ?? null,
29
+ };
30
+ }
31
+ catch {
32
+ // Network error — fall back to format check
33
+ return { valid: isValidKeyFormat(key), expiresAt: null };
34
+ }
35
+ }
36
+ export async function getLicenseStatus() {
37
+ const key = process.env.TRUSS_LICENSE_KEY ?? '';
38
+ if (!key) {
39
+ return { tier: 'free', valid: true, expiresAt: null };
40
+ }
41
+ if (!isValidKeyFormat(key)) {
42
+ return { tier: 'free', valid: false, expiresAt: null };
43
+ }
44
+ // Check in-memory cache
45
+ if (cachedStatus && cachedStatus.key === key && Date.now() - cachedStatus.timestamp < CACHE_TTL_MS) {
46
+ return cachedStatus.status;
47
+ }
48
+ const result = await validateRemote(key);
49
+ const status = {
50
+ tier: result.valid ? 'pro' : 'free',
51
+ valid: result.valid,
52
+ expiresAt: result.expiresAt,
53
+ };
54
+ cachedStatus = { key, status, timestamp: Date.now() };
55
+ return status;
56
+ }
57
+ export async function requirePro() {
58
+ const status = await getLicenseStatus();
59
+ if (status.tier !== 'pro') {
60
+ throw new Error('This feature requires a TRUSS Pro license ($25/mo). ' +
61
+ 'Get yours at https://truss.dev/pricing and set TRUSS_LICENSE_KEY.');
62
+ }
63
+ }
64
+ export function hasAiKey() {
65
+ return !!(process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY);
66
+ }
67
+ export function requireAiKey() {
68
+ if (!hasAiKey()) {
69
+ throw new Error('AI-powered features require an API key. Set ANTHROPIC_API_KEY or OPENAI_API_KEY in your environment.');
70
+ }
71
+ }
72
+ //# sourceMappingURL=license.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"license.js","sourceRoot":"","sources":["../../src/lib/license.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Anti-pattern detection engine.
3
+ * Loads pattern databases per language and scans code.
4
+ */
5
+ export interface AntiPattern {
6
+ id: string;
7
+ pattern: string;
8
+ name: string;
9
+ description: string;
10
+ severity: 'info' | 'warning' | 'error';
11
+ fix: string;
12
+ }
13
+ export interface PatternMatch {
14
+ pattern: string;
15
+ description: string;
16
+ location: {
17
+ line: number;
18
+ column: number;
19
+ text: string;
20
+ };
21
+ severity: 'info' | 'warning' | 'error';
22
+ fix: string;
23
+ }
24
+ export declare function detectAntiPatterns(code: string, language: string): PatternMatch[];
25
+ export declare function getSupportedLanguages(): string[];
26
+ export declare function isLanguageSupported(language: string): boolean;
27
+ //# sourceMappingURL=patterns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patterns.d.ts","sourceRoot":"","sources":["../../src/lib/patterns.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAQH,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;IACvC,GAAG,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACzD,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC;IACvC,GAAG,EAAE,MAAM,CAAC;CACb;AAqCD,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,EAAE,CA2DjF;AAED,wBAAgB,qBAAqB,IAAI,MAAM,EAAE,CAEhD;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAE7D"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Anti-pattern detection engine.
3
+ * Loads pattern databases per language and scans code.
4
+ */
5
+ import { readFileSync } from 'node:fs';
6
+ import { join, dirname } from 'node:path';
7
+ import { fileURLToPath } from 'node:url';
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+ // Language aliases
10
+ const LANGUAGE_MAP = {
11
+ 'javascript': 'javascript',
12
+ 'js': 'javascript',
13
+ 'jsx': 'javascript',
14
+ 'typescript': 'javascript',
15
+ 'ts': 'javascript',
16
+ 'tsx': 'javascript',
17
+ 'python': 'python',
18
+ 'py': 'python',
19
+ 'go': 'go',
20
+ 'golang': 'go',
21
+ };
22
+ const patternCache = new Map();
23
+ function loadPatterns(language) {
24
+ const lang = LANGUAGE_MAP[language.toLowerCase()];
25
+ if (!lang)
26
+ return [];
27
+ if (patternCache.has(lang)) {
28
+ return patternCache.get(lang);
29
+ }
30
+ try {
31
+ const filePath = join(__dirname, '..', 'data', 'antipatterns', `${lang}.json`);
32
+ const raw = readFileSync(filePath, 'utf-8');
33
+ const patterns = JSON.parse(raw);
34
+ patternCache.set(lang, patterns);
35
+ return patterns;
36
+ }
37
+ catch {
38
+ return [];
39
+ }
40
+ }
41
+ export function detectAntiPatterns(code, language) {
42
+ const patterns = loadPatterns(language);
43
+ if (patterns.length === 0) {
44
+ return [];
45
+ }
46
+ const lines = code.split('\n');
47
+ const matches = [];
48
+ for (const ap of patterns) {
49
+ let regex;
50
+ try {
51
+ regex = new RegExp(ap.pattern, 'gm');
52
+ }
53
+ catch {
54
+ // Invalid regex in pattern database — skip
55
+ continue;
56
+ }
57
+ // Test each line individually for line-level patterns
58
+ for (let i = 0; i < lines.length; i++) {
59
+ const line = lines[i];
60
+ const trimmed = line.trim();
61
+ // Skip empty lines and simple comments
62
+ if (!trimmed)
63
+ continue;
64
+ // Reset regex state
65
+ regex.lastIndex = 0;
66
+ let match;
67
+ while ((match = regex.exec(line)) !== null) {
68
+ matches.push({
69
+ pattern: ap.name,
70
+ description: ap.description,
71
+ location: {
72
+ line: i + 1,
73
+ column: match.index + 1,
74
+ text: trimmed,
75
+ },
76
+ severity: ap.severity,
77
+ fix: ap.fix,
78
+ });
79
+ // Avoid infinite loops on zero-length matches
80
+ if (match.index === regex.lastIndex) {
81
+ regex.lastIndex++;
82
+ }
83
+ }
84
+ }
85
+ }
86
+ // Deduplicate: same pattern + same line = keep only first
87
+ const seen = new Set();
88
+ return matches.filter(m => {
89
+ const key = `${m.pattern}:${m.location.line}`;
90
+ if (seen.has(key))
91
+ return false;
92
+ seen.add(key);
93
+ return true;
94
+ });
95
+ }
96
+ export function getSupportedLanguages() {
97
+ return [...new Set(Object.values(LANGUAGE_MAP))];
98
+ }
99
+ export function isLanguageSupported(language) {
100
+ return language.toLowerCase() in LANGUAGE_MAP;
101
+ }
102
+ //# sourceMappingURL=patterns.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"patterns.js","sourceRoot":"","sources":["../../src/lib/patterns.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * check_complexity — Cyclomatic complexity calculator (Free tier)
3
+ */
4
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
+ export declare function registerCheckComplexity(server: McpServer): void;
6
+ //# sourceMappingURL=check-complexity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-complexity.d.ts","sourceRoot":"","sources":["../../src/tools/check-complexity.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAkC/D"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * check_complexity — Cyclomatic complexity calculator (Free tier)
3
+ */
4
+ import { z } from 'zod';
5
+ import { calculateComplexity } from '../lib/complexity.js';
6
+ export function registerCheckComplexity(server) {
7
+ server.tool('check_complexity', 'Calculate cyclomatic complexity of functions/methods. Counts decision points: if, else if, for, while, switch case, &&, ||, ternary, catch. Supports JS/TS, Python, Go. Free tier.', {
8
+ code: z.string().describe('Source code to analyze'),
9
+ language: z.string().describe('Programming language (javascript, typescript, python, go)'),
10
+ }, async ({ code, language }) => {
11
+ const result = calculateComplexity(code, language);
12
+ const output = {
13
+ functions: result.functions.map(f => ({
14
+ name: f.name,
15
+ lines: `${f.startLine}-${f.endLine}`,
16
+ complexity: f.complexity,
17
+ rating: f.rating,
18
+ })),
19
+ overall: result.overall,
20
+ average_per_function: result.averagePerFunction,
21
+ rating: result.rating,
22
+ thresholds: {
23
+ simple: '1-5',
24
+ moderate: '6-10',
25
+ complex: '11-20',
26
+ very_complex: '21+',
27
+ },
28
+ };
29
+ return {
30
+ content: [{ type: 'text', text: JSON.stringify(output, null, 2) }],
31
+ };
32
+ });
33
+ }
34
+ //# sourceMappingURL=check-complexity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"check-complexity.js","sourceRoot":"","sources":["../../src/tools/check-complexity.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAE3D,MAAM,UAAU,uBAAuB,CAAC,MAAiB;IACvD,MAAM,CAAC,IAAI,CACT,kBAAkB,EAClB,oLAAoL,EACpL;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wBAAwB,CAAC;QACnD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2DAA2D,CAAC;KAC3F,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC3B,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAEnD,MAAM,MAAM,GAAG;YACb,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;gBACpC,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,KAAK,EAAE,GAAG,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,OAAO,EAAE;gBACpC,UAAU,EAAE,CAAC,CAAC,UAAU;gBACxB,MAAM,EAAE,CAAC,CAAC,MAAM;aACjB,CAAC,CAAC;YACH,OAAO,EAAE,MAAM,CAAC,OAAO;YACvB,oBAAoB,EAAE,MAAM,CAAC,kBAAkB;YAC/C,MAAM,EAAE,MAAM,CAAC,MAAM;YACrB,UAAU,EAAE;gBACV,MAAM,EAAE,KAAK;gBACb,QAAQ,EAAE,MAAM;gBAChB,OAAO,EAAE,OAAO;gBAChB,YAAY,EAAE,KAAK;aACpB;SACF,CAAC;QAEF,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SAC5E,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * deep_review — AI-powered comprehensive code review (Pro tier)
3
+ */
4
+ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
5
+ export declare function registerDeepReview(server: McpServer): void;
6
+ //# sourceMappingURL=deep-review.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deep-review.d.ts","sourceRoot":"","sources":["../../src/tools/deep-review.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAKpE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAyD1D"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * deep_review — AI-powered comprehensive code review (Pro tier)
3
+ */
4
+ import { z } from 'zod';
5
+ import { requirePro, requireAiKey } from '../lib/license.js';
6
+ import { aiReview, DEEP_REVIEW_SYSTEM } from '../lib/ai-review.js';
7
+ export function registerDeepReview(server) {
8
+ server.tool('deep_review', 'AI-powered comprehensive code review covering architecture, security, performance, error handling, and maintainability. Returns scored findings with remediation. Pro tier — requires TRUSS_LICENSE_KEY + ANTHROPIC_API_KEY or OPENAI_API_KEY.', {
9
+ code: z.string().describe('Source code to review'),
10
+ language: z.string().describe('Programming language'),
11
+ context: z.string().optional().describe('Additional context (e.g., "this is a REST API handler", "performance-critical path")'),
12
+ }, async ({ code, language, context }) => {
13
+ await requirePro();
14
+ requireAiKey();
15
+ const userPrompt = [
16
+ `Language: ${language}`,
17
+ context ? `Context: ${context}` : '',
18
+ '',
19
+ '```',
20
+ code,
21
+ '```',
22
+ ].filter(Boolean).join('\n');
23
+ try {
24
+ const result = await aiReview(DEEP_REVIEW_SYSTEM, userPrompt);
25
+ let parsed;
26
+ try {
27
+ parsed = JSON.parse(result.content);
28
+ }
29
+ catch {
30
+ parsed = { raw_review: result.content };
31
+ }
32
+ return {
33
+ content: [{
34
+ type: 'text',
35
+ text: JSON.stringify({
36
+ review: parsed,
37
+ meta: {
38
+ model: result.model,
39
+ provider: result.provider,
40
+ tokens: result.tokensUsed,
41
+ },
42
+ }, null, 2),
43
+ }],
44
+ };
45
+ }
46
+ catch (err) {
47
+ return {
48
+ content: [{
49
+ type: 'text',
50
+ text: JSON.stringify({
51
+ error: err instanceof Error ? err.message : String(err),
52
+ }),
53
+ }],
54
+ };
55
+ }
56
+ });
57
+ }
58
+ //# sourceMappingURL=deep-review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deep-review.js","sourceRoot":"","sources":["../../src/tools/deep-review.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAEnE,MAAM,UAAU,kBAAkB,CAAC,MAAiB;IAClD,MAAM,CAAC,IAAI,CACT,aAAa,EACb,gPAAgP,EAChP;QACE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,uBAAuB,CAAC;QAClD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sBAAsB,CAAC;QACrD,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sFAAsF,CAAC;KAChI,EACD,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE;QACpC,MAAM,UAAU,EAAE,CAAC;QACnB,YAAY,EAAE,CAAC;QAEf,MAAM,UAAU,GAAG;YACjB,aAAa,QAAQ,EAAE;YACvB,OAAO,CAAC,CAAC,CAAC,YAAY,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE;YACpC,EAAE;YACF,KAAK;YACL,IAAI;YACJ,KAAK;SACN,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAE7B,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,kBAAkB,EAAE,UAAU,CAAC,CAAC;YAE9D,IAAI,MAAe,CAAC;YACpB,IAAI,CAAC;gBACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;YACtC,CAAC;YAAC,MAAM,CAAC;gBACP,MAAM,GAAG,EAAE,UAAU,EAAE,MAAM,CAAC,OAAO,EAAE,CAAC;YAC1C,CAAC;YAED,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,MAAM,EAAE,MAAM;4BACd,IAAI,EAAE;gCACJ,KAAK,EAAE,MAAM,CAAC,KAAK;gCACnB,QAAQ,EAAE,MAAM,CAAC,QAAQ;gCACzB,MAAM,EAAE,MAAM,CAAC,UAAU;6BAC1B;yBACF,EAAE,IAAI,EAAE,CAAC,CAAC;qBACZ,CAAC;aACH,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAe;wBACrB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;4BACnB,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;yBACxD,CAAC;qBACH,CAAC;aACH,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}