recoder-code 2.2.1 → 2.2.3

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.
@@ -2,7 +2,9 @@
2
2
 
3
3
  const fs = require('fs');
4
4
  const path = require('path');
5
- const chalk = require('chalk');
5
+ // Handle chalk properly
6
+ const chalkModule = require('chalk');
7
+ const chalk = chalkModule.default || chalkModule;
6
8
  const { EventEmitter } = require('events');
7
9
 
8
10
  /**
@@ -482,7 +484,7 @@ class TaskManager extends EventEmitter {
482
484
  console.log(chalk.gray('🤖 Starting automation engine...'));
483
485
 
484
486
  // Set up file watchers for automated triggers
485
- if (this.contextEngine && this.contextEngine.fileWatcher) {
487
+ if (this.contextEngine && this.contextEngine.fileWatcher && typeof this.contextEngine.on === 'function') {
486
488
  this.contextEngine.on('fileChanged', (filePath, eventType) => {
487
489
  this.handleFileChangeAutomation(filePath, eventType);
488
490
  });
@@ -1080,13 +1082,19 @@ class TaskManager extends EventEmitter {
1080
1082
  this.setupGitHooksAutomation();
1081
1083
 
1082
1084
  // Dependency change automation
1083
- this.setupDependencyAutomation();
1085
+ if (typeof this.setupDependencyAutomation === 'function') {
1086
+ this.setupDependencyAutomation();
1087
+ }
1084
1088
 
1085
1089
  // Performance monitoring automation
1086
- this.setupPerformanceAutomation();
1090
+ if (typeof this.setupPerformanceAutomation === 'function') {
1091
+ this.setupPerformanceAutomation();
1092
+ }
1087
1093
 
1088
1094
  // Security monitoring automation
1089
- this.setupSecurityAutomation();
1095
+ if (typeof this.setupSecurityAutomation === 'function') {
1096
+ this.setupSecurityAutomation();
1097
+ }
1090
1098
  }
1091
1099
 
1092
1100
  /**
@@ -7,7 +7,9 @@
7
7
 
8
8
  const fs = require('fs').promises;
9
9
  const path = require('path');
10
- const chalk = require('chalk');
10
+ // Handle chalk properly
11
+ const chalkModule = require('chalk');
12
+ const chalk = chalkModule.default || chalkModule;;
11
13
  const crypto = require('crypto');
12
14
  const WebSocket = require('ws');
13
15
  const EventEmitter = require('events');
@@ -0,0 +1,391 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ // Handle chalk properly
6
+ const chalkModule = require('chalk');
7
+ const chalk = chalkModule.default || chalkModule;
8
+
9
+ /**
10
+ * Production-Ready Todo Management System for Recoder Code
11
+ * Provides visual todo management with checkboxes and status tracking
12
+ */
13
+ class TodoManager {
14
+ constructor(options = {}) {
15
+ this.todoFile = options.todoFile || path.join(process.cwd(), '.recoder-todos.json');
16
+ this.todos = [];
17
+ this.currentUser = options.user || this.getCurrentUser();
18
+ this.loadTodos();
19
+ }
20
+
21
+ getCurrentUser() {
22
+ return process.env.USER || process.env.USERNAME || 'developer';
23
+ }
24
+
25
+ /**
26
+ * Load todos from file
27
+ */
28
+ loadTodos() {
29
+ try {
30
+ if (fs.existsSync(this.todoFile)) {
31
+ const data = JSON.parse(fs.readFileSync(this.todoFile, 'utf8'));
32
+ this.todos = data.todos || [];
33
+ }
34
+ } catch (error) {
35
+ console.log(chalk.yellow(`⚠️ Could not load todos: ${error.message}`));
36
+ this.todos = [];
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Save todos to file
42
+ */
43
+ saveTodos() {
44
+ try {
45
+ const data = {
46
+ todos: this.todos,
47
+ lastUpdated: new Date().toISOString(),
48
+ user: this.currentUser
49
+ };
50
+ fs.writeFileSync(this.todoFile, JSON.stringify(data, null, 2));
51
+ } catch (error) {
52
+ console.log(chalk.red(`❌ Could not save todos: ${error.message}`));
53
+ }
54
+ }
55
+
56
+ /**
57
+ * Add a new todo
58
+ */
59
+ addTodo(content, priority = 'medium', category = 'general') {
60
+ const todo = {
61
+ id: this.generateId(),
62
+ content: content,
63
+ status: 'pending',
64
+ priority: priority,
65
+ category: category,
66
+ createdAt: new Date().toISOString(),
67
+ createdBy: this.currentUser,
68
+ updatedAt: new Date().toISOString()
69
+ };
70
+
71
+ this.todos.push(todo);
72
+ this.saveTodos();
73
+ return todo.id;
74
+ }
75
+
76
+ /**
77
+ * Update todo status
78
+ */
79
+ updateTodoStatus(id, status) {
80
+ const todo = this.todos.find(t => t.id === id);
81
+ if (todo) {
82
+ todo.status = status;
83
+ todo.updatedAt = new Date().toISOString();
84
+ this.saveTodos();
85
+ return true;
86
+ }
87
+ return false;
88
+ }
89
+
90
+ /**
91
+ * Mark todo as completed
92
+ */
93
+ completeTodo(id) {
94
+ return this.updateTodoStatus(id, 'completed');
95
+ }
96
+
97
+ /**
98
+ * Mark todo as in progress
99
+ */
100
+ startTodo(id) {
101
+ return this.updateTodoStatus(id, 'in_progress');
102
+ }
103
+
104
+ /**
105
+ * Delete a todo
106
+ */
107
+ deleteTodo(id) {
108
+ const index = this.todos.findIndex(t => t.id === id);
109
+ if (index !== -1) {
110
+ this.todos.splice(index, 1);
111
+ this.saveTodos();
112
+ return true;
113
+ }
114
+ return false;
115
+ }
116
+
117
+ /**
118
+ * Display todos with visual interface like shown
119
+ */
120
+ displayTodos(showCompleted = true) {
121
+ console.log(chalk.cyan.bold('Update Todos'));
122
+
123
+ if (this.todos.length === 0) {
124
+ console.log(chalk.gray(' ⎿ No todos found. Add one with: /todo add <task>'));
125
+ return;
126
+ }
127
+
128
+ // Group todos by status
129
+ const pending = this.todos.filter(t => t.status === 'pending');
130
+ const inProgress = this.todos.filter(t => t.status === 'in_progress');
131
+ const completed = this.todos.filter(t => t.status === 'completed');
132
+
133
+ // Display in progress first
134
+ if (inProgress.length > 0) {
135
+ console.log(chalk.yellow(' ⎿ ◐ In Progress:'));
136
+ inProgress.forEach(todo => {
137
+ console.log(chalk.yellow(` ◐ ${todo.content}`));
138
+ });
139
+ }
140
+
141
+ // Display pending todos
142
+ if (pending.length > 0) {
143
+ console.log(chalk.white(' ⎿ ☐ Pending:'));
144
+ pending.forEach(todo => {
145
+ const priorityIcon = this.getPriorityIcon(todo.priority);
146
+ console.log(chalk.white(` ☐ ${priorityIcon} ${todo.content}`));
147
+ });
148
+ }
149
+
150
+ // Display completed todos if requested
151
+ if (showCompleted && completed.length > 0) {
152
+ console.log(chalk.green(' ⎿ ☒ Completed:'));
153
+ completed.forEach(todo => {
154
+ console.log(chalk.green(` ☒ ${todo.content}`));
155
+ });
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Get priority icon
161
+ */
162
+ getPriorityIcon(priority) {
163
+ switch (priority) {
164
+ case 'high': return '🔴';
165
+ case 'medium': return '🟡';
166
+ case 'low': return '🟢';
167
+ default: return '⚪';
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Display todos by category
173
+ */
174
+ displayTodosByCategory() {
175
+ const categories = {};
176
+ this.todos.forEach(todo => {
177
+ if (!categories[todo.category]) {
178
+ categories[todo.category] = [];
179
+ }
180
+ categories[todo.category].push(todo);
181
+ });
182
+
183
+ Object.keys(categories).forEach(category => {
184
+ console.log(chalk.cyan.bold(`\n📋 ${category.toUpperCase()}`));
185
+ categories[category].forEach(todo => {
186
+ const statusIcon = this.getStatusIcon(todo.status);
187
+ const priorityIcon = this.getPriorityIcon(todo.priority);
188
+ console.log(` ${statusIcon} ${priorityIcon} ${todo.content}`);
189
+ });
190
+ });
191
+ }
192
+
193
+ /**
194
+ * Get status icon
195
+ */
196
+ getStatusIcon(status) {
197
+ switch (status) {
198
+ case 'completed': return chalk.green('☒');
199
+ case 'in_progress': return chalk.yellow('◐');
200
+ case 'pending': return chalk.white('☐');
201
+ default: return '⚪';
202
+ }
203
+ }
204
+
205
+ /**
206
+ * Generate unique ID
207
+ */
208
+ generateId() {
209
+ return Date.now().toString(36) + Math.random().toString(36).substr(2);
210
+ }
211
+
212
+ /**
213
+ * Get statistics
214
+ */
215
+ getStats() {
216
+ const total = this.todos.length;
217
+ const completed = this.todos.filter(t => t.status === 'completed').length;
218
+ const inProgress = this.todos.filter(t => t.status === 'in_progress').length;
219
+ const pending = this.todos.filter(t => t.status === 'pending').length;
220
+
221
+ return {
222
+ total,
223
+ completed,
224
+ inProgress,
225
+ pending,
226
+ completionRate: total > 0 ? Math.round((completed / total) * 100) : 0
227
+ };
228
+ }
229
+
230
+ /**
231
+ * Display statistics
232
+ */
233
+ displayStats() {
234
+ const stats = this.getStats();
235
+ console.log(chalk.cyan.bold('📊 Todo Statistics'));
236
+ console.log(chalk.white(`Total: ${stats.total}`));
237
+ console.log(chalk.green(`Completed: ${stats.completed}`));
238
+ console.log(chalk.yellow(`In Progress: ${stats.inProgress}`));
239
+ console.log(chalk.gray(`Pending: ${stats.pending}`));
240
+ console.log(chalk.blue(`Completion Rate: ${stats.completionRate}%`));
241
+ }
242
+
243
+ /**
244
+ * Clear completed todos
245
+ */
246
+ clearCompleted() {
247
+ const beforeCount = this.todos.length;
248
+ this.todos = this.todos.filter(t => t.status !== 'completed');
249
+ const removedCount = beforeCount - this.todos.length;
250
+
251
+ if (removedCount > 0) {
252
+ this.saveTodos();
253
+ console.log(chalk.green(`✅ Cleared ${removedCount} completed todos`));
254
+ } else {
255
+ console.log(chalk.gray('No completed todos to clear'));
256
+ }
257
+ }
258
+
259
+ /**
260
+ * Search todos
261
+ */
262
+ searchTodos(query) {
263
+ const results = this.todos.filter(todo =>
264
+ todo.content.toLowerCase().includes(query.toLowerCase()) ||
265
+ todo.category.toLowerCase().includes(query.toLowerCase())
266
+ );
267
+
268
+ if (results.length === 0) {
269
+ console.log(chalk.gray(`No todos found matching: ${query}`));
270
+ return;
271
+ }
272
+
273
+ console.log(chalk.cyan.bold(`🔍 Search Results for "${query}":`));
274
+ results.forEach(todo => {
275
+ const statusIcon = this.getStatusIcon(todo.status);
276
+ const priorityIcon = this.getPriorityIcon(todo.priority);
277
+ console.log(` ${statusIcon} ${priorityIcon} ${todo.content}`);
278
+ });
279
+ }
280
+
281
+ /**
282
+ * Import todos from existing TodoWrite format
283
+ */
284
+ importFromTodoWrite(todoWriteTodos) {
285
+ todoWriteTodos.forEach(todo => {
286
+ this.addTodo(todo.content, 'medium', 'imported');
287
+ if (todo.status !== 'pending') {
288
+ this.updateTodoStatus(this.todos[this.todos.length - 1].id, todo.status);
289
+ }
290
+ });
291
+ console.log(chalk.green(`✅ Imported ${todoWriteTodos.length} todos`));
292
+ }
293
+ }
294
+
295
+ module.exports = TodoManager;
296
+
297
+ // CLI interface when run directly
298
+ if (require.main === module) {
299
+ const todoManager = new TodoManager();
300
+ const command = process.argv[2];
301
+ const args = process.argv.slice(3);
302
+
303
+ switch (command) {
304
+ case 'add':
305
+ if (args.length === 0) {
306
+ console.log('Usage: todo-manager.js add <content> [priority] [category]');
307
+ process.exit(1);
308
+ }
309
+ const content = args[0];
310
+ const priority = args[1] || 'medium';
311
+ const category = args[2] || 'general';
312
+ const id = todoManager.addTodo(content, priority, category);
313
+ console.log(chalk.green(`✅ Added todo: ${id}`));
314
+ break;
315
+
316
+ case 'list':
317
+ todoManager.displayTodos();
318
+ break;
319
+
320
+ case 'complete':
321
+ if (args.length === 0) {
322
+ console.log('Usage: todo-manager.js complete <id>');
323
+ process.exit(1);
324
+ }
325
+ if (todoManager.completeTodo(args[0])) {
326
+ console.log(chalk.green('✅ Todo marked as completed'));
327
+ } else {
328
+ console.log(chalk.red('❌ Todo not found'));
329
+ }
330
+ break;
331
+
332
+ case 'start':
333
+ if (args.length === 0) {
334
+ console.log('Usage: todo-manager.js start <id>');
335
+ process.exit(1);
336
+ }
337
+ if (todoManager.startTodo(args[0])) {
338
+ console.log(chalk.yellow('◐ Todo marked as in progress'));
339
+ } else {
340
+ console.log(chalk.red('❌ Todo not found'));
341
+ }
342
+ break;
343
+
344
+ case 'delete':
345
+ if (args.length === 0) {
346
+ console.log('Usage: todo-manager.js delete <id>');
347
+ process.exit(1);
348
+ }
349
+ if (todoManager.deleteTodo(args[0])) {
350
+ console.log(chalk.green('✅ Todo deleted'));
351
+ } else {
352
+ console.log(chalk.red('❌ Todo not found'));
353
+ }
354
+ break;
355
+
356
+ case 'stats':
357
+ todoManager.displayStats();
358
+ break;
359
+
360
+ case 'clear':
361
+ todoManager.clearCompleted();
362
+ break;
363
+
364
+ case 'search':
365
+ if (args.length === 0) {
366
+ console.log('Usage: todo-manager.js search <query>');
367
+ process.exit(1);
368
+ }
369
+ todoManager.searchTodos(args[0]);
370
+ break;
371
+
372
+ case 'categories':
373
+ todoManager.displayTodosByCategory();
374
+ break;
375
+
376
+ default:
377
+ console.log(chalk.cyan.bold('Recoder Code - Todo Manager'));
378
+ console.log('');
379
+ console.log('Usage:');
380
+ console.log(' todo-manager.js add <content> [priority] [category]');
381
+ console.log(' todo-manager.js list');
382
+ console.log(' todo-manager.js complete <id>');
383
+ console.log(' todo-manager.js start <id>');
384
+ console.log(' todo-manager.js delete <id>');
385
+ console.log(' todo-manager.js stats');
386
+ console.log(' todo-manager.js clear');
387
+ console.log(' todo-manager.js search <query>');
388
+ console.log(' todo-manager.js categories');
389
+ break;
390
+ }
391
+ }
@@ -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;
@@ -7,7 +7,9 @@
7
7
 
8
8
  const { Command } = require('commander');
9
9
  const inquirer = require('inquirer');
10
- const chalk = require('chalk');
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');