@sschepis/robodev 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.
package/ai.mjs ADDED
@@ -0,0 +1,8 @@
1
+ // Simple working AI Assistant Entry Point
2
+ import { main } from './src/main.mjs';
3
+
4
+ // Execute main function
5
+ main().catch(err => {
6
+ console.error("Fatal error:", err);
7
+ process.exit(1);
8
+ });
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@sschepis/robodev",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "Robodev: AI-powered development assistant",
6
+ "author": "sschepis",
7
+ "license": "MIT",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/sschepis/robodev.git"
11
+ },
12
+ "keywords": [
13
+ "ai",
14
+ "assistant",
15
+ "agent",
16
+ "automation",
17
+ "llm",
18
+ "dev-tool"
19
+ ],
20
+ "bin": {
21
+ "robodev": "./ai.mjs"
22
+ },
23
+ "main": "src/lib/index.mjs",
24
+ "exports": {
25
+ ".": "./src/lib/index.mjs",
26
+ "./cli": "./ai.mjs",
27
+ "./lib": "./src/lib/index.mjs"
28
+ },
29
+ "scripts": {
30
+ "start": "node ai.mjs"
31
+ },
32
+ "dependencies": {
33
+ "@google/genai": "^1.41.0",
34
+ "@nut-tree-fork/nut-js": "^4.2.6",
35
+ "boxen": "^8.0.1",
36
+ "chalk": "^5.5.0",
37
+ "cli-spinners": "^3.2.0",
38
+ "dotenv": "^17.3.1",
39
+ "figures": "^6.1.0",
40
+ "gradient-string": "^3.0.0",
41
+ "mathjs": "^14.6.0",
42
+ "ora": "^8.2.0",
43
+ "vm2": "^3.10.4"
44
+ },
45
+ "engines": {
46
+ "node": ">=18.0.0"
47
+ }
48
+ }
@@ -0,0 +1,271 @@
1
+ // CLI interface logic
2
+ // Handles command-line interaction and user input processing
3
+
4
+ import readline from 'readline';
5
+ import { consoleStyler } from '../ui/console-styler.mjs';
6
+
7
+ export class CLIInterface {
8
+ constructor() {
9
+ this.rl = null;
10
+ }
11
+
12
+ // Start interactive mode with simple approach
13
+ // Returns a Promise that resolves only when the user types "exit"
14
+ async startInteractiveMode(assistant, workingDir) {
15
+ consoleStyler.log('system', 'AI Assistant (Interactive Mode). Type "exit" to quit.');
16
+ consoleStyler.log('system', `Working Directory: ${workingDir}`);
17
+
18
+ // Create readline with minimal config
19
+ this.rl = readline.createInterface({
20
+ input: process.stdin,
21
+ output: process.stdout
22
+ });
23
+
24
+ // Return a promise that stays pending until exit
25
+ return new Promise((resolve) => {
26
+ // Simple recursive prompt
27
+ const prompt = () => {
28
+ this.rl.question('👤 [YOU] ', async (userInput) => {
29
+ if (!userInput || userInput.trim() === '') {
30
+ prompt();
31
+ return;
32
+ }
33
+
34
+ if (userInput.toLowerCase() === 'exit') {
35
+ consoleStyler.log('system', 'Goodbye!', { box: true });
36
+ // Save session on exit
37
+ await assistant.saveSession('.ai-session');
38
+ resolve(); // Resolve the promise so main() can clean up
39
+ return;
40
+ }
41
+
42
+ // Handle backslash commands for history deletion
43
+ if (userInput.match(/^\\+$/)) {
44
+ const backslashCount = userInput.length;
45
+ const deletedCount = assistant.deleteHistoryExchanges(backslashCount);
46
+ consoleStyler.log('history', `Deleted ${deletedCount} exchange(s) from history.`);
47
+ prompt();
48
+ return;
49
+ }
50
+
51
+ try {
52
+ // Using streaming if available
53
+ if (assistant.runStream) {
54
+ consoleStyler.log('working', 'Thinking...');
55
+ // No spinner for streaming to avoid clearing/redrawing issues
56
+ await assistant.runStream(userInput, (chunk) => {
57
+ process.stdout.write(chunk);
58
+ });
59
+ console.log('\n'); // Newline after stream
60
+ } else {
61
+ const spinner = consoleStyler.startSpinner('processing', 'Processing your request...');
62
+ const response = await assistant.run(userInput);
63
+ consoleStyler.succeedSpinner('processing', 'Request processed');
64
+ consoleStyler.log('ai', response);
65
+ }
66
+ } catch (error) {
67
+ consoleStyler.failSpinner('processing', 'Request failed');
68
+ consoleStyler.log('error', error.message);
69
+ }
70
+
71
+ prompt(); // Continue prompting
72
+ });
73
+ };
74
+
75
+ // Handle stdin close (e.g., piped input, Ctrl+D)
76
+ this.rl.on('close', () => {
77
+ resolve();
78
+ });
79
+
80
+ // Start prompting
81
+ prompt();
82
+ });
83
+ }
84
+
85
+ // Run single-shot mode
86
+ async runSingleShot(assistant, userInput, workingDir) {
87
+ consoleStyler.log('user', userInput);
88
+ consoleStyler.log('system', `Working Directory: ${workingDir}`);
89
+
90
+ try {
91
+ const spinner = consoleStyler.startSpinner('processing', 'Processing your request...');
92
+ const response = await assistant.run(userInput);
93
+ consoleStyler.succeedSpinner('processing', 'Request completed');
94
+ consoleStyler.log('ai', response);
95
+ } catch (error) {
96
+ consoleStyler.failSpinner('processing', 'Request failed');
97
+ const errorDisplay = consoleStyler.formatError(error, {
98
+ suggestions: [
99
+ 'Check your AI provider is configured correctly (see .env.example)',
100
+ 'For local: ensure LMStudio/Ollama is running on the configured port',
101
+ 'For cloud: verify your API key (OPENAI_API_KEY or GOOGLE_API_KEY)',
102
+ 'Try restarting the application'
103
+ ]
104
+ });
105
+ console.log(errorDisplay);
106
+ process.exit(1);
107
+ }
108
+
109
+ // Force exit after a short delay to ensure all output is flushed
110
+ setTimeout(() => {
111
+ process.exit(0);
112
+ }, 100);
113
+ }
114
+
115
+ // Parse command line arguments
116
+ parseArguments() {
117
+ const args = process.argv.slice(2);
118
+ const workingDir = process.cwd();
119
+
120
+ // Check for flags
121
+ const resumeIndex = args.indexOf('--resume');
122
+ const resume = resumeIndex !== -1;
123
+
124
+ // Remove flags from args
125
+ if (resume) {
126
+ args.splice(resumeIndex, 1);
127
+ }
128
+
129
+ return {
130
+ args,
131
+ workingDir,
132
+ resume,
133
+ isInteractive: args.length === 0,
134
+ userInput: args.length > 0 ? args.join(' ') : null
135
+ };
136
+ }
137
+
138
+ // Display startup information
139
+ displayStartupInfo(workingDir) {
140
+ consoleStyler.displayStartupBanner(workingDir);
141
+ }
142
+
143
+ // Display help information
144
+ displayHelp() {
145
+ const theme = consoleStyler.getTheme();
146
+ const helpContent = `
147
+ ${consoleStyler.icons.ai} AI Assistant Help:
148
+
149
+ ${theme.primary('USAGE:')}
150
+ Interactive mode: node ai.mjs
151
+ Single-shot mode: node ai.mjs "your question or command"
152
+
153
+ ${theme.warning('SPECIAL COMMANDS (Interactive mode only):')}
154
+ \\ - Delete the last exchange from conversation history
155
+ \\\\ - Delete the last 2 exchanges from conversation history
156
+ \\\\\\ - Delete the last 3 exchanges from conversation history
157
+ exit - Exit the program
158
+
159
+ ${theme.info('EXAMPLES:')}
160
+ node ai.mjs "Create a simple calculator function"
161
+ node ai.mjs "Use axios to fetch data from jsonplaceholder.typicode.com"
162
+ node ai.mjs "Install and use uuid to generate 5 random IDs"
163
+
164
+ ${theme.success('FEATURES:')}
165
+ ${consoleStyler.icons.check} Execute JavaScript code with automatic npm package installation
166
+ ${consoleStyler.icons.check} Create and manage custom reusable tools
167
+ ${consoleStyler.icons.check} Multi-step task management with todo lists
168
+ ${consoleStyler.icons.check} Error recovery and retry mechanisms
169
+ ${consoleStyler.icons.check} Quality evaluation and response improvement
170
+ ${consoleStyler.icons.check} Workspace management for complex tasks
171
+ ${consoleStyler.icons.check} Text-to-speech support (with ElevenLabs API key)
172
+ ${consoleStyler.icons.check} Enhanced console styling with themes
173
+
174
+ ${theme.system('REQUIREMENTS:')}
175
+ ${consoleStyler.icons.bullet} Node.js v18+ (for native fetch support)
176
+ ${consoleStyler.icons.bullet} One of: LMStudio/Ollama (local), OpenAI API key, or Google Gemini API key
177
+ ${consoleStyler.icons.bullet} Set AI_MODEL in .env (e.g., gpt-4o, gemini-2.0-flash, or local model name)
178
+ ${consoleStyler.icons.bullet} Optional: ElevenLabs API key for text-to-speech
179
+
180
+ ${theme.accent('THEMES:')}
181
+ Available: ${consoleStyler.getAvailableThemes().join(', ')}
182
+ Current: ${consoleStyler.currentTheme}
183
+ `;
184
+
185
+ console.log(helpContent);
186
+ }
187
+
188
+ // Display error information
189
+ displayError(error) {
190
+ const suggestions = [];
191
+
192
+ if (error.code === 'ECONNREFUSED') {
193
+ suggestions.push(
194
+ 'For local: start LMStudio/Ollama and load a model with function calling support',
195
+ 'For cloud: set AI_MODEL and API key in .env (e.g., gemini-2.0-flash + GOOGLE_API_KEY)',
196
+ 'Check your network connection'
197
+ );
198
+ }
199
+
200
+ const errorDisplay = consoleStyler.formatError(error, { suggestions });
201
+ console.log(errorDisplay);
202
+ }
203
+
204
+ // Handle process signals for graceful shutdown
205
+ setupSignalHandlers() {
206
+ process.on('SIGINT', () => {
207
+ consoleStyler.clearAllSpinners();
208
+ consoleStyler.log('system', 'Received SIGINT, shutting down gracefully...', { box: true });
209
+ if (this.rl) {
210
+ this.rl.close();
211
+ }
212
+ process.exit(0);
213
+ });
214
+
215
+ process.on('SIGTERM', () => {
216
+ consoleStyler.clearAllSpinners();
217
+ consoleStyler.log('system', 'Received SIGTERM, shutting down gracefully...', { box: true });
218
+ if (this.rl) {
219
+ this.rl.close();
220
+ }
221
+ process.exit(0);
222
+ });
223
+
224
+ process.on('uncaughtException', (error) => {
225
+ consoleStyler.clearAllSpinners();
226
+ consoleStyler.log('error', `UNCAUGHT EXCEPTION: ${error.message}`);
227
+ this.displayError(error);
228
+ process.exit(1);
229
+ });
230
+
231
+ process.on('unhandledRejection', (reason, promise) => {
232
+ consoleStyler.clearAllSpinners();
233
+ consoleStyler.log('error', `UNHANDLED REJECTION: ${reason}`);
234
+ console.error('At promise:', promise);
235
+ process.exit(1);
236
+ });
237
+ }
238
+
239
+ // Close the CLI interface
240
+ close() {
241
+ if (this.rl) {
242
+ this.rl.close();
243
+ this.rl = null;
244
+ }
245
+ }
246
+
247
+ // Display a message with color coding
248
+ displayMessage(message, type = 'info') {
249
+ consoleStyler.log(type, message);
250
+ }
251
+
252
+ // Display progress indicator
253
+ displayProgress(message) {
254
+ consoleStyler.startSpinner('progress', message);
255
+ }
256
+
257
+ // Clear progress indicator
258
+ clearProgress() {
259
+ consoleStyler.succeedSpinner('progress', 'Done');
260
+ }
261
+
262
+ // Set console theme
263
+ setTheme(themeName) {
264
+ return consoleStyler.setTheme(themeName);
265
+ }
266
+
267
+ // Get available themes
268
+ getAvailableThemes() {
269
+ return consoleStyler.getAvailableThemes();
270
+ }
271
+ }
package/src/config.mjs ADDED
@@ -0,0 +1,64 @@
1
+ import dotenv from 'dotenv';
2
+ import path from 'path';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ // Load environment variables
6
+ dotenv.config();
7
+
8
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
9
+
10
+ /**
11
+ * Centralized configuration for the AI Assistant
12
+ */
13
+ export const config = {
14
+ // AI Configuration
15
+ ai: {
16
+ model: process.env.AI_MODEL || 'gpt-4o', // Default model
17
+ provider: process.env.AI_PROVIDER || '', // Auto-detected from model name if empty. Options: 'local', 'openai', 'gemini'
18
+ endpoint: process.env.AI_ENDPOINT || 'http://localhost:1234/v1/chat/completions',
19
+ temperature: parseFloat(process.env.AI_TEMPERATURE || '0.7'),
20
+ maxTokens: parseInt(process.env.AI_MAX_TOKENS || '4096', 10),
21
+ contextWindowSize: parseInt(process.env.AI_CONTEXT_WINDOW || '128000', 10),
22
+ },
23
+
24
+ // System Configuration
25
+ system: {
26
+ environment: process.env.NODE_ENV || 'development',
27
+ logLevel: process.env.LOG_LEVEL || 'info',
28
+ workspaceRoot: process.env.WORKSPACE_ROOT || path.resolve(__dirname, '..', '..'),
29
+ },
30
+
31
+ // Tool Configuration
32
+ tools: {
33
+ enableUnsafeTools: process.env.ENABLE_UNSAFE_TOOLS === 'true',
34
+ allowedFileExtensions: (process.env.ALLOWED_FILE_EXTENSIONS || '.js,.mjs,.json,.md,.txt').split(','),
35
+ },
36
+
37
+ // API Keys (accessed safely)
38
+ keys: {
39
+ openai: process.env.OPENAI_API_KEY,
40
+ anthropic: process.env.ANTHROPIC_API_KEY,
41
+ google: process.env.GOOGLE_API_KEY,
42
+ }
43
+ };
44
+
45
+ /**
46
+ * Validate required configuration
47
+ */
48
+ export function validateConfig() {
49
+ const missingKeys = [];
50
+
51
+ // Example validation - uncomment if strict validation is needed
52
+ // if (!config.keys.openai && !config.keys.anthropic) {
53
+ // missingKeys.push('OPENAI_API_KEY or ANTHROPIC_API_KEY');
54
+ // }
55
+
56
+ if (missingKeys.length > 0) {
57
+ console.warn(`Warning: Missing configuration for: ${missingKeys.join(', ')}`);
58
+ return false;
59
+ }
60
+
61
+ return true;
62
+ }
63
+
64
+ export default config;