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 CHANGED
@@ -30,20 +30,65 @@
30
30
 
31
31
  ## 🚀 Quick Start
32
32
 
33
- ### Get Up and Running in 30 Seconds
33
+ ### Perfect Production-Ready User Flow
34
+
35
+ **⚠️ Important:** Use `npm install -g` (not `npm i` shown on some npm pages) for global installation.
34
36
 
35
37
  ```bash
36
- # Install globally
38
+ # 1. Install globally (use full command for global install)
37
39
  npm install -g recoder-code
38
40
 
39
- # Quick setup (first time only)
40
- recoder-code --setup
41
+ # 2. Launch Recoder Code
42
+ recoder-code
43
+ ```
44
+
45
+ **That's it!** When you run `recoder-code`, you'll see:
46
+
47
+ 1. **🎨 Beautiful ASCII Logo** - Professional welcome screen
48
+ 2. **👋 Personal Setup** - Enter your name and get your free API key
49
+ 3. **🤖 Model Selection** - Choose your AI model (defaults to free DeepSeek)
50
+ 4. **🚀 Ready to Code** - Interactive AI terminal launches instantly
41
51
 
42
- # Start chatting with AI
43
- recoder-code "Hello! Create a simple calculator app"
52
+ ### First-Time User Experience
53
+
54
+ ```
55
+ ██████╗ ███████╗ ██████╗ ██████╗ ██████╗ ███████╗██████╗
56
+ ██╔══██╗██╔════╝██╔════╝██╔═══██╗██╔══██╗██╔════╝██╔══██╗
57
+ ██████╔╝█████╗ ██║ ██║ ██║██║ ██║█████╗ ██████╔╝
58
+ ██╔══██╗██╔══╝ ██║ ██║ ██║██║ ██║██╔══╝ ██╔══██╗
59
+ ██║ ██║███████╗╚██████╗╚██████╔╝██████╔╝███████╗██║ ██║
60
+ ╚═╝ ╚═╝╚══════╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝
61
+
62
+ Welcome to Recoder Code v2.2.2
63
+ Your AI-powered development companion
64
+
65
+ 👋 What's your name? John
66
+ 🔑 Enter your OpenRouter API key: [your-free-key]
67
+ 🤖 Model Selection:
68
+ 1. DeepSeek Chat v3.1 (Free) - Recommended ✨
69
+ 2. Claude 3.5 Sonnet - Advanced reasoning
70
+ 3. GPT-4 Turbo - OpenAI's latest
71
+ 4. Custom model
72
+
73
+ ✅ Setup Complete! Welcome aboard, John! 🎉
74
+ Ready for AI-powered development...
44
75
  ```
45
76
 
46
- **That's it!** No complex configuration, no API juggling, no subscription required.
77
+ ### 🔄 Returning Users
78
+
79
+ For returning users, just run `recoder-code` and you'll get:
80
+ - Instant welcome back with your saved preferences
81
+ - No setup required - jumps straight to AI chat
82
+ - Your chosen model and settings remembered
83
+
84
+ ### 🆓 Free API Key Setup
85
+
86
+ 1. Visit [OpenRouter.ai](https://openrouter.ai/keys)
87
+ 2. Sign up for free account
88
+ 3. Generate your API key
89
+ 4. Paste when prompted during setup
90
+
91
+ **Default Model:** `deepseek/deepseek-chat-v3.1:free` - Completely free, no subscription needed!
47
92
 
48
93
  ### All Available Commands
49
94
 
@@ -152,10 +197,17 @@ Recoder-Code automatically suggests new features as you become ready:
152
197
 
153
198
  ## 🛠️ Installation & Setup Options
154
199
 
200
+ > **⚠️ NPM Command Important Notice**
201
+ > Always use `npm install -g recoder-code` (full command) for global installation.
202
+ > The `npm i` shorthand shown on some npm websites is incorrect for global installs and may cause issues.
203
+
155
204
  ### Option 1: NPM Global Install (Recommended)
156
205
  ```bash
206
+ # Use full command for global install (not npm i)
157
207
  npm install -g recoder-code
158
- recoder-code --setup
208
+
209
+ # Launch with onboarding
210
+ recoder-code
159
211
  ```
160
212
 
161
213
  ### Option 2: From Source
@@ -360,9 +412,13 @@ MIT License - see [LICENSE.md](LICENSE.md) for details.
360
412
  **Ready to transform your development workflow?**
361
413
 
362
414
  ```bash
415
+ # Install globally (use full command, not npm i)
363
416
  npm install -g recoder-code
364
- recoder-code --setup
365
- recoder-code "Build me something amazing!"
417
+
418
+ # Launch with beautiful onboarding
419
+ recoder-code
420
+
421
+ # Start building amazing things!
366
422
  ```
367
423
 
368
424
  *The AI development platform that grows with you.* 🚀
@@ -1,6 +1,8 @@
1
1
  const fs = require('fs');
2
2
  const path = require('path');
3
- const chalk = require('chalk');
3
+ // Handle chalk properly
4
+ const chalkModule = require('chalk');
5
+ const chalk = chalkModule.default || chalkModule;
4
6
  const crypto = require('crypto');
5
7
 
6
8
  class CollaborationManager {
@@ -4,7 +4,9 @@ const fs = require('fs');
4
4
  const path = require('path');
5
5
  const { exec, spawn } = require('child_process');
6
6
  const { promisify } = require('util');
7
- const chalk = require('chalk');
7
+ // Handle chalk properly
8
+ const chalkModule = require('chalk');
9
+ const chalk = chalkModule.default || chalkModule;
8
10
  const { EventEmitter } = require('events');
9
11
 
10
12
  const execAsync = promisify(exec);
@@ -1,7 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  const inquirer = require('inquirer');
4
- const chalk = require('chalk');
4
+ // Handle chalk properly
5
+ const chalkModule = require('chalk');
6
+ const chalk = chalkModule.default || chalkModule;;
5
7
  const fs = require('fs');
6
8
  const path = require('path');
7
9
 
@@ -0,0 +1,216 @@
1
+ #!/usr/bin/env node
2
+
3
+ const chokidar = require('chokidar');
4
+ const chalkModule = require('chalk');
5
+ const chalk = chalkModule.default || chalkModule;
6
+
7
+ /**
8
+ * File Watcher Resource Manager
9
+ * Prevents EMFILE errors by managing file watchers globally
10
+ */
11
+ class FileWatcherManager {
12
+ constructor() {
13
+ this.watchers = new Map();
14
+ this.watchTargets = new Map(); // Track what's being watched
15
+ this.maxWatchers = 50; // Conservative limit
16
+ this.isShuttingDown = false;
17
+
18
+ // Global cleanup on process exit
19
+ process.on('exit', () => this.cleanup());
20
+ process.on('SIGINT', () => this.cleanup());
21
+ process.on('SIGTERM', () => this.cleanup());
22
+ }
23
+
24
+ /**
25
+ * Create or reuse a file watcher
26
+ */
27
+ createWatcher(id, paths, options = {}, callbacks = {}) {
28
+ // If we already have a watcher for this ID, clean it up first
29
+ if (this.watchers.has(id)) {
30
+ this.removeWatcher(id);
31
+ }
32
+
33
+ // Check watcher limit
34
+ if (this.watchers.size >= this.maxWatchers) {
35
+ console.log(chalk.yellow(`⚠️ File watcher limit reached (${this.maxWatchers}), skipping ${id}`));
36
+ return null;
37
+ }
38
+
39
+ try {
40
+ // Create watcher with safe defaults
41
+ const safeOptions = {
42
+ persistent: false, // Don't keep process alive
43
+ ignoreInitial: true,
44
+ usePolling: false,
45
+ ignorePermissionErrors: true,
46
+ ...options
47
+ };
48
+
49
+ const watcher = chokidar.watch(paths, safeOptions);
50
+
51
+ // Set up callbacks
52
+ if (callbacks.onChange) {
53
+ watcher.on('change', (path) => {
54
+ try {
55
+ callbacks.onChange(path);
56
+ } catch (error) {
57
+ if (process.env.RECODER_DEBUG === 'true') {
58
+ console.log(chalk.gray(`📁 File watcher ${id} change error:`, error.message));
59
+ }
60
+ }
61
+ });
62
+ }
63
+
64
+ if (callbacks.onAdd) {
65
+ watcher.on('add', (path) => {
66
+ try {
67
+ callbacks.onAdd(path);
68
+ } catch (error) {
69
+ if (process.env.RECODER_DEBUG === 'true') {
70
+ console.log(chalk.gray(`📁 File watcher ${id} add error:`, error.message));
71
+ }
72
+ }
73
+ });
74
+ }
75
+
76
+ if (callbacks.onUnlink) {
77
+ watcher.on('unlink', (path) => {
78
+ try {
79
+ callbacks.onUnlink(path);
80
+ } catch (error) {
81
+ if (process.env.RECODER_DEBUG === 'true') {
82
+ console.log(chalk.gray(`📁 File watcher ${id} unlink error:`, error.message));
83
+ }
84
+ }
85
+ });
86
+ }
87
+
88
+ // Handle watcher errors gracefully
89
+ watcher.on('error', (error) => {
90
+ if (process.env.RECODER_DEBUG === 'true') {
91
+ console.log(chalk.gray(`📁 File watcher ${id} error:`, error.message));
92
+ }
93
+ // Auto-remove problematic watchers
94
+ this.removeWatcher(id);
95
+ });
96
+
97
+ // Store watcher
98
+ this.watchers.set(id, watcher);
99
+ this.watchTargets.set(id, { paths, options, callbacks });
100
+
101
+ if (process.env.RECODER_DEBUG === 'true') {
102
+ console.log(chalk.gray(`📁 File watcher ${id} created (total: ${this.watchers.size})`));
103
+ }
104
+
105
+ return watcher;
106
+ } catch (error) {
107
+ console.log(chalk.yellow(`⚠️ Failed to create file watcher ${id}:`, error.message));
108
+ return null;
109
+ }
110
+ }
111
+
112
+ /**
113
+ * Remove a specific watcher
114
+ */
115
+ removeWatcher(id) {
116
+ const watcher = this.watchers.get(id);
117
+ if (watcher) {
118
+ try {
119
+ watcher.close();
120
+ } catch (error) {
121
+ // Ignore cleanup errors
122
+ }
123
+ this.watchers.delete(id);
124
+ this.watchTargets.delete(id);
125
+
126
+ if (process.env.RECODER_DEBUG === 'true') {
127
+ console.log(chalk.gray(`📁 File watcher ${id} removed (total: ${this.watchers.size})`));
128
+ }
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Get watcher by ID
134
+ */
135
+ getWatcher(id) {
136
+ return this.watchers.get(id);
137
+ }
138
+
139
+ /**
140
+ * Check if watcher exists
141
+ */
142
+ hasWatcher(id) {
143
+ return this.watchers.has(id);
144
+ }
145
+
146
+ /**
147
+ * Get watcher count
148
+ */
149
+ getWatcherCount() {
150
+ return this.watchers.size;
151
+ }
152
+
153
+ /**
154
+ * List all active watchers
155
+ */
156
+ listWatchers() {
157
+ return Array.from(this.watchers.keys());
158
+ }
159
+
160
+ /**
161
+ * Cleanup all watchers
162
+ */
163
+ cleanup() {
164
+ if (this.isShuttingDown) return;
165
+ this.isShuttingDown = true;
166
+
167
+ console.log(chalk.gray(`📁 Cleaning up ${this.watchers.size} file watchers...`));
168
+
169
+ for (const [id, watcher] of this.watchers) {
170
+ try {
171
+ watcher.close();
172
+ } catch (error) {
173
+ // Ignore cleanup errors
174
+ }
175
+ }
176
+
177
+ this.watchers.clear();
178
+ this.watchTargets.clear();
179
+ }
180
+
181
+ /**
182
+ * Health check - remove dead watchers
183
+ */
184
+ healthCheck() {
185
+ const deadWatchers = [];
186
+
187
+ for (const [id, watcher] of this.watchers) {
188
+ try {
189
+ // Try to get watched paths - if this fails, watcher is dead
190
+ if (!watcher.getWatched || Object.keys(watcher.getWatched()).length === 0) {
191
+ deadWatchers.push(id);
192
+ }
193
+ } catch (error) {
194
+ deadWatchers.push(id);
195
+ }
196
+ }
197
+
198
+ // Remove dead watchers
199
+ deadWatchers.forEach(id => this.removeWatcher(id));
200
+
201
+ if (deadWatchers.length > 0 && process.env.RECODER_DEBUG === 'true') {
202
+ console.log(chalk.gray(`📁 Removed ${deadWatchers.length} dead file watchers`));
203
+ }
204
+ }
205
+ }
206
+
207
+ // Global singleton instance
208
+ const fileWatcherManager = new FileWatcherManager();
209
+
210
+ // Periodic health check
211
+ setInterval(() => {
212
+ fileWatcherManager.healthCheck();
213
+ }, 30000); // Every 30 seconds
214
+
215
+ module.exports = FileWatcherManager;
216
+ module.exports.instance = fileWatcherManager;