ownkey 0.2.1 → 0.5.1

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 (50) hide show
  1. package/README.md +108 -38
  2. package/dist/ai/factory.d.ts +23 -0
  3. package/dist/ai/factory.d.ts.map +1 -0
  4. package/dist/ai/factory.js +96 -0
  5. package/dist/ai/factory.js.map +1 -0
  6. package/dist/ai/gemini.d.ts +21 -0
  7. package/dist/ai/gemini.d.ts.map +1 -0
  8. package/dist/ai/gemini.js +87 -0
  9. package/dist/ai/gemini.js.map +1 -0
  10. package/dist/ai/provider.d.ts +39 -0
  11. package/dist/ai/provider.d.ts.map +1 -0
  12. package/dist/ai/provider.js +99 -0
  13. package/dist/ai/provider.js.map +1 -0
  14. package/dist/commands/config.js +3 -1
  15. package/dist/commands/config.js.map +1 -1
  16. package/dist/commands/suggest.d.ts.map +1 -1
  17. package/dist/commands/suggest.js +102 -10
  18. package/dist/commands/suggest.js.map +1 -1
  19. package/dist/config/defaults.d.ts.map +1 -1
  20. package/dist/config/defaults.js +5 -2
  21. package/dist/config/defaults.js.map +1 -1
  22. package/dist/config/keychain.d.ts.map +1 -1
  23. package/dist/config/keychain.js +12 -0
  24. package/dist/config/keychain.js.map +1 -1
  25. package/dist/db/client.d.ts.map +1 -1
  26. package/dist/db/client.js +41 -15
  27. package/dist/db/client.js.map +1 -1
  28. package/dist/index.js +1 -1
  29. package/dist/types/index.d.ts +4 -1
  30. package/dist/types/index.d.ts.map +1 -1
  31. package/dist/types/index.js.map +1 -1
  32. package/package.json +11 -3
  33. package/.prettierrc +0 -9
  34. package/src/commands/apply.ts +0 -27
  35. package/src/commands/config.ts +0 -154
  36. package/src/commands/scan.ts +0 -114
  37. package/src/commands/suggest.ts +0 -37
  38. package/src/config/defaults.ts +0 -80
  39. package/src/config/keychain.ts +0 -125
  40. package/src/config/manager.ts +0 -166
  41. package/src/core/scanner.ts +0 -174
  42. package/src/db/client.ts +0 -151
  43. package/src/db/operations.ts +0 -217
  44. package/src/db/schema.ts +0 -118
  45. package/src/index.ts +0 -74
  46. package/src/types/index.ts +0 -198
  47. package/src/utils/encryption.ts +0 -54
  48. package/src/utils/logger.ts +0 -111
  49. package/tsconfig.json +0 -33
  50. /package/{src → dist}/db/migrations/001_init.sql +0 -0
package/README.md CHANGED
@@ -1,9 +1,24 @@
1
- # OwnKey CLI
1
+ <div align="center">
2
2
 
3
- **Local-first AI coding agent for intelligent codebase analysis**
3
+ <img src="assets/logo.png" alt="OwnKey Logo" width="600"/>
4
+
5
+ # OwnKey
6
+
7
+ **Privacy-First AI Coding Agent**
4
8
 
5
9
  [![npm version](https://badge.fury.io/js/ownkey.svg)](https://www.npmjs.com/package/ownkey)
6
10
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
11
+ [![Downloads](https://img.shields.io/npm/dm/ownkey.svg)](https://www.npmjs.com/package/ownkey)
12
+
13
+ *Intelligent code analysis powered by Google Gemini 2.5 • Your code never leaves your machine*
14
+
15
+ [Quick Start](#-quick-start) • [Features](#-features) • [Installation](#-installation) • [Documentation](#-commands)
16
+
17
+ </div>
18
+
19
+ ---
20
+
21
+ > ⚠️ **v0.5.0** - Currently supports Google Gemini. OpenAI, Anthropic, and Ollama coming soon!
7
22
 
8
23
  ## 🚀 Quick Start
9
24
 
@@ -11,24 +26,58 @@
11
26
  # Install globally
12
27
  npm install -g ownkey
13
28
 
14
- # Configure OwnKey
15
- ownkey config
16
-
17
- # Scan your project
18
- ownkey scan .
29
+ # Configure with your Gemini API key
30
+ ownkey config --provider gemini --api-key YOUR_KEY
19
31
 
20
- # Get AI suggestions (coming in v0.5.0)
32
+ # Analyze your codebase
21
33
  ownkey suggest .
22
34
  ```
23
35
 
24
- ## 📋 Features
36
+ **Get your free Gemini API key:** [Google AI Studio](https://aistudio.google.com/app/apikey)
37
+
38
+ ## ✨ Features
39
+
40
+ <table>
41
+ <tr>
42
+ <td width="50%">
43
+
44
+ ### 🤖 AI-Powered Analysis
45
+ Intelligent code review using Google Gemini 2.5 Pro
46
+
47
+ ### 🔒 Privacy-First
48
+ Your code never leaves your machine - all analysis is local
49
+
50
+ ### 💾 Optional Cloud Sync
51
+ Store history in your own Supabase database
52
+
53
+ </td>
54
+ <td width="50%">
25
55
 
26
- - **Local-First**: Your code never leaves your machine
27
- - **AI-Powered**: Intelligent analysis using OpenAI, Anthropic, or local LLMs
28
- - **Privacy-First**: API keys stored securely in OS keychain
29
- - **Database Integration**: Optional Supabase for history tracking
30
- - **Smart Scanning**: Respects .gitignore and custom ignore patterns
31
- - **Safe Changes**: Backup files before applying suggestions
56
+ ### 🔐 Secure Storage
57
+ API keys stored in OS keychain or encrypted
58
+
59
+ ### 📂 Smart Scanning
60
+ Respects .gitignore and custom patterns
61
+
62
+ ### 🎯 Multi-Model Support
63
+ Use any Gemini model (pro, flash, flash-lite)
64
+
65
+ </td>
66
+ </tr>
67
+ </table>
68
+
69
+ ## ⚡ AI Provider Support
70
+
71
+ <div align="center">
72
+
73
+ | Provider | Status | Models | ETA |
74
+ |:--------:|:------:|:------:|:---:|
75
+ | **🟢 Google Gemini** | ✅ **Available Now** | gemini-2.5-pro, gemini-2.5-flash | - |
76
+ | **🔵 OpenAI** | 🔜 Coming Soon | GPT-4, GPT-4 Turbo | v0.6.0 |
77
+ | **🟣 Anthropic** | 🔜 Coming Soon | Claude 3.5 Sonnet | v0.7.0 |
78
+ | **🟠 Ollama** | 🔜 Coming Soon | Any local model | v0.8.0 |
79
+
80
+ </div>
32
81
 
33
82
  ## 🛠 Installation
34
83
 
@@ -41,7 +90,7 @@ npm install -g ownkey
41
90
  ### From Source
42
91
 
43
92
  ```bash
44
- git clone https://github.com/yourusername/ownkey-cli.git
93
+ git clone https://github.com/ArpitK24/OwnKey.git
45
94
  cd ownkey-cli
46
95
  npm install
47
96
  npm run build
@@ -50,27 +99,30 @@ npm link
50
99
 
51
100
  ## ⚙️ Configuration
52
101
 
53
- Run the interactive configuration wizard:
102
+ ### Interactive Setup
54
103
 
55
104
  ```bash
56
105
  ownkey config
57
106
  ```
58
107
 
59
- Or use flags:
108
+ ### Using Flags
60
109
 
61
110
  ```bash
62
- # Configure Supabase
63
- ownkey config --supabase-url postgresql://... --supabase-key your-key
111
+ # Configure Gemini
112
+ ownkey config --provider gemini --api-key YOUR_GEMINI_API_KEY
113
+
114
+ # Optional: Configure Supabase for history tracking
115
+ ownkey config --supabase-url https://xxx.supabase.co --supabase-key YOUR_KEY
64
116
 
65
- # Configure AI provider
66
- ownkey config --provider openai --api-key sk-...
117
+ # Use different Gemini model
118
+ ownkey config --provider gemini --model gemini-2.5-flash
67
119
  ```
68
120
 
69
- ### Supported AI Providers
121
+ ### Getting a Gemini API Key
70
122
 
71
- - **OpenAI** (GPT-4)
72
- - **Anthropic** (Claude)
73
- - **Ollama** (Local LLMs)
123
+ 1. Visit [Google AI Studio](https://aistudio.google.com/app/apikey)
124
+ 2. Create a new API key
125
+ 3. Run `ownkey config --provider gemini --api-key YOUR_KEY`
74
126
 
75
127
  ## 📖 Commands
76
128
 
@@ -81,6 +133,7 @@ Configure Supabase database and AI providers.
81
133
  ```bash
82
134
  ownkey config # Interactive wizard
83
135
  ownkey config --reset # Reset to defaults
136
+ ownkey config --provider gemini --api-key YOUR_KEY
84
137
  ```
85
138
 
86
139
  ### `ownkey scan [path]`
@@ -91,16 +144,32 @@ Scan a project directory.
91
144
  ownkey scan . # Scan current directory
92
145
  ownkey scan ./src # Scan specific folder
93
146
  ownkey scan --max-file-size 1mb # Custom file size limit
147
+ ownkey scan --ignore "*.test.js" # Additional ignore patterns
94
148
  ```
95
149
 
96
- ### `ownkey suggest [path]` *(Coming in v0.5.0)*
150
+ ### `ownkey suggest [path]`
97
151
 
98
- Generate AI-powered suggestions.
152
+ Generate AI-powered code suggestions.
99
153
 
100
154
  ```bash
101
- ownkey suggest .
102
- ownkey suggest --type security
103
- ownkey suggest --severity high
155
+ ownkey suggest . # Analyze current directory
156
+ ownkey suggest ./src # Analyze specific folder
157
+ ownkey suggest --max-files 20 # Limit files analyzed
158
+ ownkey suggest --local-only # Skip database storage
159
+ ```
160
+
161
+ **Output:**
162
+ ```
163
+ 🔍 Analyzing code...
164
+
165
+ [1] bug (high) in src/auth.ts
166
+ Potential null pointer dereference
167
+
168
+ [2] security (critical) in db/query.ts
169
+ SQL injection vulnerability detected
170
+
171
+ ✨ Analysis Complete!
172
+ Total suggestions: 12
104
173
  ```
105
174
 
106
175
  ### `ownkey apply <id>` *(Coming in v0.7.0)*
@@ -149,16 +218,16 @@ npm test
149
218
  - [x] v0.2.0 - CLI skeleton & configuration
150
219
  - [x] v0.3.0 - Config system with keychain
151
220
  - [x] v0.4.0 - File scanner
152
- - [ ] v0.5.0 - AI provider integration
153
- - [ ] v0.6.0 - Suggestion engine
221
+ - [x] **v0.5.0 - Gemini AI integration** ← Current
222
+ - [ ] v0.6.0 - OpenAI & Anthropic providers
154
223
  - [ ] v0.7.0 - Apply/diff system
155
- - [ ] v0.8.0 - Additional commands
224
+ - [ ] v0.8.0 - Ollama (local LLM) support
156
225
  - [ ] v0.9.0 - Testing & polish
157
226
  - [ ] v1.0.0 - Stable release
158
227
 
159
228
  ## 🤝 Contributing
160
229
 
161
- Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) first.
230
+ Contributions are welcome! Please feel free to submit a Pull Request.
162
231
 
163
232
  ## 📄 License
164
233
 
@@ -166,10 +235,11 @@ MIT © 2026 OwnKey
166
235
 
167
236
  ## 🔗 Links
168
237
 
169
- - [Documentation](https://github.com/yourusername/ownkey-cli/wiki)
170
- - [Issue Tracker](https://github.com/yourusername/ownkey-cli/issues)
238
+ - [GitHub Repository](https://github.com/ArpitK24/OwnKey)
239
+ - [Issue Tracker](https://github.com/ArpitK24/OwnKey/issues)
171
240
  - [npm Package](https://www.npmjs.com/package/ownkey)
241
+ - [Get Gemini API Key](https://aistudio.google.com/app/apikey)
172
242
 
173
243
  ---
174
244
 
175
- **Note**: OwnKey is currently in active development. Features marked as "coming soon" are planned for upcoming releases.
245
+ **Built with ❤️ for developers who value privacy and AI-powered productivity**
@@ -0,0 +1,23 @@
1
+ import { AIProvider } from './provider.js';
2
+ /**
3
+ * Factory for creating AI provider instances
4
+ */
5
+ export declare class AIProviderFactory {
6
+ /**
7
+ * Create an AI provider instance based on configuration
8
+ */
9
+ static createProvider(): Promise<AIProvider>;
10
+ /**
11
+ * Test provider connection
12
+ */
13
+ static testProvider(provider: AIProvider): Promise<boolean>;
14
+ /**
15
+ * Get recommended model for a provider
16
+ */
17
+ static getRecommendedModel(provider: string): string;
18
+ /**
19
+ * Get available models for a provider
20
+ */
21
+ static getAvailableModels(provider: string): string[];
22
+ }
23
+ //# sourceMappingURL=factory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/ai/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAM3C;;GAEG;AACH,qBAAa,iBAAiB;IAC1B;;OAEG;WACU,cAAc,IAAI,OAAO,CAAC,UAAU,CAAC;IAkClD;;OAEG;WACU,YAAY,CAAC,QAAQ,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC;IAgBjE;;OAEG;IACH,MAAM,CAAC,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAepD;;OAEG;IACH,MAAM,CAAC,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE;CAkBxD"}
@@ -0,0 +1,96 @@
1
+ import { GeminiProvider } from './gemini.js';
2
+ import { ConfigError } from '../types/index.js';
3
+ import { configManager } from '../config/manager.js';
4
+ import { logger } from '../utils/logger.js';
5
+ /**
6
+ * Factory for creating AI provider instances
7
+ */
8
+ export class AIProviderFactory {
9
+ /**
10
+ * Create an AI provider instance based on configuration
11
+ */
12
+ static async createProvider() {
13
+ const config = await configManager.load();
14
+ if (!config.activeProvider) {
15
+ throw new ConfigError('No active AI provider configured. Run: ownkey config');
16
+ }
17
+ const provider = config.activeProvider;
18
+ const apiKey = await configManager.getApiKey(provider);
19
+ logger.verbose(`Creating ${provider} provider...`);
20
+ switch (provider) {
21
+ case 'gemini':
22
+ if (!apiKey) {
23
+ throw new ConfigError('Gemini API key not found. Run: ownkey config');
24
+ }
25
+ const geminiModel = config.providers.gemini?.model || GeminiProvider.getRecommendedModel();
26
+ return new GeminiProvider(apiKey, geminiModel);
27
+ case 'openai':
28
+ throw new ConfigError('OpenAI provider not yet implemented (coming soon)');
29
+ case 'anthropic':
30
+ throw new ConfigError('Anthropic provider not yet implemented (coming soon)');
31
+ case 'ollama':
32
+ throw new ConfigError('Ollama provider not yet implemented (coming soon)');
33
+ default:
34
+ throw new ConfigError(`Unknown provider: ${provider}`);
35
+ }
36
+ }
37
+ /**
38
+ * Test provider connection
39
+ */
40
+ static async testProvider(provider) {
41
+ try {
42
+ logger.verbose('Testing provider connection...');
43
+ const result = await provider.testConnection();
44
+ if (result) {
45
+ logger.success('Provider connection successful');
46
+ }
47
+ else {
48
+ logger.error('Provider connection failed');
49
+ }
50
+ return result;
51
+ }
52
+ catch (error) {
53
+ logger.error('Provider test error', error);
54
+ return false;
55
+ }
56
+ }
57
+ /**
58
+ * Get recommended model for a provider
59
+ */
60
+ static getRecommendedModel(provider) {
61
+ switch (provider) {
62
+ case 'gemini':
63
+ return GeminiProvider.getRecommendedModel();
64
+ case 'openai':
65
+ return 'gpt-4-turbo';
66
+ case 'anthropic':
67
+ return 'claude-3-5-sonnet-20241022';
68
+ case 'ollama':
69
+ return 'deepseek-coder:latest';
70
+ default:
71
+ return '';
72
+ }
73
+ }
74
+ /**
75
+ * Get available models for a provider
76
+ */
77
+ static getAvailableModels(provider) {
78
+ switch (provider) {
79
+ case 'gemini':
80
+ return GeminiProvider.getAvailableModels();
81
+ case 'openai':
82
+ return ['gpt-4-turbo', 'gpt-4', 'gpt-3.5-turbo'];
83
+ case 'anthropic':
84
+ return [
85
+ 'claude-3-5-sonnet-20241022',
86
+ 'claude-3-opus-20240229',
87
+ 'claude-3-haiku-20240307',
88
+ ];
89
+ case 'ollama':
90
+ return ['deepseek-coder:latest', 'codellama:latest', 'llama2:latest'];
91
+ default:
92
+ return [];
93
+ }
94
+ }
95
+ }
96
+ //# sourceMappingURL=factory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/ai/factory.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { AIProvider } from './provider.js';
2
+ import { CodeContext, Suggestion, AnalyzeOptions } from '../types/index.js';
3
+ /**
4
+ * Google Gemini AI Provider
5
+ * Supports: gemini-1.5-pro, gemini-1.5-flash, gemini-pro
6
+ */
7
+ export declare class GeminiProvider extends AIProvider {
8
+ private baseUrl;
9
+ getDefaultModel(): string;
10
+ testConnection(): Promise<boolean>;
11
+ analyze(context: CodeContext, options?: AnalyzeOptions): AsyncGenerator<Suggestion>;
12
+ /**
13
+ * Get available Gemini models
14
+ */
15
+ static getAvailableModels(): string[];
16
+ /**
17
+ * Get recommended model for code analysis
18
+ */
19
+ static getRecommendedModel(): string;
20
+ }
21
+ //# sourceMappingURL=gemini.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini.d.ts","sourceRoot":"","sources":["../../src/ai/gemini.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAmB,MAAM,mBAAmB,CAAC;AAyB7F;;;GAGG;AACH,qBAAa,cAAe,SAAQ,UAAU;IAC1C,OAAO,CAAC,OAAO,CAAkD;IAEjE,eAAe,IAAI,MAAM;IAInB,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAMjC,OAAO,CAAC,OAAO,EAAE,WAAW,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,cAAc,CAAC,UAAU,CAAC;IAsE1F;;OAEG;IACH,MAAM,CAAC,kBAAkB,IAAI,MAAM,EAAE;IAIrC;;OAEG;IACH,MAAM,CAAC,mBAAmB,IAAI,MAAM;CAGvC"}
@@ -0,0 +1,87 @@
1
+ import { AIProvider } from './provider.js';
2
+ import { AIProviderError } from '../types/index.js';
3
+ import { logger } from '../utils/logger.js';
4
+ /**
5
+ * Google Gemini AI Provider
6
+ * Supports: gemini-1.5-pro, gemini-1.5-flash, gemini-pro
7
+ */
8
+ export class GeminiProvider extends AIProvider {
9
+ baseUrl = 'https://generativelanguage.googleapis.com/v1';
10
+ getDefaultModel() {
11
+ return 'gemini-2.5-pro';
12
+ }
13
+ async testConnection() {
14
+ // Temporarily bypass for testing - will fix endpoint later
15
+ logger.verbose('Skipping Gemini connection test (will test during analysis)');
16
+ return true;
17
+ }
18
+ async *analyze(context, options) {
19
+ try {
20
+ logger.verbose(`Analyzing with Gemini (${this.model})...`);
21
+ const systemPrompt = this.getSystemPrompt();
22
+ const userPrompt = this.buildUserPrompt(context);
23
+ const request = {
24
+ contents: [
25
+ {
26
+ role: 'user',
27
+ parts: [
28
+ { text: systemPrompt },
29
+ { text: userPrompt },
30
+ ],
31
+ },
32
+ ],
33
+ generationConfig: {
34
+ temperature: options?.temperature || 0.3,
35
+ maxOutputTokens: options?.maxTokens || 8192,
36
+ },
37
+ };
38
+ const response = await fetch(`${this.baseUrl}/models/${this.model}:generateContent`, {
39
+ method: 'POST',
40
+ headers: {
41
+ 'Content-Type': 'application/json',
42
+ 'x-goog-api-key': this.apiKey || '',
43
+ },
44
+ body: JSON.stringify(request),
45
+ });
46
+ if (!response.ok) {
47
+ const errorText = await response.text();
48
+ logger.error(`Gemini API error: ${errorText}`);
49
+ throw new AIProviderError(`Gemini API error: ${response.status} ${errorText}`);
50
+ }
51
+ const data = (await response.json());
52
+ if (!data.candidates || data.candidates.length === 0) {
53
+ throw new AIProviderError('No response from Gemini');
54
+ }
55
+ const candidate = data.candidates[0];
56
+ const responseText = candidate.content.parts.map((p) => p.text).join('');
57
+ logger.verbose('Received response from Gemini');
58
+ logger.debug('Response:', responseText.substring(0, 200) + '...');
59
+ // Parse suggestions from response
60
+ const suggestions = this.parseSuggestions(responseText);
61
+ logger.success(`Generated ${suggestions.length} suggestions`);
62
+ // Yield suggestions one by one (simulating streaming)
63
+ for (const suggestion of suggestions) {
64
+ yield suggestion;
65
+ }
66
+ }
67
+ catch (error) {
68
+ if (error instanceof AIProviderError) {
69
+ throw error;
70
+ }
71
+ throw new AIProviderError('Failed to analyze with Gemini', error);
72
+ }
73
+ }
74
+ /**
75
+ * Get available Gemini models
76
+ */
77
+ static getAvailableModels() {
78
+ return ['gemini-2.5-pro', 'gemini-2.5-flash', 'gemini-2.5-flash-lite'];
79
+ }
80
+ /**
81
+ * Get recommended model for code analysis
82
+ */
83
+ static getRecommendedModel() {
84
+ return 'gemini-2.5-pro';
85
+ }
86
+ }
87
+ //# sourceMappingURL=gemini.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini.js","sourceRoot":"","sources":["../../src/ai/gemini.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import { CodeContext, Suggestion, AnalyzeOptions, AIProviderInterface } from '../types/index.js';
2
+ /**
3
+ * Base abstract class for AI providers
4
+ * All providers (OpenAI, Gemini, Anthropic, Ollama) must implement this interface
5
+ */
6
+ export declare abstract class AIProvider implements AIProviderInterface {
7
+ protected apiKey?: string;
8
+ protected model: string;
9
+ protected endpoint?: string;
10
+ constructor(apiKey?: string, model?: string, endpoint?: string);
11
+ /**
12
+ * Get the default model for this provider
13
+ */
14
+ abstract getDefaultModel(): string;
15
+ /**
16
+ * Test if the provider connection is working
17
+ */
18
+ abstract testConnection(): Promise<boolean>;
19
+ /**
20
+ * Analyze code and generate suggestions
21
+ * @param context - Code context with files and project info
22
+ * @param options - Analysis options (streaming, max tokens, etc.)
23
+ * @returns AsyncGenerator yielding suggestions as they're generated
24
+ */
25
+ abstract analyze(context: CodeContext, options?: AnalyzeOptions): AsyncGenerator<Suggestion>;
26
+ /**
27
+ * Format the system prompt for code analysis
28
+ */
29
+ protected getSystemPrompt(): string;
30
+ /**
31
+ * Build the user prompt with code context
32
+ */
33
+ protected buildUserPrompt(context: CodeContext): string;
34
+ /**
35
+ * Parse AI response and extract suggestions
36
+ */
37
+ protected parseSuggestions(response: string): Suggestion[];
38
+ }
39
+ //# sourceMappingURL=provider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/ai/provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAEjG;;;GAGG;AACH,8BAAsB,UAAW,YAAW,mBAAmB;IAC3D,SAAS,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,KAAK,EAAE,MAAM,CAAC;IACxB,SAAS,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;gBAEhB,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM;IAM9D;;OAEG;IACH,QAAQ,CAAC,eAAe,IAAI,MAAM;IAElC;;OAEG;IACH,QAAQ,CAAC,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;IAE3C;;;;;OAKG;IACH,QAAQ,CAAC,OAAO,CACZ,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE,cAAc,GACzB,cAAc,CAAC,UAAU,CAAC;IAE7B;;OAEG;IACH,SAAS,CAAC,eAAe,IAAI,MAAM;IAgCnC;;OAEG;IACH,SAAS,CAAC,eAAe,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM;IA2BvD;;OAEG;IACH,SAAS,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,EAAE;CAwB7D"}
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Base abstract class for AI providers
3
+ * All providers (OpenAI, Gemini, Anthropic, Ollama) must implement this interface
4
+ */
5
+ export class AIProvider {
6
+ apiKey;
7
+ model;
8
+ endpoint;
9
+ constructor(apiKey, model, endpoint) {
10
+ this.apiKey = apiKey;
11
+ this.model = model || this.getDefaultModel();
12
+ this.endpoint = endpoint;
13
+ }
14
+ /**
15
+ * Format the system prompt for code analysis
16
+ */
17
+ getSystemPrompt() {
18
+ return `You are a senior software engineer performing code review and analysis.
19
+
20
+ Your task is to analyze the provided codebase and identify:
21
+ - Bugs and potential errors
22
+ - Security vulnerabilities
23
+ - Performance issues
24
+ - Code quality improvements
25
+ - Refactoring opportunities
26
+ - Missing tests or documentation
27
+
28
+ Guidelines:
29
+ - Be conservative and precise
30
+ - Only suggest changes you're confident about
31
+ - Provide clear rationale for each suggestion
32
+ - Use unified diff format for code changes
33
+ - Categorize suggestions by type and severity
34
+
35
+ Output Format:
36
+ Return a JSON array of suggestions. Each suggestion must have:
37
+ {
38
+ "type": "bug" | "security" | "performance" | "refactor" | "style" | "architecture" | "test" | "documentation",
39
+ "severity": "critical" | "high" | "medium" | "low" | "info",
40
+ "content": "Brief description of the issue",
41
+ "filePath": "path/to/file.ts",
42
+ "rationale": "Detailed explanation of why this matters",
43
+ "diff": "Unified diff format showing the change"
44
+ }
45
+
46
+ Be thorough but practical. Focus on high-impact suggestions.`;
47
+ }
48
+ /**
49
+ * Build the user prompt with code context
50
+ */
51
+ buildUserPrompt(context) {
52
+ let prompt = `# Project Analysis Request\n\n`;
53
+ prompt += `**Project:** ${context.projectInfo.name}\n`;
54
+ prompt += `**Path:** ${context.projectInfo.rootPath}\n`;
55
+ prompt += `**Files:** ${context.projectInfo.fileCount}\n\n`;
56
+ if (context.projectInfo.language) {
57
+ prompt += `**Primary Language:** ${context.projectInfo.language}\n`;
58
+ }
59
+ if (context.projectInfo.framework) {
60
+ prompt += `**Framework:** ${context.projectInfo.framework}\n`;
61
+ }
62
+ prompt += `\n## Code Files\n\n`;
63
+ for (const file of context.files) {
64
+ prompt += `### ${file.relativePath}\n\n`;
65
+ prompt += `\`\`\`${file.extension.slice(1)}\n`;
66
+ prompt += file.content;
67
+ prompt += `\n\`\`\`\n\n`;
68
+ }
69
+ prompt += `\nAnalyze the above code and provide suggestions in JSON format.`;
70
+ return prompt;
71
+ }
72
+ /**
73
+ * Parse AI response and extract suggestions
74
+ */
75
+ parseSuggestions(response) {
76
+ try {
77
+ // Try to extract JSON from response
78
+ const jsonMatch = response.match(/\[[\s\S]*\]/);
79
+ if (!jsonMatch) {
80
+ throw new Error('No JSON array found in response');
81
+ }
82
+ const suggestions = JSON.parse(jsonMatch[0]);
83
+ // Validate and normalize suggestions
84
+ return suggestions.map((s) => ({
85
+ type: s.type || 'refactor',
86
+ severity: s.severity || 'medium',
87
+ content: s.content || 'No description provided',
88
+ filePath: s.filePath || '',
89
+ rationale: s.rationale || '',
90
+ diff: s.diff || '',
91
+ tags: s.tags,
92
+ }));
93
+ }
94
+ catch (error) {
95
+ throw new Error(`Failed to parse suggestions: ${error}`);
96
+ }
97
+ }
98
+ }
99
+ //# sourceMappingURL=provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/ai/provider.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,OAAgB,UAAU;IAClB,MAAM,CAAU;IAChB,KAAK,CAAS;IACd,QAAQ,CAAU;IAE5B,YAAY,MAAe,EAAE,KAAc,EAAE,QAAiB;QAC1D,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,KAAK,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;QAC7C,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC7B,CAAC;IAuBD;;OAEG;IACO,eAAe;QACrB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;6DA4B8C,CAAC;IAC1D,CAAC;IAED;;OAEG;IACO,eAAe,CAAC,OAAoB;QAC1C,IAAI,MAAM,GAAG,gCAAgC,CAAC;QAC9C,MAAM,IAAI,gBAAgB,OAAO,CAAC,WAAW,CAAC,IAAI,IAAI,CAAC;QACvD,MAAM,IAAI,aAAa,OAAO,CAAC,WAAW,CAAC,QAAQ,IAAI,CAAC;QACxD,MAAM,IAAI,cAAc,OAAO,CAAC,WAAW,CAAC,SAAS,MAAM,CAAC;QAE5D,IAAI,OAAO,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC;YAC/B,MAAM,IAAI,yBAAyB,OAAO,CAAC,WAAW,CAAC,QAAQ,IAAI,CAAC;QACxE,CAAC;QACD,IAAI,OAAO,CAAC,WAAW,CAAC,SAAS,EAAE,CAAC;YAChC,MAAM,IAAI,kBAAkB,OAAO,CAAC,WAAW,CAAC,SAAS,IAAI,CAAC;QAClE,CAAC;QAED,MAAM,IAAI,qBAAqB,CAAC;QAEhC,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAC/B,MAAM,IAAI,OAAO,IAAI,CAAC,YAAY,MAAM,CAAC;YACzC,MAAM,IAAI,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;YAC/C,MAAM,IAAI,IAAI,CAAC,OAAO,CAAC;YACvB,MAAM,IAAI,cAAc,CAAC;QAC7B,CAAC;QAED,MAAM,IAAI,kEAAkE,CAAC;QAE7E,OAAO,MAAM,CAAC;IAClB,CAAC;IAED;;OAEG;IACO,gBAAgB,CAAC,QAAgB;QACvC,IAAI,CAAC;YACD,oCAAoC;YACpC,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;YAChD,IAAI,CAAC,SAAS,EAAE,CAAC;gBACb,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;YACvD,CAAC;YAED,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;YAE7C,qCAAqC;YACrC,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC;gBAChC,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,UAAU;gBAC1B,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,QAAQ;gBAChC,OAAO,EAAE,CAAC,CAAC,OAAO,IAAI,yBAAyB;gBAC/C,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,EAAE;gBAC1B,SAAS,EAAE,CAAC,CAAC,SAAS,IAAI,EAAE;gBAC5B,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,EAAE;gBAClB,IAAI,EAAE,CAAC,CAAC,IAAI;aACf,CAAC,CAAC,CAAC;QACR,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,gCAAgC,KAAK,EAAE,CAAC,CAAC;QAC7D,CAAC;IACL,CAAC;CACJ"}
@@ -108,17 +108,19 @@ async function runInteractiveWizard() {
108
108
  choices: [
109
109
  { name: 'OpenAI (GPT-4)', value: 'openai' },
110
110
  { name: 'Anthropic (Claude)', value: 'anthropic' },
111
+ { name: 'Google Gemini', value: 'gemini' },
111
112
  { name: 'Ollama (Local)', value: 'ollama' },
112
113
  ],
113
114
  },
114
115
  ]);
115
116
  // Get API key (not needed for Ollama)
116
117
  if (provider !== 'ollama') {
118
+ const providerName = provider === 'openai' ? 'OpenAI' : provider === 'anthropic' ? 'Anthropic' : 'Google Gemini';
117
119
  const { apiKey } = await inquirer.prompt([
118
120
  {
119
121
  type: 'password',
120
122
  name: 'apiKey',
121
- message: `${provider === 'openai' ? 'OpenAI' : 'Anthropic'} API Key:`,
123
+ message: `${providerName} API Key:`,
122
124
  validate: (input) => (input ? true : 'API key is required'),
123
125
  },
124
126
  ]);