recoder-code 2.2.0 ā 2.2.2
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/README.md +66 -10
- package/cli/collaboration-manager.js +3 -1
- package/cli/dev-tools-integration.js +3 -1
- package/cli/enhanced-setup.js +3 -1
- package/cli/file-watcher-manager.js +216 -0
- package/cli/interactive.js +2258 -165
- package/cli/logger.js +181 -0
- package/cli/mcp-client.js +32 -9
- package/cli/ml-training-manager.js +3 -1
- package/cli/model-manager.js +3 -1
- package/cli/natural-language-processor.js +3 -1
- package/cli/project-manager.js +3 -1
- package/cli/rules-engine.js +9 -4
- package/cli/run.js +90 -13
- package/cli/setup-wizard.js +3 -1
- package/cli/slash-commands.js +132 -5
- package/cli/task-manager.js +13 -5
- package/cli/team-collaboration.js +3 -1
- package/cli/todo-manager.js +391 -0
- package/cli/unified-error-handler.js +260 -0
- package/cli/user-experience.js +3 -1
- package/cli/user-onboarding.js +251 -0
- package/cli/vision-analyzer.js +3 -1
- package/index.js +88 -13
- package/package.json +7 -1
- package/plugins/enhanced-plugin-manager.js +31 -11
- package/scripts/performance-benchmark.js +3 -1
- package/scripts/security-audit.js +3 -1
- package/setup.js +3 -1
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const chalkModule = require('chalk');
|
|
4
|
+
const chalk = chalkModule.default || chalkModule;
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Unified Error Handler for Recoder Code
|
|
8
|
+
* Coordinates all error handling to prevent conflicts
|
|
9
|
+
*/
|
|
10
|
+
class UnifiedErrorHandler {
|
|
11
|
+
constructor() {
|
|
12
|
+
this.isInitialized = false;
|
|
13
|
+
this.errorHandlers = new Map();
|
|
14
|
+
this.errorStats = {
|
|
15
|
+
api: 0,
|
|
16
|
+
mcp: 0,
|
|
17
|
+
network: 0,
|
|
18
|
+
general: 0
|
|
19
|
+
};
|
|
20
|
+
this.suppressedErrors = new Set([
|
|
21
|
+
'ENOTFOUND your-resource.openai.azure.com', // Expected MCP connection failure
|
|
22
|
+
'ECONNREFUSED', // Expected for localhost services
|
|
23
|
+
'socket hang up', // Expected for unavailable services
|
|
24
|
+
'EMFILE: too many open files', // File watcher resource exhaustion
|
|
25
|
+
'spawn EBADF' // Process spawn errors for unavailable tools
|
|
26
|
+
]);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Initialize unified error handling (call once)
|
|
31
|
+
*/
|
|
32
|
+
initialize() {
|
|
33
|
+
if (this.isInitialized) return;
|
|
34
|
+
|
|
35
|
+
// Remove any existing handlers to prevent conflicts
|
|
36
|
+
process.removeAllListeners('unhandledRejection');
|
|
37
|
+
process.removeAllListeners('uncaughtException');
|
|
38
|
+
|
|
39
|
+
// Set up unified handlers
|
|
40
|
+
process.on('unhandledRejection', (reason, promise) => {
|
|
41
|
+
this.handleUnhandledRejection(reason, promise);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
process.on('uncaughtException', (error) => {
|
|
45
|
+
this.handleUncaughtException(error);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
this.isInitialized = true;
|
|
49
|
+
console.log(chalk.gray('š”ļø Unified error handler initialized'));
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Register a specific error handler for a domain
|
|
54
|
+
*/
|
|
55
|
+
registerHandler(domain, handler) {
|
|
56
|
+
this.errorHandlers.set(domain, handler);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Handle unhandled promise rejections
|
|
61
|
+
*/
|
|
62
|
+
handleUnhandledRejection(reason, promise) {
|
|
63
|
+
const errorInfo = this.analyzeError(reason);
|
|
64
|
+
|
|
65
|
+
// Try domain-specific handlers first
|
|
66
|
+
if (this.tryDomainHandler(errorInfo.domain, reason)) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Handle based on error type
|
|
71
|
+
switch (errorInfo.type) {
|
|
72
|
+
case 'api':
|
|
73
|
+
this.handleAPIError(reason);
|
|
74
|
+
break;
|
|
75
|
+
case 'mcp':
|
|
76
|
+
this.handleMCPError(reason);
|
|
77
|
+
break;
|
|
78
|
+
case 'network':
|
|
79
|
+
this.handleNetworkError(reason);
|
|
80
|
+
break;
|
|
81
|
+
default:
|
|
82
|
+
this.handleGenericError(reason, 'unhandled_rejection');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Handle uncaught exceptions
|
|
88
|
+
*/
|
|
89
|
+
handleUncaughtException(error) {
|
|
90
|
+
const errorInfo = this.analyzeError(error);
|
|
91
|
+
|
|
92
|
+
// Try domain-specific handlers first
|
|
93
|
+
if (this.tryDomainHandler(errorInfo.domain, error)) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Log critical error
|
|
98
|
+
console.error(chalk.red('šØ Critical Error:'), error.message);
|
|
99
|
+
if (process.env.RECODER_DEBUG === 'true') {
|
|
100
|
+
console.error(error.stack);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Don't exit process - maintain availability
|
|
104
|
+
this.errorStats.general++;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Analyze error to determine type and handling strategy
|
|
109
|
+
*/
|
|
110
|
+
analyzeError(error) {
|
|
111
|
+
const message = error?.message || error?.toString() || '';
|
|
112
|
+
const code = error?.code || '';
|
|
113
|
+
const status = error?.response?.status || error?.status;
|
|
114
|
+
|
|
115
|
+
// API errors
|
|
116
|
+
if (status || message.includes('credits') || message.includes('OpenRouter')) {
|
|
117
|
+
return { type: 'api', domain: 'openrouter', severity: 'medium' };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// MCP connection errors
|
|
121
|
+
if (message.includes('your-resource.openai.azure.com') ||
|
|
122
|
+
message.includes('localhost:8080') ||
|
|
123
|
+
code === 'ENOTFOUND' ||
|
|
124
|
+
code === 'ECONNREFUSED' ||
|
|
125
|
+
message.includes('socket hang up')) {
|
|
126
|
+
return { type: 'mcp', domain: 'mcp', severity: 'low' };
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Network errors
|
|
130
|
+
if (code === 'ENOTFOUND' || code === 'ECONNREFUSED' || message.includes('network')) {
|
|
131
|
+
return { type: 'network', domain: 'network', severity: 'medium' };
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return { type: 'generic', domain: 'general', severity: 'high' };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Try domain-specific handler
|
|
139
|
+
*/
|
|
140
|
+
tryDomainHandler(domain, error) {
|
|
141
|
+
const handler = this.errorHandlers.get(domain);
|
|
142
|
+
if (handler) {
|
|
143
|
+
try {
|
|
144
|
+
handler(error);
|
|
145
|
+
return true;
|
|
146
|
+
} catch (handlerError) {
|
|
147
|
+
console.log(chalk.yellow(`ā ļø Error handler for ${domain} failed:`, handlerError.message));
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Handle API errors (402, 401, etc.)
|
|
155
|
+
*/
|
|
156
|
+
handleAPIError(error) {
|
|
157
|
+
const status = error?.response?.status || error?.status;
|
|
158
|
+
|
|
159
|
+
if (status) {
|
|
160
|
+
switch (status) {
|
|
161
|
+
case 401:
|
|
162
|
+
console.error(chalk.red('š Authentication failed - check your API key'));
|
|
163
|
+
break;
|
|
164
|
+
case 402:
|
|
165
|
+
console.error(chalk.yellow('š³ Insufficient credits - add credits to your account'));
|
|
166
|
+
break;
|
|
167
|
+
case 429:
|
|
168
|
+
console.error(chalk.yellow('ā±ļø Rate limited - please wait before trying again'));
|
|
169
|
+
break;
|
|
170
|
+
default:
|
|
171
|
+
console.error(chalk.red(`š API Error (${status}):`, error.message));
|
|
172
|
+
}
|
|
173
|
+
} else {
|
|
174
|
+
console.error(chalk.red('š API Error:'), error.message);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
this.errorStats.api++;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Handle MCP connection errors (graceful degradation)
|
|
182
|
+
*/
|
|
183
|
+
handleMCPError(error) {
|
|
184
|
+
const message = error?.message || error?.toString();
|
|
185
|
+
|
|
186
|
+
// Check if this is a suppressed (expected) error
|
|
187
|
+
if (this.suppressedErrors.has(message) ||
|
|
188
|
+
this.suppressedErrors.some(suppressed => message.includes(suppressed))) {
|
|
189
|
+
// Silently track but don't display
|
|
190
|
+
this.errorStats.mcp++;
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Log non-critical MCP errors quietly
|
|
195
|
+
if (process.env.RECODER_DEBUG === 'true') {
|
|
196
|
+
console.log(chalk.gray('š MCP service unavailable:'), message);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
this.errorStats.mcp++;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Handle network errors
|
|
204
|
+
*/
|
|
205
|
+
handleNetworkError(error) {
|
|
206
|
+
const message = error?.message || error?.toString();
|
|
207
|
+
|
|
208
|
+
// Check if this is a suppressed error first
|
|
209
|
+
if (this.suppressedErrors.has(message) ||
|
|
210
|
+
this.suppressedErrors.some(suppressed => message.includes(suppressed))) {
|
|
211
|
+
this.errorStats.network++;
|
|
212
|
+
return; // Silently handle
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
console.log(chalk.yellow('š Network issue detected - some features may be limited'));
|
|
216
|
+
if (process.env.RECODER_DEBUG === 'true') {
|
|
217
|
+
console.log(chalk.gray('Details:'), error.message);
|
|
218
|
+
}
|
|
219
|
+
this.errorStats.network++;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Handle generic errors
|
|
224
|
+
*/
|
|
225
|
+
handleGenericError(error, type = 'generic') {
|
|
226
|
+
console.error(chalk.red('ā ļø Error:'), error?.message || error);
|
|
227
|
+
if (process.env.RECODER_DEBUG === 'true' && error?.stack) {
|
|
228
|
+
console.error(chalk.gray('Stack:'), error.stack);
|
|
229
|
+
}
|
|
230
|
+
this.errorStats.general++;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/**
|
|
234
|
+
* Get error statistics
|
|
235
|
+
*/
|
|
236
|
+
getStats() {
|
|
237
|
+
return { ...this.errorStats };
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Reset error statistics
|
|
242
|
+
*/
|
|
243
|
+
resetStats() {
|
|
244
|
+
this.errorStats = { api: 0, mcp: 0, network: 0, general: 0 };
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Check if system is healthy (low error rates)
|
|
249
|
+
*/
|
|
250
|
+
isHealthy() {
|
|
251
|
+
const total = Object.values(this.errorStats).reduce((a, b) => a + b, 0);
|
|
252
|
+
return total < 10 && this.errorStats.general < 3;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// Global singleton instance
|
|
257
|
+
const unifiedErrorHandler = new UnifiedErrorHandler();
|
|
258
|
+
|
|
259
|
+
module.exports = UnifiedErrorHandler;
|
|
260
|
+
module.exports.instance = unifiedErrorHandler;
|
package/cli/user-experience.js
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
|
|
8
8
|
const { Command } = require('commander');
|
|
9
9
|
const inquirer = require('inquirer');
|
|
10
|
-
|
|
10
|
+
// Handle chalk properly
|
|
11
|
+
const chalkModule = require('chalk');
|
|
12
|
+
const chalk = chalkModule.default || chalkModule;
|
|
11
13
|
const axios = require('axios');
|
|
12
14
|
const fs = require('fs');
|
|
13
15
|
const path = require('path');
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const readline = require('readline');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
6
|
+
const chalkModule = require('chalk');
|
|
7
|
+
const chalk = chalkModule.default || chalkModule;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* User Onboarding for Recoder Code
|
|
11
|
+
* Handles first-time user setup with proper welcome flow
|
|
12
|
+
*/
|
|
13
|
+
class UserOnboarding {
|
|
14
|
+
constructor() {
|
|
15
|
+
this.rl = readline.createInterface({
|
|
16
|
+
input: process.stdin,
|
|
17
|
+
output: process.stdout
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
this.configDir = path.join(require('os').homedir(), '.recoder-code');
|
|
21
|
+
this.configFile = path.join(this.configDir, 'config.json');
|
|
22
|
+
this.defaultConfig = {
|
|
23
|
+
apiKey: '',
|
|
24
|
+
model: 'deepseek/deepseek-chat-v3.1:free',
|
|
25
|
+
userName: '',
|
|
26
|
+
setupCompleted: false,
|
|
27
|
+
firstRun: true
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Show ASCII logo and welcome message
|
|
33
|
+
*/
|
|
34
|
+
showWelcome() {
|
|
35
|
+
console.clear();
|
|
36
|
+
console.log(chalk.cyan(`
|
|
37
|
+
āāāāāāā āāāāāāāā āāāāāāā āāāāāāā āāāāāāā āāāāāāāāāāāāāāā
|
|
38
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
39
|
+
āāāāāāāāāāāāāā āāā āāā āāāāāā āāāāāāāāā āāāāāāāā
|
|
40
|
+
āāāāāāāāāāāāāā āāā āāā āāāāāā āāāāāāāāā āāāāāāāā
|
|
41
|
+
āāā āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā āāā
|
|
42
|
+
āāā āāāāāāāāāāā āāāāāāā āāāāāāā āāāāāāā āāāāāāāāāāā āāā
|
|
43
|
+
|
|
44
|
+
`));
|
|
45
|
+
|
|
46
|
+
console.log(chalk.white.bold('Welcome to Recoder Code v2.2.2'));
|
|
47
|
+
console.log(chalk.gray('Your AI-powered development companion\n'));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Check if user needs onboarding
|
|
52
|
+
*/
|
|
53
|
+
needsOnboarding() {
|
|
54
|
+
if (!fs.existsSync(this.configFile)) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
const config = JSON.parse(fs.readFileSync(this.configFile, 'utf8'));
|
|
60
|
+
return !config.setupCompleted || !config.apiKey;
|
|
61
|
+
} catch (error) {
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Get user's name
|
|
68
|
+
*/
|
|
69
|
+
async getUserName() {
|
|
70
|
+
return new Promise((resolve) => {
|
|
71
|
+
this.rl.question(chalk.cyan('š What\'s your name? '), (name) => {
|
|
72
|
+
resolve(name.trim() || 'Developer');
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Get API key from user
|
|
79
|
+
*/
|
|
80
|
+
async getApiKey() {
|
|
81
|
+
console.log(chalk.yellow('\nš API Key Setup'));
|
|
82
|
+
console.log(chalk.white('To use Recoder Code, you need an API key from OpenRouter.'));
|
|
83
|
+
console.log(chalk.gray('š” Get your free API key at: https://openrouter.ai/keys\n'));
|
|
84
|
+
|
|
85
|
+
return new Promise((resolve) => {
|
|
86
|
+
this.rl.question(chalk.cyan('Enter your OpenRouter API key: '), (apiKey) => {
|
|
87
|
+
resolve(apiKey.trim());
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Show model selection
|
|
94
|
+
*/
|
|
95
|
+
async selectModel() {
|
|
96
|
+
console.log(chalk.yellow('\nš¤ Model Selection'));
|
|
97
|
+
console.log(chalk.white('Choose your preferred AI model:'));
|
|
98
|
+
console.log(chalk.gray('1. DeepSeek Chat v3.1 (Free) - Recommended for most users'));
|
|
99
|
+
console.log(chalk.gray('2. Claude 3.5 Sonnet - Advanced reasoning and coding'));
|
|
100
|
+
console.log(chalk.gray('3. GPT-4 Turbo - OpenAI\'s latest model'));
|
|
101
|
+
console.log(chalk.gray('4. Custom model - Enter your own model name\n'));
|
|
102
|
+
|
|
103
|
+
return new Promise((resolve) => {
|
|
104
|
+
this.rl.question(chalk.cyan('Select option (1-4) [1]: '), (choice) => {
|
|
105
|
+
switch (choice.trim() || '1') {
|
|
106
|
+
case '1':
|
|
107
|
+
resolve('deepseek/deepseek-chat-v3.1:free');
|
|
108
|
+
break;
|
|
109
|
+
case '2':
|
|
110
|
+
resolve('anthropic/claude-3.5-sonnet');
|
|
111
|
+
break;
|
|
112
|
+
case '3':
|
|
113
|
+
resolve('openai/gpt-4-turbo');
|
|
114
|
+
break;
|
|
115
|
+
case '4':
|
|
116
|
+
this.rl.question(chalk.cyan('Enter custom model name: '), (customModel) => {
|
|
117
|
+
resolve(customModel.trim() || 'deepseek/deepseek-chat-v3.1:free');
|
|
118
|
+
});
|
|
119
|
+
break;
|
|
120
|
+
default:
|
|
121
|
+
resolve('deepseek/deepseek-chat-v3.1:free');
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Save configuration
|
|
129
|
+
*/
|
|
130
|
+
saveConfig(config) {
|
|
131
|
+
try {
|
|
132
|
+
// Create config directory if it doesn't exist
|
|
133
|
+
if (!fs.existsSync(this.configDir)) {
|
|
134
|
+
fs.mkdirSync(this.configDir, { recursive: true });
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Save configuration
|
|
138
|
+
fs.writeFileSync(this.configFile, JSON.stringify(config, null, 2));
|
|
139
|
+
return true;
|
|
140
|
+
} catch (error) {
|
|
141
|
+
console.log(chalk.red(`ā Failed to save configuration: ${error.message}`));
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Load existing configuration
|
|
148
|
+
*/
|
|
149
|
+
loadConfig() {
|
|
150
|
+
try {
|
|
151
|
+
if (fs.existsSync(this.configFile)) {
|
|
152
|
+
return JSON.parse(fs.readFileSync(this.configFile, 'utf8'));
|
|
153
|
+
}
|
|
154
|
+
} catch (error) {
|
|
155
|
+
// Return default if config can't be loaded
|
|
156
|
+
}
|
|
157
|
+
return { ...this.defaultConfig };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Show setup completion
|
|
162
|
+
*/
|
|
163
|
+
showCompletion(userName, model) {
|
|
164
|
+
console.log(chalk.green('\nā
Setup Complete!'));
|
|
165
|
+
console.log(chalk.white(`Welcome aboard, ${userName}! š`));
|
|
166
|
+
console.log(chalk.gray(`Model: ${model}`));
|
|
167
|
+
console.log(chalk.gray('Configuration saved to ~/.recoder-code/config.json\n'));
|
|
168
|
+
|
|
169
|
+
console.log(chalk.cyan('š Quick Start:'));
|
|
170
|
+
console.log(chalk.white('⢠Type your questions or requests'));
|
|
171
|
+
console.log(chalk.white('⢠Use /help for available commands'));
|
|
172
|
+
console.log(chalk.white('⢠Press Ctrl+C to exit anytime\n'));
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Run complete onboarding flow
|
|
177
|
+
*/
|
|
178
|
+
async runOnboarding() {
|
|
179
|
+
this.showWelcome();
|
|
180
|
+
|
|
181
|
+
const userName = await this.getUserName();
|
|
182
|
+
const apiKey = await this.getApiKey();
|
|
183
|
+
|
|
184
|
+
if (!apiKey) {
|
|
185
|
+
console.log(chalk.red('\nā API key is required to use Recoder Code.'));
|
|
186
|
+
console.log(chalk.yellow('Get your free key at: https://openrouter.ai/keys'));
|
|
187
|
+
this.rl.close();
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const model = await this.selectModel();
|
|
192
|
+
|
|
193
|
+
const config = {
|
|
194
|
+
...this.defaultConfig,
|
|
195
|
+
apiKey,
|
|
196
|
+
model,
|
|
197
|
+
userName,
|
|
198
|
+
setupCompleted: true,
|
|
199
|
+
firstRun: false,
|
|
200
|
+
setupDate: new Date().toISOString()
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
if (this.saveConfig(config)) {
|
|
204
|
+
this.showCompletion(userName, model);
|
|
205
|
+
} else {
|
|
206
|
+
console.log(chalk.red('\nā Setup failed. Please try again.'));
|
|
207
|
+
this.rl.close();
|
|
208
|
+
process.exit(1);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Set environment variables for immediate use
|
|
212
|
+
process.env.OPENROUTER_API_KEY = config.apiKey;
|
|
213
|
+
process.env.OPENROUTER_MODEL = config.model;
|
|
214
|
+
process.env.RECODER_USER_MODE = 'true'; // Suppress technical messages
|
|
215
|
+
|
|
216
|
+
this.rl.close();
|
|
217
|
+
return config;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* Quick start for returning users
|
|
222
|
+
*/
|
|
223
|
+
async quickStart() {
|
|
224
|
+
const config = this.loadConfig();
|
|
225
|
+
|
|
226
|
+
if (!config.setupCompleted || !config.apiKey) {
|
|
227
|
+
return await this.runOnboarding();
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// Show welcome for returning users
|
|
231
|
+
this.showWelcome();
|
|
232
|
+
console.log(chalk.green(`Welcome back, ${config.userName || 'Developer'}! š`));
|
|
233
|
+
console.log(chalk.gray(`Using model: ${config.model}\n`));
|
|
234
|
+
|
|
235
|
+
// Set environment variables for immediate use
|
|
236
|
+
process.env.OPENROUTER_API_KEY = config.apiKey;
|
|
237
|
+
process.env.OPENROUTER_MODEL = config.model;
|
|
238
|
+
process.env.RECODER_USER_MODE = 'true'; // Suppress technical messages
|
|
239
|
+
|
|
240
|
+
return config;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Close readline interface
|
|
245
|
+
*/
|
|
246
|
+
close() {
|
|
247
|
+
this.rl.close();
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
module.exports = UserOnboarding;
|
package/cli/vision-analyzer.js
CHANGED
package/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
3
|
* Recoder Code - AI Development Platform
|
|
4
|
-
*
|
|
4
|
+
* Production-ready main entry point for programmatic usage
|
|
5
5
|
*
|
|
6
6
|
* For CLI usage: Use `recoder-code` command
|
|
7
7
|
* For programmatic usage: require('recoder-code')
|
|
@@ -10,6 +10,19 @@
|
|
|
10
10
|
const path = require('path');
|
|
11
11
|
const config = require('./config.js');
|
|
12
12
|
|
|
13
|
+
// Handle chalk properly for production
|
|
14
|
+
const chalkModule = require('chalk');
|
|
15
|
+
const chalk = chalkModule.default || chalkModule;
|
|
16
|
+
|
|
17
|
+
// Initialize unified error handling
|
|
18
|
+
const UnifiedErrorHandler = require('./cli/unified-error-handler.js');
|
|
19
|
+
const errorHandler = UnifiedErrorHandler.instance;
|
|
20
|
+
|
|
21
|
+
// Only initialize in non-test environments
|
|
22
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
23
|
+
errorHandler.initialize();
|
|
24
|
+
}
|
|
25
|
+
|
|
13
26
|
// Main RecoderCode class for programmatic usage
|
|
14
27
|
class RecoderCode {
|
|
15
28
|
constructor(options = {}) {
|
|
@@ -82,22 +95,81 @@ class RecoderCode {
|
|
|
82
95
|
const discovery = new ProgressiveDiscovery();
|
|
83
96
|
return discovery.getProgressSummary();
|
|
84
97
|
}
|
|
98
|
+
|
|
99
|
+
// Todo management
|
|
100
|
+
async getTodoManager() {
|
|
101
|
+
const TodoManager = require('./cli/todo-manager.js');
|
|
102
|
+
return new TodoManager({ user: this.currentUser || 'developer' });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Production health check
|
|
106
|
+
async healthCheck() {
|
|
107
|
+
const checks = {
|
|
108
|
+
dependencies: false,
|
|
109
|
+
configuration: false,
|
|
110
|
+
services: false,
|
|
111
|
+
todos: false
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
// Check dependencies
|
|
116
|
+
require('chalk');
|
|
117
|
+
require('openai');
|
|
118
|
+
checks.dependencies = true;
|
|
119
|
+
} catch (error) {
|
|
120
|
+
console.error('Dependency check failed:', error.message);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
try {
|
|
124
|
+
// Check configuration
|
|
125
|
+
const config = require('./config.js');
|
|
126
|
+
checks.configuration = !!config;
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.error('Configuration check failed:', error.message);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
try {
|
|
132
|
+
// Check services
|
|
133
|
+
const status = await this.getServicesStatus();
|
|
134
|
+
checks.services = true;
|
|
135
|
+
} catch (error) {
|
|
136
|
+
console.error('Services check failed:', error.message);
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
try {
|
|
140
|
+
// Check todo system
|
|
141
|
+
const todoManager = await this.getTodoManager();
|
|
142
|
+
checks.todos = true;
|
|
143
|
+
} catch (error) {
|
|
144
|
+
console.error('Todo system check failed:', error.message);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return checks;
|
|
148
|
+
}
|
|
85
149
|
}
|
|
86
150
|
|
|
87
151
|
// Legacy compatibility - simple OpenAI client function
|
|
88
152
|
async function legacyMain() {
|
|
89
|
-
const OpenAI = require('openai');
|
|
90
|
-
|
|
91
|
-
const openai = new OpenAI({
|
|
92
|
-
baseURL: config.apiUrl,
|
|
93
|
-
apiKey: config.openRouterApiKey,
|
|
94
|
-
defaultHeaders: {
|
|
95
|
-
'HTTP-Referer': config.siteUrl || 'https://recoder.xyz',
|
|
96
|
-
'X-Title': config.siteName || 'Recoder-Code',
|
|
97
|
-
},
|
|
98
|
-
});
|
|
99
|
-
|
|
100
153
|
try {
|
|
154
|
+
// Check if API key is configured
|
|
155
|
+
if (!config.openRouterApiKey) {
|
|
156
|
+
console.log(chalk.yellow('ā ļø No API key configured.'));
|
|
157
|
+
console.log(chalk.white('To configure: export OPENROUTER_API_KEY="your-key"'));
|
|
158
|
+
console.log(chalk.white('Or run: recoder-code setup'));
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const OpenAI = require('openai');
|
|
163
|
+
|
|
164
|
+
const openai = new OpenAI({
|
|
165
|
+
baseURL: config.apiUrl,
|
|
166
|
+
apiKey: config.openRouterApiKey,
|
|
167
|
+
defaultHeaders: {
|
|
168
|
+
'HTTP-Referer': config.siteUrl || 'https://recoder.xyz',
|
|
169
|
+
'X-Title': config.siteName || 'Recoder-Code',
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
|
|
101
173
|
const completion = await openai.chat.completions.create({
|
|
102
174
|
model: config.model || 'deepseek/deepseek-chat',
|
|
103
175
|
messages: [
|
|
@@ -110,7 +182,10 @@ async function legacyMain() {
|
|
|
110
182
|
|
|
111
183
|
console.log(completion.choices[0].message.content);
|
|
112
184
|
} catch (error) {
|
|
113
|
-
console.error('API request failed:', error.message);
|
|
185
|
+
console.error(chalk.red('ā API request failed:'), error.message);
|
|
186
|
+
if (error.message.includes('credentials') || error.message.includes('apiKey')) {
|
|
187
|
+
console.log(chalk.yellow('š” Tip: Set your API key with: export OPENROUTER_API_KEY="your-key"'));
|
|
188
|
+
}
|
|
114
189
|
}
|
|
115
190
|
}
|
|
116
191
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "recoder-code",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.2",
|
|
4
4
|
"description": "Complete AI-powered development platform with ML model training, plugin registry, real-time collaboration, monitoring, infrastructure automation, and enterprise deployment capabilities",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
@@ -28,6 +28,12 @@
|
|
|
28
28
|
"security:audit": "npm audit --audit-level moderate",
|
|
29
29
|
"optimize": "node scripts/optimize-package.js",
|
|
30
30
|
"health-check": "node scripts/health-check.js",
|
|
31
|
+
"todo": "node cli/todo-manager.js",
|
|
32
|
+
"todo:list": "node cli/todo-manager.js list",
|
|
33
|
+
"todo:stats": "node cli/todo-manager.js stats",
|
|
34
|
+
"production:check": "npm run test && npm run lint && npm run typecheck && npm run security:audit",
|
|
35
|
+
"production:bundle": "npm run production:check && npm run build:production",
|
|
36
|
+
"production:deploy": "npm run production:bundle && npm publish --access public",
|
|
31
37
|
"postinstall": "node -e \"console.log('\\nš Recoder-Code installed successfully!\\n\\nā
Quick Start:\\n recoder-code\\n\\nš” If command not found, run setup:\\n npx recoder-code setup:global\\n\\nOr add npm global bin to PATH manually:\\n echo \\\"export PATH=\\\\\\\"$(npm config get prefix)/bin:$PATH\\\\\\\"\\\" >> ~/.zshrc\\n source ~/.zshrc\\n\\nš Then try: recoder-code --help\\n')\"",
|
|
32
38
|
"prepare": "echo 'Package prepared for distribution'",
|
|
33
39
|
"prepublishOnly": "npm run prepare && npm run security:audit"
|