@npm7381/agent-code-review 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 (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +75 -0
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +316 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/src/aiClient.d.ts +38 -0
  8. package/dist/src/aiClient.d.ts.map +1 -0
  9. package/dist/src/aiClient.js +180 -0
  10. package/dist/src/aiClient.js.map +1 -0
  11. package/dist/src/cache.d.ts +7 -0
  12. package/dist/src/cache.d.ts.map +1 -0
  13. package/dist/src/cache.js +50 -0
  14. package/dist/src/cache.js.map +1 -0
  15. package/dist/src/configLoader.d.ts +14 -0
  16. package/dist/src/configLoader.d.ts.map +1 -0
  17. package/dist/src/configLoader.js +26 -0
  18. package/dist/src/configLoader.js.map +1 -0
  19. package/dist/src/fileProcessor.d.ts +5 -0
  20. package/dist/src/fileProcessor.d.ts.map +1 -0
  21. package/dist/src/fileProcessor.js +78 -0
  22. package/dist/src/fileProcessor.js.map +1 -0
  23. package/dist/src/htmlFormatter.d.ts +12 -0
  24. package/dist/src/htmlFormatter.d.ts.map +1 -0
  25. package/dist/src/htmlFormatter.js +97 -0
  26. package/dist/src/htmlFormatter.js.map +1 -0
  27. package/dist/src/pdfFormatter.d.ts +11 -0
  28. package/dist/src/pdfFormatter.d.ts.map +1 -0
  29. package/dist/src/pdfFormatter.js +46 -0
  30. package/dist/src/pdfFormatter.js.map +1 -0
  31. package/dist/src/prompts.d.ts +3 -0
  32. package/dist/src/prompts.d.ts.map +1 -0
  33. package/dist/src/prompts.js +134 -0
  34. package/dist/src/prompts.js.map +1 -0
  35. package/dist/src/providerDetector.d.ts +20 -0
  36. package/dist/src/providerDetector.d.ts.map +1 -0
  37. package/dist/src/providerDetector.js +145 -0
  38. package/dist/src/providerDetector.js.map +1 -0
  39. package/dist/src/reviewGenerator.d.ts +8 -0
  40. package/dist/src/reviewGenerator.d.ts.map +1 -0
  41. package/dist/src/reviewGenerator.js +80 -0
  42. package/dist/src/reviewGenerator.js.map +1 -0
  43. package/dist/src/types.d.ts +34 -0
  44. package/dist/src/types.d.ts.map +1 -0
  45. package/dist/src/types.js +2 -0
  46. package/dist/src/types.js.map +1 -0
  47. package/package.json +45 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Marcelo Adán
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,75 @@
1
+ # agent-code-review
2
+
3
+ Analiza calidad del código y sugiere mejoras usando IA.
4
+
5
+ ## Instalación
6
+
7
+ ```bash
8
+ # Global
9
+ npm install -g agent-code-review
10
+
11
+ # O sin instalar
12
+ npx agent-code-review --path ./src
13
+ ```
14
+
15
+ ## Uso
16
+
17
+ ```bash
18
+ agent-code-review --path ./src # review de todo src/
19
+ agent-code-review --path ./src/utils.ts # un solo archivo
20
+ agent-code-review --path ./src --severity warning # solo warning y critical
21
+ agent-code-review --path ./src --extensions .ts,.prisma # solo archivos .ts y .prisma
22
+ agent-code-review --path ./src --format html # salida HTML
23
+ agent-code-review --path ./src --dry-run # preview sin escribir
24
+ agent-code-review --path ./src --verbose # logs detallados
25
+ ```
26
+
27
+ ## Proveedores
28
+
29
+ | Provider | Modelo Default | Auth | Notas |
30
+ |----------|---------------|------|-------|
31
+ | gemini | `gemini-2.5-flash` | `GEMINI_API_KEY` | Free tier disponible |
32
+ | openai | `gpt-4o` | `OPENAI_API_KEY` | GPT-4o, GPT-4o-mini |
33
+ | anthropic | `claude-sonnet-4-20250514` | `ANTHROPIC_API_KEY` | Claude |
34
+ | deepseek | `deepseek-chat` | `DEEPSEEK_API_KEY` | El más barato |
35
+ | ollama | modelo instalado | Sin key | Local, gratis, privacidad |
36
+
37
+ **Auto-detección**: Si no especificas `--provider`, detecta automáticamente qué tienes configurado (keys en `.env` o Ollama corriendo).
38
+
39
+ ## Flags
40
+
41
+ | Flag | Descripción | Default |
42
+ |------|-------------|---------|
43
+ | `--path` | Archivo o carpeta a procesar | (requerido) |
44
+ | `--provider` | `gemini` \| `openai` \| `anthropic` \| `deepseek` \| `ollama` | auto-detectado |
45
+ | `--model` | Modelo a usar | según provider |
46
+ | `--base-url` | URL del servidor (Ollama) | `http://localhost:11434` |
47
+ | `--api-key` | API key (opcional para Ollama) | .env |
48
+ | `--max-chars` | Límite de chars por archivo | 15000 |
49
+ | `--output` | Carpeta/archivo de salida | junto al archivo |
50
+ | `--extensions` | Extensiones a procesar (CSV: `.ts,.prisma`) | todas |
51
+ | `--format` | Formato de salida `terminal` \| `markdown` \| `html` \| `pdf` | terminal |
52
+ | `--severity` | Severidad mínima: `info` \| `warning` \| `critical` | info |
53
+ | `--dry-run` | Solo preview, no escribir | false |
54
+ | `--verbose` | Logs detallados | false |
55
+
56
+ ## Features
57
+
58
+ - **Review por severidad**: critical, warning, info
59
+ - **Salida terminal** con iconos y colores por severidad
60
+ - **Cache**: hash MD5 para no regenerar archivos sin cambios
61
+ - **Auto-detección**: detecta provider disponible al iniciar
62
+ - **Resiliencia**: 3 reintentos con backoff ante errores de API
63
+ - **Truncado**: archivos > `--max-chars` se recortan con aviso
64
+ - **Filtro por extensión**: `--extensions .ts,.prisma` para limitar tipos de archivo
65
+
66
+ ## Requisitos
67
+
68
+ - Node.js >= 18
69
+ - Un proveedor de IA configurado (API key o Ollama local)
70
+
71
+ ## Licencia
72
+
73
+ MIT
74
+
75
+ Parte de [AI Agent Toolkit](https://github.com/MarceloAdan73/ai-agent-toolkit).
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,316 @@
1
+ #!/usr/bin/env node
2
+ import { Command } from 'commander';
3
+ import dotenv from 'dotenv';
4
+ import fs from 'fs';
5
+ import path from 'path';
6
+ import { fileURLToPath } from 'url';
7
+ import ora from 'ora';
8
+ import { collectFiles, readFile, shouldSkipContent } from './src/fileProcessor.js';
9
+ import { createAIClient, generateReview, parseReviewResults } from './src/reviewGenerator.js';
10
+ import { loadCache, saveCache, computeFileHash, isFileCached, updateCache } from './src/cache.js';
11
+ import { detectProvider, loadConfig, saveConfig, printDetectionResult } from './src/providerDetector.js';
12
+ import { loadConfigFile, mergeConfig } from './src/configLoader.js';
13
+ import { generateHtmlReport } from './src/htmlFormatter.js';
14
+ import { generatePdfReport } from './src/pdfFormatter.js';
15
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
16
+ dotenv.config({ path: path.join(__dirname, '.env') });
17
+ const program = new Command();
18
+ program
19
+ .name('agent-code-review')
20
+ .description('AI-powered code review tool')
21
+ .version('1.0.0')
22
+ .requiredOption('--path <path>', 'Path to file or directory to review')
23
+ .option('--model <model>', 'AI model to use (auto-detected if not set)')
24
+ .option('--provider <provider>', 'AI provider: gemini | openai | anthropic | deepseek | ollama')
25
+ .option('--base-url <url>', 'Base URL for Ollama provider')
26
+ .option('--api-key <key>', 'API key (optional for Ollama)')
27
+ .option('--max-chars <n>', 'Maximum characters per file (default: 15000)', (val) => parseInt(val, 10))
28
+ .option('--output <file>', 'Output file for review report (default: terminal)')
29
+ .option('--format <format>', 'Output format: terminal | markdown | html | pdf', 'terminal')
30
+ .option('--dry-run', 'Preview what would be generated without writing files')
31
+ .option('--extensions <extensions>', 'File extensions to process (comma-separated, e.g. .ts,.prisma)')
32
+ .option('--verbose', 'Show detailed logs')
33
+ .parse(process.argv);
34
+ const options = program.opts();
35
+ const rcConfig = loadConfigFile(process.cwd());
36
+ async function resolveProvider() {
37
+ if (options.provider) {
38
+ return {
39
+ provider: options.provider,
40
+ model: options.model ?? getDefaultModelForProvider(options.provider),
41
+ apiKey: options.apiKey,
42
+ baseUrl: options.baseUrl,
43
+ };
44
+ }
45
+ if (rcConfig?.provider) {
46
+ return {
47
+ provider: rcConfig.provider,
48
+ model: options.model ?? rcConfig.model ?? getDefaultModelForProvider(rcConfig.provider),
49
+ baseUrl: options.baseUrl ?? rcConfig.baseUrl,
50
+ };
51
+ }
52
+ const projectRoot = process.cwd();
53
+ const savedConfig = loadConfig(projectRoot);
54
+ if (savedConfig) {
55
+ return {
56
+ provider: savedConfig.provider,
57
+ model: options.model ?? savedConfig.model,
58
+ baseUrl: savedConfig.baseUrl,
59
+ };
60
+ }
61
+ const detected = await detectProvider({ projectRoot });
62
+ if (detected) {
63
+ saveConfig(projectRoot, detected);
64
+ return {
65
+ provider: detected.provider,
66
+ model: options.model ?? detected.model,
67
+ baseUrl: detected.baseUrl,
68
+ };
69
+ }
70
+ return { provider: 'gemini', model: options.model ?? 'gemini-2.5-flash' };
71
+ }
72
+ function getDefaultModelForProvider(provider) {
73
+ const defaults = {
74
+ gemini: 'gemini-2.5-flash',
75
+ openai: 'gpt-4o',
76
+ anthropic: 'claude-sonnet-4-20250514',
77
+ deepseek: 'deepseek-chat',
78
+ ollama: 'llama3',
79
+ };
80
+ return defaults[provider] ?? 'gemini-2.5-flash';
81
+ }
82
+ function getApiKeyForProvider(provider) {
83
+ const envKeyMap = {
84
+ gemini: 'GEMINI_API_KEY',
85
+ openai: 'OPENAI_API_KEY',
86
+ anthropic: 'ANTHROPIC_API_KEY',
87
+ deepseek: 'DEEPSEEK_API_KEY',
88
+ };
89
+ const envKey = envKeyMap[provider];
90
+ return envKey ? process.env[envKey] : undefined;
91
+ }
92
+ function printTerminalReport(entries) {
93
+ const allResults = entries.flatMap(e => e.results);
94
+ const critical = allResults.filter(r => r.severity === 'critical');
95
+ const warnings = allResults.filter(r => r.severity === 'warning');
96
+ const info = allResults.filter(r => r.severity === 'info');
97
+ console.log('\n=== Code Review Report ===\n');
98
+ console.log(` Files reviewed: ${entries.length}`);
99
+ console.log(` 🔴 Critical: ${critical.length}`);
100
+ console.log(` 🟡 Warning: ${warnings.length}`);
101
+ console.log(` 🟢 Info: ${info.length}`);
102
+ console.log('');
103
+ for (const entry of entries) {
104
+ if (entry.results.length === 0)
105
+ continue;
106
+ console.log(`--- ${entry.relativePath} ---`);
107
+ for (const result of entry.results) {
108
+ const severityIcon = result.severity === 'critical' ? '🔴' : result.severity === 'warning' ? '🟡' : '🟢';
109
+ const lineInfo = result.line ? `:${result.line}` : '';
110
+ console.log(` ${severityIcon} [${result.category}]${lineInfo} ${result.suggestion}`);
111
+ }
112
+ console.log('');
113
+ }
114
+ }
115
+ function generateMarkdownReport(entries) {
116
+ const allResults = entries.flatMap(e => e.results);
117
+ const critical = allResults.filter(r => r.severity === 'critical');
118
+ const warnings = allResults.filter(r => r.severity === 'warning');
119
+ const info = allResults.filter(r => r.severity === 'info');
120
+ const lines = [
121
+ '# Code Review Report',
122
+ '',
123
+ `Generated: ${new Date().toLocaleDateString('es-AR')}`,
124
+ '',
125
+ '## Summary',
126
+ '',
127
+ `- **Files reviewed:** ${entries.length}`,
128
+ `- **🔴 Critical:** ${critical.length}`,
129
+ `- **🟡 Warning:** ${warnings.length}`,
130
+ `- **🟢 Info:** ${info.length}`,
131
+ '',
132
+ '---',
133
+ '',
134
+ ];
135
+ for (const entry of entries) {
136
+ if (entry.results.length === 0)
137
+ continue;
138
+ lines.push(`## ${entry.relativePath}`, '');
139
+ for (const result of entry.results) {
140
+ const severityIcon = result.severity === 'critical' ? '🔴' : result.severity === 'warning' ? '🟡' : '🟢';
141
+ const lineInfo = result.line ? `:${result.line}` : '';
142
+ lines.push(`- ${severityIcon} **[${result.category}]**${lineInfo} ${result.suggestion}`);
143
+ }
144
+ lines.push('');
145
+ }
146
+ return lines.join('\n');
147
+ }
148
+ async function main() {
149
+ const verbose = mergeConfig(options.verbose, rcConfig?.verbose, false);
150
+ const dryRun = mergeConfig(options.dryRun, rcConfig?.dryRun, false);
151
+ const maxChars = mergeConfig(options.maxChars, rcConfig?.maxChars, 15000);
152
+ console.log('=== Agent Code Review v1.0.0 ===\n');
153
+ if (dryRun) {
154
+ console.log('[DRY-RUN] Modo preview activo - no se escribirán archivos\n');
155
+ }
156
+ const scanSpinner = ora('🔍 Resolviendo provider...').start();
157
+ const resolved = await resolveProvider();
158
+ const apiKey = options.apiKey || getApiKeyForProvider(resolved.provider);
159
+ scanSpinner.succeed(`Provider: ${resolved.provider} | Model: ${resolved.model}`);
160
+ const ai = createAIClient({
161
+ provider: resolved.provider,
162
+ apiKey,
163
+ baseUrl: resolved.baseUrl,
164
+ model: resolved.model,
165
+ verbose,
166
+ });
167
+ if (!ai) {
168
+ printDetectionResult(null, verbose);
169
+ process.exit(1);
170
+ }
171
+ if (verbose) {
172
+ console.log(`[INFO] Provider: ${resolved.provider}`);
173
+ console.log(`[INFO] Modelo: ${resolved.model}`);
174
+ console.log(`[INFO] Max chars: ${maxChars}`);
175
+ }
176
+ const extensions = options.extensions
177
+ ? options.extensions.split(',').map((e) => e.trim())
178
+ : rcConfig?.extensions;
179
+ const filesSpinner = ora('🔍 Escaneando archivos...').start();
180
+ const files = collectFiles(options.path, verbose, extensions);
181
+ if (files.length === 0) {
182
+ filesSpinner.warn('No se encontraron archivos soportados para procesar.');
183
+ process.exit(0);
184
+ }
185
+ filesSpinner.succeed(`Encontrados ${files.length} archivo(s) para revisar.`);
186
+ const projectRoot = process.cwd();
187
+ const cache = loadCache(projectRoot);
188
+ let cacheHits = 0;
189
+ const reviewEntries = [];
190
+ let succeeded = 0;
191
+ let failed = 0;
192
+ let skipped = 0;
193
+ for (let i = 0; i < files.length; i++) {
194
+ const filePath = files[i];
195
+ const relativePath = path.relative(projectRoot, filePath);
196
+ const fileSpinner = ora({ text: `[${i + 1}/${files.length}] ${relativePath}`, spinner: 'dots' }).start();
197
+ try {
198
+ const fileData = readFile(filePath);
199
+ if (!fileData || shouldSkipContent(fileData.content)) {
200
+ fileSpinner.warn(`Saltado (archivo vacío o no procesable)`);
201
+ skipped++;
202
+ continue;
203
+ }
204
+ const currentHash = computeFileHash(filePath);
205
+ if (isFileCached(filePath, cache, currentHash)) {
206
+ const cachedEntry = cache[filePath];
207
+ fileSpinner.info(`[${i + 1}/${files.length}] ${relativePath} → Cache hit`);
208
+ if (cachedEntry?.content) {
209
+ const cachedResults = parseReviewResults(cachedEntry.content);
210
+ reviewEntries.push({ relativePath, filePath, results: cachedResults });
211
+ succeeded++;
212
+ cacheHits++;
213
+ }
214
+ continue;
215
+ }
216
+ if (verbose) {
217
+ fileSpinner.text = `[${i + 1}/${files.length}] ${relativePath} - Generando review...`;
218
+ }
219
+ const reviewResults = await generateReview(ai, filePath, fileData.content, verbose, resolved.model, maxChars);
220
+ if (reviewResults) {
221
+ if (dryRun) {
222
+ const preview = reviewResults.slice(0, 3).map(r => ` ${r.severity}: ${r.suggestion}`).join('\n');
223
+ fileSpinner.succeed(`[${i + 1}/${files.length}] ${relativePath} → [DRY-RUN] ${reviewResults.length} findings:\n${preview}`);
224
+ succeeded++;
225
+ }
226
+ else {
227
+ const severityIcon = reviewResults.some(r => r.severity === 'critical') ? '🔴' :
228
+ reviewResults.some(r => r.severity === 'warning') ? '🟡' : '🟢';
229
+ fileSpinner.succeed(`[${i + 1}/${files.length}] ${relativePath} → ${severityIcon} ${reviewResults.length} findings`);
230
+ reviewEntries.push({ relativePath, filePath, results: reviewResults });
231
+ updateCache(filePath, '', currentHash, cache, JSON.stringify(reviewResults));
232
+ succeeded++;
233
+ }
234
+ }
235
+ else {
236
+ fileSpinner.fail(`[${i + 1}/${files.length}] ${relativePath} - No se pudo generar review`);
237
+ failed++;
238
+ }
239
+ }
240
+ catch (err) {
241
+ const error = err;
242
+ fileSpinner.fail(`[${i + 1}/${files.length}] ${relativePath} - Error inesperado`);
243
+ if (verbose) {
244
+ console.error(` ${error.message}`);
245
+ }
246
+ failed++;
247
+ }
248
+ }
249
+ if (!dryRun && reviewEntries.length > 0) {
250
+ if (options.output) {
251
+ const writeSpinner = ora('📄 Escribiendo reporte...').start();
252
+ const outputPath = path.resolve(options.output);
253
+ const format = mergeConfig(options.format, rcConfig?.format, 'terminal');
254
+ if (format === 'markdown') {
255
+ const markdown = generateMarkdownReport(reviewEntries);
256
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
257
+ fs.writeFileSync(outputPath, markdown, 'utf-8');
258
+ writeSpinner.succeed(`Reporte guardado: ${outputPath}`);
259
+ }
260
+ else if (format === 'html') {
261
+ const htmlOutput = outputPath.endsWith('.html') ? outputPath : outputPath + '.html';
262
+ const html = generateHtmlReport(reviewEntries, 'Agent Code Review');
263
+ fs.mkdirSync(path.dirname(htmlOutput), { recursive: true });
264
+ fs.writeFileSync(htmlOutput, html, 'utf-8');
265
+ writeSpinner.succeed(`Reporte HTML guardado: ${htmlOutput}`);
266
+ }
267
+ else if (format === 'pdf') {
268
+ const pdfOutput = outputPath.endsWith('.pdf') ? outputPath : outputPath + '.pdf';
269
+ fs.mkdirSync(path.dirname(pdfOutput), { recursive: true });
270
+ await generatePdfReport(reviewEntries, pdfOutput, 'Agent Code Review');
271
+ writeSpinner.succeed(`Reporte PDF guardado: ${pdfOutput}`);
272
+ }
273
+ else {
274
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
275
+ fs.writeFileSync(outputPath, JSON.stringify(reviewEntries, null, 2), 'utf-8');
276
+ writeSpinner.succeed(`Reporte guardado: ${outputPath}`);
277
+ }
278
+ }
279
+ else {
280
+ printTerminalReport(reviewEntries);
281
+ }
282
+ }
283
+ if (!dryRun) {
284
+ saveCache(projectRoot, cache);
285
+ }
286
+ console.log('=== Resumen ===');
287
+ console.log(` Total: ${files.length}`);
288
+ console.log(` ✅ OK: ${succeeded}`);
289
+ console.log(` ⚠️ Skip: ${skipped}`);
290
+ console.log(` ❌ Error: ${failed}`);
291
+ if (cacheHits > 0) {
292
+ console.log(` 💾 Cache: ${cacheHits}`);
293
+ }
294
+ console.log('');
295
+ if (failed > 0) {
296
+ process.exit(1);
297
+ }
298
+ }
299
+ main().catch((err) => {
300
+ const error = err;
301
+ console.error(`[FATAL] Error inesperado: ${error.message}`);
302
+ process.exit(1);
303
+ });
304
+ function resolveTargetDir(targetPath, output) {
305
+ const resolvedOutput = output ?? rcConfig?.output;
306
+ if (resolvedOutput)
307
+ return path.resolve(resolvedOutput);
308
+ const resolved = path.resolve(targetPath);
309
+ try {
310
+ return fs.statSync(resolved).isDirectory() ? resolved : path.dirname(resolved);
311
+ }
312
+ catch {
313
+ return resolved;
314
+ }
315
+ }
316
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ export interface AIClient {
2
+ generate(prompt: string, model: string): Promise<string | null>;
3
+ }
4
+ export interface CreateAIClientOptions {
5
+ provider?: string;
6
+ apiKey?: string;
7
+ baseUrl?: string;
8
+ model?: string;
9
+ verbose?: boolean;
10
+ }
11
+ export declare class GeminiClient implements AIClient {
12
+ private ai;
13
+ constructor(apiKey: string);
14
+ generate(prompt: string, model: string): Promise<string | null>;
15
+ }
16
+ export declare class OpenAIClient implements AIClient {
17
+ private apiKey;
18
+ constructor(apiKey: string);
19
+ generate(prompt: string, model: string): Promise<string | null>;
20
+ }
21
+ export declare class AnthropicClient implements AIClient {
22
+ private apiKey;
23
+ constructor(apiKey: string);
24
+ generate(prompt: string, model: string): Promise<string | null>;
25
+ }
26
+ export declare class DeepSeekClient implements AIClient {
27
+ private apiKey;
28
+ constructor(apiKey: string);
29
+ generate(prompt: string, model: string): Promise<string | null>;
30
+ }
31
+ export declare class OllamaClient implements AIClient {
32
+ private baseUrl;
33
+ private apiKey?;
34
+ constructor(baseUrl: string, apiKey?: string);
35
+ generate(prompt: string, model: string): Promise<string | null>;
36
+ }
37
+ export declare function createAIClient(options?: CreateAIClientOptions): AIClient | null;
38
+ //# sourceMappingURL=aiClient.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aiClient.d.ts","sourceRoot":"","sources":["../../src/aiClient.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CACjE;AAED,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAKD,qBAAa,YAAa,YAAW,QAAQ;IAC3C,OAAO,CAAC,EAAE,CAAc;gBAEZ,MAAM,EAAE,MAAM;IAIpB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAItE;AAED,qBAAa,YAAa,YAAW,QAAQ;IAC3C,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,MAAM;IAIpB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAwBtE;AAED,qBAAa,eAAgB,YAAW,QAAQ;IAC9C,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,MAAM;IAIpB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAyBtE;AAED,qBAAa,cAAe,YAAW,QAAQ;IAC7C,OAAO,CAAC,MAAM,CAAS;gBAEX,MAAM,EAAE,MAAM;IAIpB,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAwBtE;AAED,qBAAa,YAAa,YAAW,QAAQ;IAC3C,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,MAAM,CAAC,CAAS;gBAEZ,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;IAKtC,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CAyBtE;AAED,wBAAgB,cAAc,CAAC,OAAO,GAAE,qBAA0B,GAAG,QAAQ,GAAG,IAAI,CA8DnF"}
@@ -0,0 +1,180 @@
1
+ import { GoogleGenAI } from '@google/genai';
2
+ const PLACEHOLDER_KEY = 'your_gemini_api_key_here';
3
+ const DEFAULT_LOCAL_BASE_URL = 'http://localhost:11434';
4
+ export class GeminiClient {
5
+ ai;
6
+ constructor(apiKey) {
7
+ this.ai = new GoogleGenAI({ apiKey });
8
+ }
9
+ async generate(prompt, model) {
10
+ const result = await this.ai.models.generateContent({ model, contents: prompt });
11
+ return result.text ?? null;
12
+ }
13
+ }
14
+ export class OpenAIClient {
15
+ apiKey;
16
+ constructor(apiKey) {
17
+ this.apiKey = apiKey;
18
+ }
19
+ async generate(prompt, model) {
20
+ const res = await fetch('https://api.openai.com/v1/chat/completions', {
21
+ method: 'POST',
22
+ headers: {
23
+ 'Content-Type': 'application/json',
24
+ 'Authorization': `Bearer ${this.apiKey}`,
25
+ },
26
+ body: JSON.stringify({
27
+ model,
28
+ messages: [{ role: 'user', content: prompt }],
29
+ stream: false,
30
+ }),
31
+ });
32
+ if (!res.ok) {
33
+ const body = await res.text().catch(() => '');
34
+ throw new Error(`OpenAI API error ${res.status}: ${body}`);
35
+ }
36
+ const data = (await res.json());
37
+ return data?.choices?.[0]?.message?.content ?? null;
38
+ }
39
+ }
40
+ export class AnthropicClient {
41
+ apiKey;
42
+ constructor(apiKey) {
43
+ this.apiKey = apiKey;
44
+ }
45
+ async generate(prompt, model) {
46
+ const res = await fetch('https://api.anthropic.com/v1/messages', {
47
+ method: 'POST',
48
+ headers: {
49
+ 'Content-Type': 'application/json',
50
+ 'x-api-key': this.apiKey,
51
+ 'anthropic-version': '2023-06-01',
52
+ },
53
+ body: JSON.stringify({
54
+ model,
55
+ messages: [{ role: 'user', content: prompt }],
56
+ max_tokens: 8096,
57
+ }),
58
+ });
59
+ if (!res.ok) {
60
+ const body = await res.text().catch(() => '');
61
+ throw new Error(`Anthropic API error ${res.status}: ${body}`);
62
+ }
63
+ const data = (await res.json());
64
+ return data?.content?.[0]?.text ?? null;
65
+ }
66
+ }
67
+ export class DeepSeekClient {
68
+ apiKey;
69
+ constructor(apiKey) {
70
+ this.apiKey = apiKey;
71
+ }
72
+ async generate(prompt, model) {
73
+ const res = await fetch('https://api.deepseek.com/v1/chat/completions', {
74
+ method: 'POST',
75
+ headers: {
76
+ 'Content-Type': 'application/json',
77
+ 'Authorization': `Bearer ${this.apiKey}`,
78
+ },
79
+ body: JSON.stringify({
80
+ model,
81
+ messages: [{ role: 'user', content: prompt }],
82
+ stream: false,
83
+ }),
84
+ });
85
+ if (!res.ok) {
86
+ const body = await res.text().catch(() => '');
87
+ throw new Error(`DeepSeek API error ${res.status}: ${body}`);
88
+ }
89
+ const data = (await res.json());
90
+ return data?.choices?.[0]?.message?.content ?? null;
91
+ }
92
+ }
93
+ export class OllamaClient {
94
+ baseUrl;
95
+ apiKey;
96
+ constructor(baseUrl, apiKey) {
97
+ this.baseUrl = baseUrl.replace(/\/+$/, '');
98
+ this.apiKey = apiKey;
99
+ }
100
+ async generate(prompt, model) {
101
+ const url = `${this.baseUrl}/api/chat`;
102
+ const headers = { 'Content-Type': 'application/json' };
103
+ if (this.apiKey)
104
+ headers['Authorization'] = `Bearer ${this.apiKey}`;
105
+ const res = await fetch(url, {
106
+ method: 'POST',
107
+ headers,
108
+ body: JSON.stringify({
109
+ model,
110
+ messages: [{ role: 'user', content: prompt }],
111
+ stream: false,
112
+ }),
113
+ });
114
+ if (!res.ok) {
115
+ const body = await res.text().catch(() => '');
116
+ throw new Error(`Ollama API error ${res.status}: ${body}`);
117
+ }
118
+ const data = (await res.json());
119
+ return data?.message?.content ?? null;
120
+ }
121
+ }
122
+ export function createAIClient(options = {}) {
123
+ const provider = options.provider ?? 'gemini';
124
+ switch (provider) {
125
+ case 'gemini': {
126
+ const apiKey = options.apiKey;
127
+ if (!apiKey || apiKey === PLACEHOLDER_KEY) {
128
+ console.error('[ERROR] GEMINI_API_KEY is not set or is invalid.');
129
+ console.error(' Create a .env file with: GEMINI_API_KEY=your_key');
130
+ console.error(' Get key at: https://aistudio.google.com/apikey');
131
+ console.error(' Or use: --provider openai | anthropic | deepseek | ollama');
132
+ return null;
133
+ }
134
+ try {
135
+ return new GeminiClient(apiKey);
136
+ }
137
+ catch (err) {
138
+ const error = err;
139
+ console.error(`[ERROR] Failed to initialize Gemini client: ${error.message}`);
140
+ return null;
141
+ }
142
+ }
143
+ case 'openai': {
144
+ const apiKey = options.apiKey;
145
+ if (!apiKey) {
146
+ console.error('[ERROR] OPENAI_API_KEY is not set.');
147
+ console.error(' Create a .env file with: OPENAI_API_KEY=sk-...');
148
+ return null;
149
+ }
150
+ return new OpenAIClient(apiKey);
151
+ }
152
+ case 'anthropic': {
153
+ const apiKey = options.apiKey;
154
+ if (!apiKey) {
155
+ console.error('[ERROR] ANTHROPIC_API_KEY is not set.');
156
+ console.error(' Create a .env file with: ANTHROPIC_API_KEY=sk-ant-...');
157
+ return null;
158
+ }
159
+ return new AnthropicClient(apiKey);
160
+ }
161
+ case 'deepseek': {
162
+ const apiKey = options.apiKey;
163
+ if (!apiKey) {
164
+ console.error('[ERROR] DEEPSEEK_API_KEY is not set.');
165
+ console.error(' Create a .env file with: DEEPSEEK_API_KEY=sk-...');
166
+ return null;
167
+ }
168
+ return new DeepSeekClient(apiKey);
169
+ }
170
+ case 'ollama': {
171
+ const baseUrl = options.baseUrl ?? DEFAULT_LOCAL_BASE_URL;
172
+ return new OllamaClient(baseUrl, options.apiKey);
173
+ }
174
+ default:
175
+ console.error(`[ERROR] Unknown provider: "${provider}"`);
176
+ console.error(' Valid providers: gemini, openai, anthropic, deepseek, ollama');
177
+ return null;
178
+ }
179
+ }
180
+ //# sourceMappingURL=aiClient.js.map