vantaverse-ai-reviewer 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.
Files changed (55) hide show
  1. package/README.md +129 -0
  2. package/bin/cli.js +12 -0
  3. package/dist/ai/agent.d.ts +54 -0
  4. package/dist/ai/agent.d.ts.map +1 -0
  5. package/dist/ai/agent.js +141 -0
  6. package/dist/ai/agent.js.map +1 -0
  7. package/dist/ai/gemini-client.d.ts +37 -0
  8. package/dist/ai/gemini-client.d.ts.map +1 -0
  9. package/dist/ai/gemini-client.js +75 -0
  10. package/dist/ai/gemini-client.js.map +1 -0
  11. package/dist/ai/prompts.d.ts +25 -0
  12. package/dist/ai/prompts.d.ts.map +1 -0
  13. package/dist/ai/prompts.js +176 -0
  14. package/dist/ai/prompts.js.map +1 -0
  15. package/dist/auth/token-manager.d.ts +33 -0
  16. package/dist/auth/token-manager.d.ts.map +1 -0
  17. package/dist/auth/token-manager.js +97 -0
  18. package/dist/auth/token-manager.js.map +1 -0
  19. package/dist/commands/config.d.ts +12 -0
  20. package/dist/commands/config.d.ts.map +1 -0
  21. package/dist/commands/config.js +84 -0
  22. package/dist/commands/config.js.map +1 -0
  23. package/dist/commands/scan.d.ts +14 -0
  24. package/dist/commands/scan.d.ts.map +1 -0
  25. package/dist/commands/scan.js +110 -0
  26. package/dist/commands/scan.js.map +1 -0
  27. package/dist/core/executor.d.ts +33 -0
  28. package/dist/core/executor.d.ts.map +1 -0
  29. package/dist/core/executor.js +149 -0
  30. package/dist/core/executor.js.map +1 -0
  31. package/dist/core/framework-detector.d.ts +20 -0
  32. package/dist/core/framework-detector.d.ts.map +1 -0
  33. package/dist/core/framework-detector.js +155 -0
  34. package/dist/core/framework-detector.js.map +1 -0
  35. package/dist/core/scanner.d.ts +34 -0
  36. package/dist/core/scanner.d.ts.map +1 -0
  37. package/dist/core/scanner.js +172 -0
  38. package/dist/core/scanner.js.map +1 -0
  39. package/dist/core/security.d.ts +40 -0
  40. package/dist/core/security.d.ts.map +1 -0
  41. package/dist/core/security.js +118 -0
  42. package/dist/core/security.js.map +1 -0
  43. package/dist/index.d.ts +5 -0
  44. package/dist/index.d.ts.map +1 -0
  45. package/dist/index.js +40 -0
  46. package/dist/index.js.map +1 -0
  47. package/dist/reporters/markdown.d.ts +25 -0
  48. package/dist/reporters/markdown.d.ts.map +1 -0
  49. package/dist/reporters/markdown.js +135 -0
  50. package/dist/reporters/markdown.js.map +1 -0
  51. package/dist/utils/logger.d.ts +50 -0
  52. package/dist/utils/logger.d.ts.map +1 -0
  53. package/dist/utils/logger.js +94 -0
  54. package/dist/utils/logger.js.map +1 -0
  55. package/package.json +51 -0
@@ -0,0 +1,155 @@
1
+ /**
2
+ * Framework Detector - Auto-detect project type
3
+ */
4
+ import fs from 'fs';
5
+ import path from 'path';
6
+ const FRAMEWORK_CONFIGS = {
7
+ nextjs: {
8
+ displayName: 'Next.js',
9
+ description: 'React framework with SSR/SSG',
10
+ scanPatterns: ['app/**/*.{ts,tsx,js,jsx}', 'pages/**/*.{ts,tsx,js,jsx}', 'components/**/*.{ts,tsx,js,jsx}'],
11
+ ignorePatterns: ['.next/**', 'node_modules/**']
12
+ },
13
+ react: {
14
+ displayName: 'React',
15
+ description: 'React SPA',
16
+ scanPatterns: ['src/**/*.{ts,tsx,js,jsx}', 'components/**/*.{ts,tsx,js,jsx}'],
17
+ ignorePatterns: ['build/**', 'node_modules/**']
18
+ },
19
+ vite: {
20
+ displayName: 'Vite',
21
+ description: 'Vite-powered frontend',
22
+ scanPatterns: ['src/**/*.{ts,tsx,js,jsx,vue,svelte}'],
23
+ ignorePatterns: ['dist/**', 'node_modules/**']
24
+ },
25
+ angular: {
26
+ displayName: 'Angular',
27
+ description: 'Angular framework',
28
+ scanPatterns: ['src/**/*.{ts,html,scss,css}'],
29
+ ignorePatterns: ['dist/**', 'node_modules/**', '.angular/**']
30
+ },
31
+ vue: {
32
+ displayName: 'Vue.js',
33
+ description: 'Vue.js framework',
34
+ scanPatterns: ['src/**/*.{vue,ts,js}'],
35
+ ignorePatterns: ['dist/**', 'node_modules/**']
36
+ },
37
+ svelte: {
38
+ displayName: 'Svelte',
39
+ description: 'Svelte framework',
40
+ scanPatterns: ['src/**/*.{svelte,ts,js}'],
41
+ ignorePatterns: ['build/**', '.svelte-kit/**', 'node_modules/**']
42
+ },
43
+ django: {
44
+ displayName: 'Django',
45
+ description: 'Python Django framework',
46
+ scanPatterns: ['**/*.py', '**/templates/**/*.html'],
47
+ ignorePatterns: ['venv/**', '__pycache__/**', '*.pyc', 'migrations/**']
48
+ },
49
+ flask: {
50
+ displayName: 'Flask',
51
+ description: 'Python Flask framework',
52
+ scanPatterns: ['**/*.py', 'templates/**/*.html'],
53
+ ignorePatterns: ['venv/**', '__pycache__/**', '*.pyc']
54
+ },
55
+ express: {
56
+ displayName: 'Express.js',
57
+ description: 'Node.js Express backend',
58
+ scanPatterns: ['**/*.{ts,js}', 'routes/**/*.{ts,js}', 'controllers/**/*.{ts,js}'],
59
+ ignorePatterns: ['node_modules/**', 'dist/**']
60
+ },
61
+ nestjs: {
62
+ displayName: 'NestJS',
63
+ description: 'NestJS backend framework',
64
+ scanPatterns: ['src/**/*.ts'],
65
+ ignorePatterns: ['node_modules/**', 'dist/**']
66
+ },
67
+ unknown: {
68
+ displayName: 'Unknown',
69
+ description: 'Generic project',
70
+ scanPatterns: ['**/*.{ts,tsx,js,jsx,py,java,go,rs}'],
71
+ ignorePatterns: ['node_modules/**', 'dist/**', 'build/**', 'venv/**', '__pycache__/**']
72
+ }
73
+ };
74
+ /**
75
+ * Detect the framework used in a project
76
+ */
77
+ export async function detectFramework(repoRoot) {
78
+ const exists = async (file) => {
79
+ try {
80
+ await fs.promises.access(path.join(repoRoot, file));
81
+ return true;
82
+ }
83
+ catch {
84
+ return false;
85
+ }
86
+ };
87
+ // Check for Next.js
88
+ if (await exists('next.config.js') || await exists('next.config.ts') || await exists('next.config.mjs')) {
89
+ return { name: 'nextjs', ...FRAMEWORK_CONFIGS.nextjs };
90
+ }
91
+ // Check for Angular
92
+ if (await exists('angular.json')) {
93
+ return { name: 'angular', ...FRAMEWORK_CONFIGS.angular };
94
+ }
95
+ // Check for Vue
96
+ if (await exists('vue.config.js') || await exists('nuxt.config.js') || await exists('nuxt.config.ts')) {
97
+ return { name: 'vue', ...FRAMEWORK_CONFIGS.vue };
98
+ }
99
+ // Check for Svelte
100
+ if (await exists('svelte.config.js') || await exists('svelte.config.ts')) {
101
+ return { name: 'svelte', ...FRAMEWORK_CONFIGS.svelte };
102
+ }
103
+ // Check for Vite (but not specific framework)
104
+ if (await exists('vite.config.js') || await exists('vite.config.ts')) {
105
+ return { name: 'vite', ...FRAMEWORK_CONFIGS.vite };
106
+ }
107
+ // Check for NestJS
108
+ if (await exists('nest-cli.json')) {
109
+ return { name: 'nestjs', ...FRAMEWORK_CONFIGS.nestjs };
110
+ }
111
+ // Check for Django
112
+ if (await exists('manage.py')) {
113
+ return { name: 'django', ...FRAMEWORK_CONFIGS.django };
114
+ }
115
+ // Check for Flask (app.py with Flask import)
116
+ if (await exists('app.py') || await exists('wsgi.py')) {
117
+ return { name: 'flask', ...FRAMEWORK_CONFIGS.flask };
118
+ }
119
+ // Check for Express
120
+ if (await exists('package.json')) {
121
+ try {
122
+ const pkg = JSON.parse(await fs.promises.readFile(path.join(repoRoot, 'package.json'), 'utf-8'));
123
+ if (pkg.dependencies?.express || pkg.devDependencies?.express) {
124
+ return { name: 'express', ...FRAMEWORK_CONFIGS.express };
125
+ }
126
+ if (pkg.dependencies?.react || pkg.devDependencies?.react) {
127
+ return { name: 'react', ...FRAMEWORK_CONFIGS.react };
128
+ }
129
+ }
130
+ catch {
131
+ // Ignore JSON parse errors
132
+ }
133
+ }
134
+ return { name: 'unknown', ...FRAMEWORK_CONFIGS.unknown };
135
+ }
136
+ /**
137
+ * Get framework-specific analysis hints
138
+ */
139
+ export function getFrameworkHints(framework) {
140
+ const hints = {
141
+ nextjs: 'Focus on: App Router structure, Server Components, API routes, metadata, loading/error states',
142
+ react: 'Focus on: Component composition, hooks usage, state management, prop drilling, memo usage',
143
+ vite: 'Focus on: Build configuration, HMR setup, plugin usage, environment variables',
144
+ angular: 'Focus on: Module structure, dependency injection, RxJS usage, template syntax',
145
+ vue: 'Focus on: Composition API, reactivity, Pinia/Vuex stores, template directives',
146
+ svelte: 'Focus on: Reactive declarations, stores, component lifecycle, SSR handling',
147
+ django: 'Focus on: View logic, model design, URL patterns, template security, middleware',
148
+ flask: 'Focus on: Route handlers, blueprints, request handling, template rendering',
149
+ express: 'Focus on: Middleware chain, route organization, error handling, async patterns',
150
+ nestjs: 'Focus on: Module structure, decorators, dependency injection, guards, pipes',
151
+ unknown: 'General code quality analysis'
152
+ };
153
+ return hints[framework];
154
+ }
155
+ //# sourceMappingURL=framework-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"framework-detector.js","sourceRoot":"","sources":["../../src/core/framework-detector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Scanner - Discover and categorize files in the repository
3
+ */
4
+ import type { FrameworkInfo } from './framework-detector.js';
5
+ export interface ScannedFile {
6
+ path: string;
7
+ relativePath: string;
8
+ size: number;
9
+ category: FileCategory;
10
+ extension: string;
11
+ }
12
+ export type FileCategory = 'component' | 'page' | 'api' | 'utility' | 'config' | 'test' | 'style' | 'type' | 'other';
13
+ export interface ScanResult {
14
+ files: ScannedFile[];
15
+ totalSize: number;
16
+ byCategory: Record<FileCategory, ScannedFile[]>;
17
+ skipped: string[];
18
+ }
19
+ /**
20
+ * Scan repository for files matching framework patterns
21
+ */
22
+ export declare function scanRepository(repoRoot: string, framework: FrameworkInfo, options?: {
23
+ maxFiles?: number;
24
+ maxFileSizeKb?: number;
25
+ }): Promise<ScanResult>;
26
+ /**
27
+ * Read multiple files with content
28
+ */
29
+ export declare function readFiles(files: ScannedFile[], repoRoot: string, maxSizeKb?: number): Promise<Map<string, string>>;
30
+ /**
31
+ * Get a summary of scan results
32
+ */
33
+ export declare function getScanSummary(result: ScanResult): string;
34
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../../src/core/scanner.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAE7D,MAAM,WAAW,WAAW;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,YAAY,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,MAAM,YAAY,GAClB,WAAW,GACX,MAAM,GACN,KAAK,GACL,SAAS,GACT,QAAQ,GACR,MAAM,GACN,OAAO,GACP,MAAM,GACN,OAAO,CAAC;AAEd,MAAM,WAAW,UAAU;IACvB,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC,YAAY,EAAE,WAAW,EAAE,CAAC,CAAC;IAChD,OAAO,EAAE,MAAM,EAAE,CAAC;CACrB;AAwDD;;GAEG;AACH,wBAAsB,cAAc,CAChC,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,aAAa,EACxB,OAAO,GAAE;IACL,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACrB,GACP,OAAO,CAAC,UAAU,CAAC,CA+ErB;AAED;;GAEG;AACH,wBAAsB,SAAS,CAC3B,KAAK,EAAE,WAAW,EAAE,EACpB,QAAQ,EAAE,MAAM,EAChB,SAAS,GAAE,MAAY,GACxB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAc9B;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CAgCzD"}
@@ -0,0 +1,172 @@
1
+ /**
2
+ * Scanner - Discover and categorize files in the repository
3
+ */
4
+ import { glob } from 'glob';
5
+ import path from 'path';
6
+ import fs from 'fs';
7
+ import { SECURITY_IGNORE_PATTERNS, validatePath, safeReadFile } from './security.js';
8
+ /**
9
+ * Categorize a file based on its path and extension
10
+ */
11
+ function categorizeFile(relativePath, extension) {
12
+ const lowerPath = relativePath.toLowerCase();
13
+ // Test files
14
+ if (lowerPath.includes('.test.') || lowerPath.includes('.spec.') ||
15
+ lowerPath.includes('__tests__') || lowerPath.includes('__test__')) {
16
+ return 'test';
17
+ }
18
+ // Config files
19
+ if (lowerPath.includes('config') || extension === 'json' ||
20
+ lowerPath.endsWith('.config.ts') || lowerPath.endsWith('.config.js')) {
21
+ return 'config';
22
+ }
23
+ // Type definitions
24
+ if (extension === 'd.ts' || lowerPath.includes('/types/') || lowerPath.includes('/interfaces/')) {
25
+ return 'type';
26
+ }
27
+ // Style files
28
+ if (['css', 'scss', 'sass', 'less', 'styl'].includes(extension)) {
29
+ return 'style';
30
+ }
31
+ // API routes
32
+ if (lowerPath.includes('/api/') || lowerPath.includes('/routes/') ||
33
+ lowerPath.includes('/controllers/') || lowerPath.includes('/handlers/')) {
34
+ return 'api';
35
+ }
36
+ // Pages
37
+ if (lowerPath.includes('/pages/') || lowerPath.includes('/app/') &&
38
+ (lowerPath.includes('page.') || lowerPath.includes('layout.'))) {
39
+ return 'page';
40
+ }
41
+ // Components
42
+ if (lowerPath.includes('/components/') || lowerPath.includes('/ui/')) {
43
+ return 'component';
44
+ }
45
+ // Utilities
46
+ if (lowerPath.includes('/utils/') || lowerPath.includes('/helpers/') ||
47
+ lowerPath.includes('/lib/') || lowerPath.includes('/services/')) {
48
+ return 'utility';
49
+ }
50
+ return 'other';
51
+ }
52
+ /**
53
+ * Scan repository for files matching framework patterns
54
+ */
55
+ export async function scanRepository(repoRoot, framework, options = {}) {
56
+ const { maxFiles = 500, maxFileSizeKb = 500 } = options;
57
+ const maxFileSize = maxFileSizeKb * 1024;
58
+ const allIgnorePatterns = [
59
+ ...SECURITY_IGNORE_PATTERNS,
60
+ ...framework.ignorePatterns
61
+ ];
62
+ const files = [];
63
+ const skipped = [];
64
+ let totalSize = 0;
65
+ // Scan using framework patterns
66
+ for (const pattern of framework.scanPatterns) {
67
+ const matches = await glob(pattern, {
68
+ cwd: repoRoot,
69
+ ignore: allIgnorePatterns,
70
+ nodir: true,
71
+ absolute: false
72
+ });
73
+ for (const relativePath of matches) {
74
+ if (files.length >= maxFiles) {
75
+ skipped.push(`Limit reached (${maxFiles} files)`);
76
+ break;
77
+ }
78
+ const absolutePath = path.join(repoRoot, relativePath);
79
+ try {
80
+ // Validate path is within repo
81
+ validatePath(absolutePath, repoRoot);
82
+ const stats = await fs.promises.stat(absolutePath);
83
+ if (stats.size > maxFileSize) {
84
+ skipped.push(`${relativePath} (too large: ${(stats.size / 1024).toFixed(1)}KB)`);
85
+ continue;
86
+ }
87
+ const extension = path.extname(relativePath).slice(1).toLowerCase();
88
+ const category = categorizeFile(relativePath, extension);
89
+ // Avoid duplicates
90
+ if (!files.some(f => f.relativePath === relativePath)) {
91
+ files.push({
92
+ path: absolutePath,
93
+ relativePath,
94
+ size: stats.size,
95
+ category,
96
+ extension
97
+ });
98
+ totalSize += stats.size;
99
+ }
100
+ }
101
+ catch (error) {
102
+ skipped.push(`${relativePath} (${error instanceof Error ? error.message : 'error'})`);
103
+ }
104
+ }
105
+ }
106
+ // Group by category
107
+ const byCategory = {
108
+ component: [],
109
+ page: [],
110
+ api: [],
111
+ utility: [],
112
+ config: [],
113
+ test: [],
114
+ style: [],
115
+ type: [],
116
+ other: []
117
+ };
118
+ for (const file of files) {
119
+ byCategory[file.category].push(file);
120
+ }
121
+ return { files, totalSize, byCategory, skipped };
122
+ }
123
+ /**
124
+ * Read multiple files with content
125
+ */
126
+ export async function readFiles(files, repoRoot, maxSizeKb = 100) {
127
+ const contents = new Map();
128
+ const maxSize = maxSizeKb * 1024;
129
+ for (const file of files) {
130
+ try {
131
+ const content = await safeReadFile(file.path, repoRoot, maxSize);
132
+ contents.set(file.relativePath, content);
133
+ }
134
+ catch {
135
+ // Skip files that can't be read
136
+ }
137
+ }
138
+ return contents;
139
+ }
140
+ /**
141
+ * Get a summary of scan results
142
+ */
143
+ export function getScanSummary(result) {
144
+ const lines = [
145
+ `📁 Files scanned: ${result.files.length}`,
146
+ `📦 Total size: ${(result.totalSize / 1024).toFixed(1)} KB`,
147
+ ''
148
+ ];
149
+ const categoryEmojis = {
150
+ component: '🧩',
151
+ page: '📄',
152
+ api: '🔌',
153
+ utility: '🛠️',
154
+ config: '⚙️',
155
+ test: '🧪',
156
+ style: '🎨',
157
+ type: '📝',
158
+ other: '📦'
159
+ };
160
+ for (const [category, files] of Object.entries(result.byCategory)) {
161
+ if (files.length > 0) {
162
+ const emoji = categoryEmojis[category];
163
+ lines.push(` ${emoji} ${category}: ${files.length}`);
164
+ }
165
+ }
166
+ if (result.skipped.length > 0) {
167
+ lines.push('');
168
+ lines.push(`⚠️ Skipped: ${result.skipped.length} files`);
169
+ }
170
+ return lines.join('\n');
171
+ }
172
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../../src/core/scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Security Module - Sandbox file access to repository only
3
+ * Prevents path traversal attacks and ensures isolation
4
+ */
5
+ export declare class SecurityError extends Error {
6
+ constructor(message: string);
7
+ }
8
+ /**
9
+ * Normalize and resolve a path safely
10
+ */
11
+ export declare function normalizePath(filePath: string): string;
12
+ /**
13
+ * Check if a path is within the allowed repository root
14
+ */
15
+ export declare function isWithinRepo(filePath: string, repoRoot: string): boolean;
16
+ /**
17
+ * Validate a path and throw if it's outside the repo
18
+ */
19
+ export declare function validatePath(filePath: string, repoRoot: string): string;
20
+ /**
21
+ * Check if path is a symlink pointing outside repo
22
+ */
23
+ export declare function isSymlinkEscape(filePath: string, repoRoot: string): Promise<boolean>;
24
+ /**
25
+ * Safe file read with security validation
26
+ */
27
+ export declare function safeReadFile(filePath: string, repoRoot: string, maxSizeBytes?: number): Promise<string>;
28
+ /**
29
+ * Default patterns to always ignore (security sensitive)
30
+ */
31
+ export declare const SECURITY_IGNORE_PATTERNS: string[];
32
+ /**
33
+ * Validate that a command is safe to execute
34
+ */
35
+ export declare function isAllowedCommand(command: string): boolean;
36
+ /**
37
+ * Sanitize command arguments to prevent injection
38
+ */
39
+ export declare function sanitizeArgs(args: string[]): string[];
40
+ //# sourceMappingURL=security.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.d.ts","sourceRoot":"","sources":["../../src/core/security.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,qBAAa,aAAc,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI9B;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAOxE;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAUvE;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAa1F;AAED;;GAEG;AACH,wBAAsB,YAAY,CAC9B,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,YAAY,GAAE,MAAoB,GACnC,OAAO,CAAC,MAAM,CAAC,CAmBjB;AAED;;GAEG;AACH,eAAO,MAAM,wBAAwB,UAUpC,CAAC;AAEF;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAoBzD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAKrD"}
@@ -0,0 +1,118 @@
1
+ /**
2
+ * Security Module - Sandbox file access to repository only
3
+ * Prevents path traversal attacks and ensures isolation
4
+ */
5
+ import path from 'path';
6
+ import fs from 'fs';
7
+ export class SecurityError extends Error {
8
+ constructor(message) {
9
+ super(message);
10
+ this.name = 'SecurityError';
11
+ }
12
+ }
13
+ /**
14
+ * Normalize and resolve a path safely
15
+ */
16
+ export function normalizePath(filePath) {
17
+ return path.normalize(path.resolve(filePath));
18
+ }
19
+ /**
20
+ * Check if a path is within the allowed repository root
21
+ */
22
+ export function isWithinRepo(filePath, repoRoot) {
23
+ const normalizedPath = normalizePath(filePath);
24
+ const normalizedRoot = normalizePath(repoRoot);
25
+ // Ensure the path starts with the repo root
26
+ return normalizedPath.startsWith(normalizedRoot + path.sep) ||
27
+ normalizedPath === normalizedRoot;
28
+ }
29
+ /**
30
+ * Validate a path and throw if it's outside the repo
31
+ */
32
+ export function validatePath(filePath, repoRoot) {
33
+ const normalized = normalizePath(filePath);
34
+ if (!isWithinRepo(normalized, repoRoot)) {
35
+ throw new SecurityError(`Access denied: "${filePath}" is outside the repository boundary`);
36
+ }
37
+ return normalized;
38
+ }
39
+ /**
40
+ * Check if path is a symlink pointing outside repo
41
+ */
42
+ export async function isSymlinkEscape(filePath, repoRoot) {
43
+ try {
44
+ const stats = await fs.promises.lstat(filePath);
45
+ if (stats.isSymbolicLink()) {
46
+ const realPath = await fs.promises.realpath(filePath);
47
+ return !isWithinRepo(realPath, repoRoot);
48
+ }
49
+ return false;
50
+ }
51
+ catch {
52
+ return false;
53
+ }
54
+ }
55
+ /**
56
+ * Safe file read with security validation
57
+ */
58
+ export async function safeReadFile(filePath, repoRoot, maxSizeBytes = 1024 * 1024 // 1MB default
59
+ ) {
60
+ const validated = validatePath(filePath, repoRoot);
61
+ // Check for symlink escape
62
+ if (await isSymlinkEscape(validated, repoRoot)) {
63
+ throw new SecurityError(`Access denied: "${filePath}" is a symlink pointing outside the repository`);
64
+ }
65
+ // Check file size
66
+ const stats = await fs.promises.stat(validated);
67
+ if (stats.size > maxSizeBytes) {
68
+ throw new SecurityError(`File too large: "${filePath}" (${(stats.size / 1024 / 1024).toFixed(2)}MB > ${(maxSizeBytes / 1024 / 1024).toFixed(2)}MB limit)`);
69
+ }
70
+ return fs.promises.readFile(validated, 'utf-8');
71
+ }
72
+ /**
73
+ * Default patterns to always ignore (security sensitive)
74
+ */
75
+ export const SECURITY_IGNORE_PATTERNS = [
76
+ '**/.git/**',
77
+ '**/.env',
78
+ '**/.env.*',
79
+ '**/node_modules/**',
80
+ '**/*.pem',
81
+ '**/*.key',
82
+ '**/secrets/**',
83
+ '**/.aws/**',
84
+ '**/.ssh/**',
85
+ ];
86
+ /**
87
+ * Validate that a command is safe to execute
88
+ */
89
+ export function isAllowedCommand(command) {
90
+ const allowedCommands = [
91
+ 'git',
92
+ 'npm',
93
+ 'npx',
94
+ 'node',
95
+ 'tsc',
96
+ 'eslint',
97
+ 'prettier',
98
+ 'cat',
99
+ 'head',
100
+ 'tail',
101
+ 'wc',
102
+ 'find',
103
+ 'ls',
104
+ 'dir',
105
+ ];
106
+ const baseCommand = command.trim().split(/\s+/)[0];
107
+ return allowedCommands.includes(baseCommand);
108
+ }
109
+ /**
110
+ * Sanitize command arguments to prevent injection
111
+ */
112
+ export function sanitizeArgs(args) {
113
+ return args.map(arg => {
114
+ // Remove shell metacharacters
115
+ return arg.replace(/[;&|`$(){}[\]<>]/g, '');
116
+ });
117
+ }
118
+ //# sourceMappingURL=security.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"security.js","sourceRoot":"","sources":["../../src/core/security.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * AI Reviewer CLI - Main Entry Point
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG"}
package/dist/index.js ADDED
@@ -0,0 +1,40 @@
1
+ /**
2
+ * AI Reviewer CLI - Main Entry Point
3
+ */
4
+ import { program } from 'commander';
5
+ import { scan } from './commands/scan.js';
6
+ import { config } from './commands/config.js';
7
+ // Package info
8
+ const VERSION = '0.1.0';
9
+ const NAME = 'ai-reviewer';
10
+ program
11
+ .name(NAME)
12
+ .description('🤖 AI-powered code review CLI - analyze your codebase with Gemini AI')
13
+ .version(VERSION);
14
+ // Scan command (main command)
15
+ program
16
+ .command('scan')
17
+ .description('Analyze the current repository with AI')
18
+ .option('-o, --output <file>', 'Output file path', 'AI_REVIEW_REPORT.md')
19
+ .option('-j, --json', 'Also generate JSON output')
20
+ .option('-t, --types <types>', 'Analysis types (comma-separated): overview,security,codeQuality,accessibility,uiux,testing')
21
+ .option('-v, --verbose', 'Verbose output')
22
+ .action(async (opts) => {
23
+ await scan(opts);
24
+ });
25
+ // Config command
26
+ program
27
+ .command('config')
28
+ .description('Manage AI Reviewer configuration')
29
+ .option('-a, --action <action>', 'Action: show, reset, token', 'show')
30
+ .action(async (opts) => {
31
+ await config(opts);
32
+ });
33
+ // Default command (no args = scan)
34
+ program
35
+ .action(async () => {
36
+ await scan({});
37
+ });
38
+ // Parse and run
39
+ program.parse();
40
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,IAAI,EAAoB,MAAM,oBAAoB,CAAC;AAC5D,OAAO,EAAE,MAAM,EAAsB,MAAM,sBAAsB,CAAC;AAElE,eAAe;AACf,MAAM,OAAO,GAAG,OAAO,CAAC;AACxB,MAAM,IAAI,GAAG,aAAa,CAAC;AAE3B,OAAO;KACF,IAAI,CAAC,IAAI,CAAC;KACV,WAAW,CAAC,sEAAsE,CAAC;KACnF,OAAO,CAAC,OAAO,CAAC,CAAC;AAEtB,8BAA8B;AAC9B,OAAO;KACF,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,wCAAwC,CAAC;KACrD,MAAM,CAAC,qBAAqB,EAAE,kBAAkB,EAAE,qBAAqB,CAAC;KACxE,MAAM,CAAC,YAAY,EAAE,2BAA2B,CAAC;KACjD,MAAM,CAAC,qBAAqB,EAAE,4FAA4F,CAAC;KAC3H,MAAM,CAAC,eAAe,EAAE,gBAAgB,CAAC;KACzC,MAAM,CAAC,KAAK,EAAE,IAAiB,EAAE,EAAE;IAChC,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;AACrB,CAAC,CAAC,CAAC;AAEP,iBAAiB;AACjB,OAAO;KACF,OAAO,CAAC,QAAQ,CAAC;KACjB,WAAW,CAAC,kCAAkC,CAAC;KAC/C,MAAM,CAAC,uBAAuB,EAAE,4BAA4B,EAAE,MAAM,CAAC;KACrE,MAAM,CAAC,KAAK,EAAE,IAAmB,EAAE,EAAE;IAClC,MAAM,MAAM,CAAC,IAAI,CAAC,CAAC;AACvB,CAAC,CAAC,CAAC;AAEP,mCAAmC;AACnC,OAAO;KACF,MAAM,CAAC,KAAK,IAAI,EAAE;IACf,MAAM,IAAI,CAAC,EAAE,CAAC,CAAC;AACnB,CAAC,CAAC,CAAC;AAEP,gBAAgB;AAChB,OAAO,CAAC,KAAK,EAAE,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Markdown Reporter - Generate the final report
3
+ */
4
+ import type { AgentResult } from '../ai/agent.js';
5
+ import type { FrameworkInfo } from '../core/framework-detector.js';
6
+ import type { ScanResult } from '../core/scanner.js';
7
+ export interface ReportMetadata {
8
+ framework: FrameworkInfo;
9
+ scanResult: ScanResult;
10
+ generatedAt: Date;
11
+ modelName: string;
12
+ }
13
+ /**
14
+ * Generate the full markdown report
15
+ */
16
+ export declare function generateMarkdownReport(result: AgentResult, metadata: ReportMetadata): string;
17
+ /**
18
+ * Write report to file
19
+ */
20
+ export declare function writeReport(content: string, outputPath: string): Promise<string>;
21
+ /**
22
+ * Generate JSON report
23
+ */
24
+ export declare function generateJsonReport(result: AgentResult, metadata: ReportMetadata): object;
25
+ //# sourceMappingURL=markdown.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/reporters/markdown.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,WAAW,cAAc;IAC3B,SAAS,EAAE,aAAa,CAAC;IACzB,UAAU,EAAE,UAAU,CAAC;IACvB,WAAW,EAAE,IAAI,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAClC,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,cAAc,GACzB,MAAM,CAyGR;AAED;;GAEG;AACH,wBAAsB,WAAW,CAC7B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,CAAC,CAIjB;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAC9B,MAAM,EAAE,WAAW,EACnB,QAAQ,EAAE,cAAc,GACzB,MAAM,CAmBR"}