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,33 @@
1
+ /**
2
+ * Token Manager - Secure storage for Gemini API token
3
+ * Uses 'conf' for encrypted local storage
4
+ */
5
+ /**
6
+ * Check if a valid token is stored
7
+ */
8
+ export declare function hasToken(): boolean;
9
+ /**
10
+ * Get the stored Gemini token
11
+ */
12
+ export declare function getToken(): string | undefined;
13
+ /**
14
+ * Store a new Gemini token
15
+ */
16
+ export declare function setToken(token: string): void;
17
+ /**
18
+ * Clear the stored token
19
+ */
20
+ export declare function clearToken(): void;
21
+ /**
22
+ * Validate token format (basic check)
23
+ */
24
+ export declare function isValidTokenFormat(token: string): boolean;
25
+ /**
26
+ * Interactively prompt for token if not set
27
+ */
28
+ export declare function ensureToken(): Promise<string>;
29
+ /**
30
+ * Show token configuration status
31
+ */
32
+ export declare function showTokenStatus(): void;
33
+ //# sourceMappingURL=token-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-manager.d.ts","sourceRoot":"","sources":["../../src/auth/token-manager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAoBH;;GAEG;AACH,wBAAgB,QAAQ,IAAI,OAAO,CAElC;AAED;;GAEG;AACH,wBAAgB,QAAQ,IAAI,MAAM,GAAG,SAAS,CAE7C;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAG5C;AAED;;GAEG;AACH,wBAAgB,UAAU,IAAI,IAAI,CAGjC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGzD;AAED;;GAEG;AACH,wBAAsB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CAgCnD;AAED;;GAEG;AACH,wBAAgB,eAAe,IAAI,IAAI,CAWtC"}
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Token Manager - Secure storage for Gemini API token
3
+ * Uses 'conf' for encrypted local storage
4
+ */
5
+ import Conf from 'conf';
6
+ import inquirer from 'inquirer';
7
+ import chalk from 'chalk';
8
+ const config = new Conf({
9
+ projectName: 'ai-reviewer',
10
+ encryptionKey: 'ai-reviewer-secure-storage-v1',
11
+ schema: {
12
+ geminiToken: { type: 'string' },
13
+ configuredAt: { type: 'string' }
14
+ }
15
+ });
16
+ /**
17
+ * Check if a valid token is stored
18
+ */
19
+ export function hasToken() {
20
+ return !!config.get('geminiToken');
21
+ }
22
+ /**
23
+ * Get the stored Gemini token
24
+ */
25
+ export function getToken() {
26
+ return config.get('geminiToken');
27
+ }
28
+ /**
29
+ * Store a new Gemini token
30
+ */
31
+ export function setToken(token) {
32
+ config.set('geminiToken', token);
33
+ config.set('configuredAt', new Date().toISOString());
34
+ }
35
+ /**
36
+ * Clear the stored token
37
+ */
38
+ export function clearToken() {
39
+ config.delete('geminiToken');
40
+ config.delete('configuredAt');
41
+ }
42
+ /**
43
+ * Validate token format (basic check)
44
+ */
45
+ export function isValidTokenFormat(token) {
46
+ // Gemini API keys are typically 39 characters
47
+ return token.length >= 30 && token.length <= 50 && /^[A-Za-z0-9_-]+$/.test(token);
48
+ }
49
+ /**
50
+ * Interactively prompt for token if not set
51
+ */
52
+ export async function ensureToken() {
53
+ const existing = getToken();
54
+ if (existing) {
55
+ return existing;
56
+ }
57
+ console.log(chalk.yellow('\n🔑 Gemini API token not found.\n'));
58
+ console.log(chalk.dim('Get your API key from: https://aistudio.google.com/apikey\n'));
59
+ const { token } = await inquirer.prompt([
60
+ {
61
+ type: 'password',
62
+ name: 'token',
63
+ message: 'Enter your Gemini API token:',
64
+ mask: '*',
65
+ validate: (input) => {
66
+ if (!input.trim()) {
67
+ return 'Token is required';
68
+ }
69
+ if (!isValidTokenFormat(input.trim())) {
70
+ return 'Invalid token format. Should be 30-50 alphanumeric characters.';
71
+ }
72
+ return true;
73
+ }
74
+ }
75
+ ]);
76
+ const trimmedToken = token.trim();
77
+ setToken(trimmedToken);
78
+ console.log(chalk.green('✓ Token saved securely.\n'));
79
+ return trimmedToken;
80
+ }
81
+ /**
82
+ * Show token configuration status
83
+ */
84
+ export function showTokenStatus() {
85
+ if (hasToken()) {
86
+ const configuredAt = config.get('configuredAt');
87
+ console.log(chalk.green('✓ Gemini token is configured'));
88
+ if (configuredAt) {
89
+ console.log(chalk.dim(` Configured: ${new Date(configuredAt).toLocaleString()}`));
90
+ }
91
+ }
92
+ else {
93
+ console.log(chalk.yellow('⚠ Gemini token is not configured'));
94
+ console.log(chalk.dim(' Run "ai-reviewer scan" to configure'));
95
+ }
96
+ }
97
+ //# sourceMappingURL=token-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-manager.js","sourceRoot":"","sources":["../../src/auth/token-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Config Command - Manage AI Reviewer configuration
3
+ */
4
+ export type ConfigAction = 'show' | 'reset' | 'token';
5
+ export interface ConfigOptions {
6
+ action?: ConfigAction;
7
+ }
8
+ /**
9
+ * Execute the config command
10
+ */
11
+ export declare function config(options?: ConfigOptions): Promise<void>;
12
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAEtD,MAAM,WAAW,aAAa;IAC1B,MAAM,CAAC,EAAE,YAAY,CAAC;CACzB;AAED;;GAEG;AACH,wBAAsB,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBvE"}
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Config Command - Manage AI Reviewer configuration
3
+ */
4
+ import * as logger from '../utils/logger.js';
5
+ import { hasToken, showTokenStatus, clearToken, ensureToken } from '../auth/token-manager.js';
6
+ import inquirer from 'inquirer';
7
+ /**
8
+ * Execute the config command
9
+ */
10
+ export async function config(options = {}) {
11
+ const action = options.action || 'show';
12
+ switch (action) {
13
+ case 'show':
14
+ await showConfig();
15
+ break;
16
+ case 'reset':
17
+ await resetConfig();
18
+ break;
19
+ case 'token':
20
+ await configureToken();
21
+ break;
22
+ default:
23
+ logger.error(`Unknown action: ${action}`);
24
+ logger.info('Available actions: show, reset, token');
25
+ }
26
+ }
27
+ /**
28
+ * Show current configuration
29
+ */
30
+ async function showConfig() {
31
+ logger.header('AI Reviewer Configuration');
32
+ showTokenStatus();
33
+ console.log();
34
+ logger.info('Available commands:');
35
+ console.log(' ai-reviewer config --action token - Update API token');
36
+ console.log(' ai-reviewer config --action reset - Clear all settings');
37
+ }
38
+ /**
39
+ * Reset all configuration
40
+ */
41
+ async function resetConfig() {
42
+ if (!hasToken()) {
43
+ logger.info('No configuration to reset.');
44
+ return;
45
+ }
46
+ const { confirm } = await inquirer.prompt([
47
+ {
48
+ type: 'confirm',
49
+ name: 'confirm',
50
+ message: 'Are you sure you want to clear all settings including your API token?',
51
+ default: false
52
+ }
53
+ ]);
54
+ if (confirm) {
55
+ clearToken();
56
+ logger.success('Configuration reset successfully.');
57
+ }
58
+ else {
59
+ logger.info('Reset cancelled.');
60
+ }
61
+ }
62
+ /**
63
+ * Configure or update the API token
64
+ */
65
+ async function configureToken() {
66
+ if (hasToken()) {
67
+ const { override } = await inquirer.prompt([
68
+ {
69
+ type: 'confirm',
70
+ name: 'override',
71
+ message: 'A token is already configured. Do you want to replace it?',
72
+ default: false
73
+ }
74
+ ]);
75
+ if (!override) {
76
+ logger.info('Token update cancelled.');
77
+ return;
78
+ }
79
+ clearToken();
80
+ }
81
+ await ensureToken();
82
+ logger.success('Token configured successfully.');
83
+ }
84
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,MAAM,MAAM,oBAAoB,CAAC;AAC7C,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAC9F,OAAO,QAAQ,MAAM,UAAU,CAAC;AAQhC;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,UAAyB,EAAE;IACpD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,MAAM,CAAC;IAExC,QAAQ,MAAM,EAAE,CAAC;QACb,KAAK,MAAM;YACP,MAAM,UAAU,EAAE,CAAC;YACnB,MAAM;QACV,KAAK,OAAO;YACR,MAAM,WAAW,EAAE,CAAC;YACpB,MAAM;QACV,KAAK,OAAO;YACR,MAAM,cAAc,EAAE,CAAC;YACvB,MAAM;QACV;YACI,MAAM,CAAC,KAAK,CAAC,mBAAmB,MAAM,EAAE,CAAC,CAAC;YAC1C,MAAM,CAAC,IAAI,CAAC,uCAAuC,CAAC,CAAC;IAC7D,CAAC;AACL,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,UAAU;IACrB,MAAM,CAAC,MAAM,CAAC,2BAA2B,CAAC,CAAC;IAE3C,eAAe,EAAE,CAAC;IAElB,OAAO,CAAC,GAAG,EAAE,CAAC;IACd,MAAM,CAAC,IAAI,CAAC,qBAAqB,CAAC,CAAC;IACnC,OAAO,CAAC,GAAG,CAAC,yDAAyD,CAAC,CAAC;IACvE,OAAO,CAAC,GAAG,CAAC,2DAA2D,CAAC,CAAC;AAC7E,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,WAAW;IACtB,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;QACd,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAC1C,OAAO;IACX,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAuB;QAC5D;YACI,IAAI,EAAE,SAAS;YACf,IAAI,EAAE,SAAS;YACf,OAAO,EAAE,uEAAuE;YAChF,OAAO,EAAE,KAAK;SACjB;KACJ,CAAC,CAAC;IAEH,IAAI,OAAO,EAAE,CAAC;QACV,UAAU,EAAE,CAAC;QACb,MAAM,CAAC,OAAO,CAAC,mCAAmC,CAAC,CAAC;IACxD,CAAC;SAAM,CAAC;QACJ,MAAM,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACpC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,cAAc;IACzB,IAAI,QAAQ,EAAE,EAAE,CAAC;QACb,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAwB;YAC9D;gBACI,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,UAAU;gBAChB,OAAO,EAAE,2DAA2D;gBACpE,OAAO,EAAE,KAAK;aACjB;SACJ,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,EAAE,CAAC;YACZ,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;YACvC,OAAO;QACX,CAAC;QAED,UAAU,EAAE,CAAC;IACjB,CAAC;IAED,MAAM,WAAW,EAAE,CAAC;IACpB,MAAM,CAAC,OAAO,CAAC,gCAAgC,CAAC,CAAC;AACrD,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Scan Command - Main analysis command
3
+ */
4
+ export interface ScanOptions {
5
+ output?: string;
6
+ json?: boolean;
7
+ types?: string;
8
+ verbose?: boolean;
9
+ }
10
+ /**
11
+ * Execute the scan command
12
+ */
13
+ export declare function scan(options?: ScanOptions): Promise<void>;
14
+ //# sourceMappingURL=scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.d.ts","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"AAAA;;GAEG;AAaH,MAAM,WAAW,WAAW;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;GAEG;AACH,wBAAsB,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwHnE"}
@@ -0,0 +1,110 @@
1
+ /**
2
+ * Scan Command - Main analysis command
3
+ */
4
+ import path from 'path';
5
+ import * as logger from '../utils/logger.js';
6
+ import { ensureToken } from '../auth/token-manager.js';
7
+ import { detectFramework, getFrameworkHints } from '../core/framework-detector.js';
8
+ import { scanRepository, getScanSummary } from '../core/scanner.js';
9
+ import { createGeminiClient } from '../ai/gemini-client.js';
10
+ import { createAgent } from '../ai/agent.js';
11
+ import { generateMarkdownReport, writeReport, generateJsonReport } from '../reporters/markdown.js';
12
+ import fs from 'fs';
13
+ /**
14
+ * Execute the scan command
15
+ */
16
+ export async function scan(options = {}) {
17
+ const repoRoot = process.cwd();
18
+ logger.banner();
19
+ // Ensure we have a token
20
+ const spin = logger.spinner('Checking Gemini API token...');
21
+ spin.start();
22
+ try {
23
+ const token = await ensureToken();
24
+ spin.succeed('Gemini API token ready');
25
+ // Validate token with a quick check
26
+ spin.start('Validating API access...');
27
+ const client = createGeminiClient(token);
28
+ const isValid = await client.validateKey();
29
+ if (!isValid) {
30
+ spin.fail('Invalid Gemini API token');
31
+ logger.error('Please check your token and try again.');
32
+ logger.info('Get a new key at: https://aistudio.google.com/apikey');
33
+ process.exit(1);
34
+ }
35
+ spin.succeed('API access validated');
36
+ // Detect framework
37
+ spin.start('Detecting project framework...');
38
+ const framework = await detectFramework(repoRoot);
39
+ spin.succeed(`Detected: ${framework.displayName}`);
40
+ if (options.verbose) {
41
+ logger.info(`Framework hints: ${getFrameworkHints(framework.name)}`);
42
+ }
43
+ // Scan repository
44
+ spin.start('Scanning repository...');
45
+ const scanResult = await scanRepository(repoRoot, framework);
46
+ spin.succeed(`Found ${scanResult.files.length} files`);
47
+ if (options.verbose) {
48
+ console.log();
49
+ console.log(getScanSummary(scanResult));
50
+ }
51
+ if (scanResult.files.length === 0) {
52
+ logger.warn('No files found to analyze. Check your project structure.');
53
+ process.exit(0);
54
+ }
55
+ // Parse analysis types
56
+ const analysisTypes = options.types
57
+ ? options.types.split(',')
58
+ : ['overview', 'security', 'codeQuality', 'accessibility'];
59
+ // Run AI analysis
60
+ logger.header('Running AI Analysis');
61
+ logger.info(`Analysis types: ${analysisTypes.join(', ')}`);
62
+ console.log();
63
+ spin.start('Analyzing code with Gemini AI...');
64
+ const agent = createAgent(client, {
65
+ repoRoot,
66
+ framework,
67
+ analysisTypes
68
+ });
69
+ const result = await agent.analyze(scanResult);
70
+ spin.succeed(`Analysis complete (${(result.duration / 1000).toFixed(1)}s)`);
71
+ // Generate report
72
+ const outputFile = options.output || 'AI_REVIEW_REPORT.md';
73
+ const metadata = {
74
+ framework,
75
+ scanResult,
76
+ generatedAt: new Date(),
77
+ modelName: client.getModelName()
78
+ };
79
+ if (options.json) {
80
+ const jsonReport = generateJsonReport(result, metadata);
81
+ const jsonPath = outputFile.replace('.md', '.json');
82
+ await fs.promises.writeFile(path.resolve(jsonPath), JSON.stringify(jsonReport, null, 2), 'utf-8');
83
+ logger.success(`JSON report generated: ${jsonPath}`);
84
+ }
85
+ const markdownReport = generateMarkdownReport(result, metadata);
86
+ const reportPath = await writeReport(markdownReport, outputFile);
87
+ logger.success(`Report generated: ${outputFile}`);
88
+ // Summary
89
+ console.log();
90
+ logger.divider();
91
+ logger.stats({
92
+ 'Files Analyzed': scanResult.files.length,
93
+ 'Tokens Used': result.totalTokens.toLocaleString(),
94
+ 'Duration': `${(result.duration / 1000).toFixed(1)}s`,
95
+ 'Report': reportPath
96
+ });
97
+ logger.divider();
98
+ console.log();
99
+ logger.success('Analysis complete! 🎉');
100
+ }
101
+ catch (error) {
102
+ spin.fail('Analysis failed');
103
+ logger.error(error instanceof Error ? error.message : 'Unknown error');
104
+ if (options.verbose && error instanceof Error) {
105
+ console.error(error.stack);
106
+ }
107
+ process.exit(1);
108
+ }
109
+ }
110
+ //# sourceMappingURL=scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scan.js","sourceRoot":"","sources":["../../src/commands/scan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Dynamic Command Executor - Run safe commands for context gathering
3
+ */
4
+ export interface CommandResult {
5
+ success: boolean;
6
+ stdout: string;
7
+ stderr: string;
8
+ exitCode: number | null;
9
+ command: string;
10
+ }
11
+ export declare class ExecutorError extends Error {
12
+ constructor(message: string);
13
+ }
14
+ /**
15
+ * Execute a command safely within the repository
16
+ */
17
+ export declare function executeCommand(command: string, args: string[], cwd: string, options?: {
18
+ timeout?: number;
19
+ maxOutput?: number;
20
+ }): Promise<CommandResult>;
21
+ /**
22
+ * Gather repository context using safe commands
23
+ */
24
+ export declare function gatherRepoContext(repoRoot: string): Promise<Record<string, string>>;
25
+ /**
26
+ * Run type checking and gather errors
27
+ */
28
+ export declare function runTypeCheck(repoRoot: string): Promise<string[]>;
29
+ /**
30
+ * Run ESLint if available
31
+ */
32
+ export declare function runLint(repoRoot: string): Promise<string[]>;
33
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/core/executor.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,WAAW,aAAa;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,aAAc,SAAQ,KAAK;gBACxB,OAAO,EAAE,MAAM;CAI9B;AAED;;GAEG;AACH,wBAAsB,cAAc,CAChC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;IACL,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;CACjB,GACP,OAAO,CAAC,aAAa,CAAC,CAmExB;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAqCzF;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAoBtE;AAED;;GAEG;AACH,wBAAsB,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAmBjE"}
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Dynamic Command Executor - Run safe commands for context gathering
3
+ */
4
+ import { spawn } from 'child_process';
5
+ import { isAllowedCommand, sanitizeArgs } from './security.js';
6
+ export class ExecutorError extends Error {
7
+ constructor(message) {
8
+ super(message);
9
+ this.name = 'ExecutorError';
10
+ }
11
+ }
12
+ /**
13
+ * Execute a command safely within the repository
14
+ */
15
+ export async function executeCommand(command, args, cwd, options = {}) {
16
+ const { timeout = 30000, maxOutput = 100000 } = options;
17
+ // Validate command is allowed
18
+ if (!isAllowedCommand(command)) {
19
+ throw new ExecutorError(`Command "${command}" is not in the allowed list`);
20
+ }
21
+ // Sanitize arguments
22
+ const sanitizedArgs = sanitizeArgs(args);
23
+ return new Promise((resolve) => {
24
+ let stdout = '';
25
+ let stderr = '';
26
+ let timedOut = false;
27
+ const proc = spawn(command, sanitizedArgs, {
28
+ cwd,
29
+ shell: true,
30
+ timeout,
31
+ env: {
32
+ ...process.env,
33
+ // Force non-interactive mode
34
+ CI: 'true',
35
+ FORCE_COLOR: '0'
36
+ }
37
+ });
38
+ const timeoutId = setTimeout(() => {
39
+ timedOut = true;
40
+ proc.kill('SIGTERM');
41
+ }, timeout);
42
+ proc.stdout?.on('data', (data) => {
43
+ if (stdout.length < maxOutput) {
44
+ stdout += data.toString();
45
+ }
46
+ });
47
+ proc.stderr?.on('data', (data) => {
48
+ if (stderr.length < maxOutput) {
49
+ stderr += data.toString();
50
+ }
51
+ });
52
+ proc.on('close', (code) => {
53
+ clearTimeout(timeoutId);
54
+ resolve({
55
+ success: code === 0 && !timedOut,
56
+ stdout: stdout.slice(0, maxOutput),
57
+ stderr: stderr.slice(0, maxOutput),
58
+ exitCode: timedOut ? null : code,
59
+ command: `${command} ${sanitizedArgs.join(' ')}`
60
+ });
61
+ });
62
+ proc.on('error', (error) => {
63
+ clearTimeout(timeoutId);
64
+ resolve({
65
+ success: false,
66
+ stdout: '',
67
+ stderr: error.message,
68
+ exitCode: null,
69
+ command: `${command} ${sanitizedArgs.join(' ')}`
70
+ });
71
+ });
72
+ });
73
+ }
74
+ /**
75
+ * Gather repository context using safe commands
76
+ */
77
+ export async function gatherRepoContext(repoRoot) {
78
+ const context = {};
79
+ // Get git info
80
+ const gitStatus = await executeCommand('git', ['status', '--short'], repoRoot);
81
+ if (gitStatus.success) {
82
+ context['git_status'] = gitStatus.stdout || 'Clean working tree';
83
+ }
84
+ const gitLog = await executeCommand('git', ['log', '--oneline', '-5'], repoRoot);
85
+ if (gitLog.success) {
86
+ context['recent_commits'] = gitLog.stdout;
87
+ }
88
+ const gitBranch = await executeCommand('git', ['branch', '--show-current'], repoRoot);
89
+ if (gitBranch.success) {
90
+ context['current_branch'] = gitBranch.stdout.trim();
91
+ }
92
+ // Get npm info
93
+ const npmList = await executeCommand('npm', ['list', '--depth=0', '--json'], repoRoot);
94
+ if (npmList.success) {
95
+ try {
96
+ const deps = JSON.parse(npmList.stdout);
97
+ context['dependencies'] = Object.keys(deps.dependencies || {}).join(', ');
98
+ }
99
+ catch {
100
+ // Ignore parse errors
101
+ }
102
+ }
103
+ // Check for TypeScript
104
+ const tscVersion = await executeCommand('npx', ['tsc', '--version'], repoRoot);
105
+ if (tscVersion.success) {
106
+ context['typescript_version'] = tscVersion.stdout.trim();
107
+ }
108
+ return context;
109
+ }
110
+ /**
111
+ * Run type checking and gather errors
112
+ */
113
+ export async function runTypeCheck(repoRoot) {
114
+ const result = await executeCommand('npx', ['tsc', '--noEmit', '--pretty', 'false'], repoRoot, {
115
+ timeout: 60000
116
+ });
117
+ if (result.success) {
118
+ return [];
119
+ }
120
+ // Parse TypeScript errors
121
+ const errors = [];
122
+ const lines = result.stdout.split('\n');
123
+ for (const line of lines) {
124
+ if (line.includes('error TS')) {
125
+ errors.push(line.trim());
126
+ }
127
+ }
128
+ return errors.slice(0, 20); // Limit to 20 errors
129
+ }
130
+ /**
131
+ * Run ESLint if available
132
+ */
133
+ export async function runLint(repoRoot) {
134
+ const result = await executeCommand('npx', ['eslint', '.', '--format', 'compact', '--max-warnings', '50'], repoRoot, {
135
+ timeout: 60000
136
+ });
137
+ if (result.success) {
138
+ return [];
139
+ }
140
+ const issues = [];
141
+ const lines = result.stdout.split('\n');
142
+ for (const line of lines) {
143
+ if (line.includes('Warning') || line.includes('Error')) {
144
+ issues.push(line.trim());
145
+ }
146
+ }
147
+ return issues.slice(0, 20);
148
+ }
149
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/core/executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Framework Detector - Auto-detect project type
3
+ */
4
+ export type Framework = 'nextjs' | 'react' | 'vite' | 'angular' | 'vue' | 'svelte' | 'django' | 'flask' | 'express' | 'nestjs' | 'unknown';
5
+ export interface FrameworkInfo {
6
+ name: Framework;
7
+ displayName: string;
8
+ scanPatterns: string[];
9
+ ignorePatterns: string[];
10
+ description: string;
11
+ }
12
+ /**
13
+ * Detect the framework used in a project
14
+ */
15
+ export declare function detectFramework(repoRoot: string): Promise<FrameworkInfo>;
16
+ /**
17
+ * Get framework-specific analysis hints
18
+ */
19
+ export declare function getFrameworkHints(framework: Framework): string;
20
+ //# sourceMappingURL=framework-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"framework-detector.d.ts","sourceRoot":"","sources":["../../src/core/framework-detector.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,MAAM,SAAS,GACf,QAAQ,GACR,OAAO,GACP,MAAM,GACN,SAAS,GACT,KAAK,GACL,QAAQ,GACR,QAAQ,GACR,OAAO,GACP,SAAS,GACT,QAAQ,GACR,SAAS,CAAC;AAEhB,MAAM,WAAW,aAAa;IAC1B,IAAI,EAAE,SAAS,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,WAAW,EAAE,MAAM,CAAC;CACvB;AAuED;;GAEG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAkE9E;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAgB9D"}