claude-comms 1.0.0 → 1.0.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/CHANGELOG.md +53 -0
- package/README.md +64 -23
- package/bin/claude-setup.js +118 -38
- package/package.json +66 -19
- package/src/cli/index.js +30 -0
- package/src/cli/interfaces.js +386 -0
- package/src/cli/parser.js +158 -0
- package/src/cli/prompts.js +317 -0
- package/src/cli/runner.js +436 -0
- package/src/fetcher/github.js +676 -0
- package/src/index.js +221 -0
- package/src/installer/dependency-check.js +19 -0
- package/src/installer/file-writer.js +648 -0
- package/src/orchestrator/installer.js +849 -0
- package/src/orchestrator/main.js +267 -0
- package/src/orchestrator/mocks/index.js +388 -0
- package/src/utils/config.js +430 -0
- package/src/utils/constants.js +397 -0
- package/src/utils/errors.js +361 -0
- package/src/utils/index.js +46 -0
- package/src/utils/logger.js +177 -0
- package/src/utils/platform.js +362 -0
- package/src/utils/retry.js +358 -0
- package/templates/settings.local.json +1 -0
- package/templates/get_unread_messages.py +0 -54
- package/templates/send_message.py +0 -75
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Custom error classes for standardized error handling
|
|
3
|
+
* Provides consistent error codes and messages across the NPX installer
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Base installer error with error codes and details
|
|
8
|
+
*/
|
|
9
|
+
class InstallerError extends Error {
|
|
10
|
+
constructor(message, code, details = null, cause = null) {
|
|
11
|
+
super(message);
|
|
12
|
+
this.name = this.constructor.name;
|
|
13
|
+
this.code = code;
|
|
14
|
+
this.details = details;
|
|
15
|
+
this.cause = cause;
|
|
16
|
+
this.timestamp = new Date().toISOString();
|
|
17
|
+
|
|
18
|
+
// Maintain stack trace for V8
|
|
19
|
+
if (Error.captureStackTrace) {
|
|
20
|
+
Error.captureStackTrace(this, this.constructor);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Convert error to JSON for logging/debugging
|
|
26
|
+
*/
|
|
27
|
+
toJSON() {
|
|
28
|
+
return {
|
|
29
|
+
name: this.name,
|
|
30
|
+
message: this.message,
|
|
31
|
+
code: this.code,
|
|
32
|
+
details: this.details,
|
|
33
|
+
timestamp: this.timestamp,
|
|
34
|
+
stack: this.stack
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get user-friendly error message
|
|
40
|
+
*/
|
|
41
|
+
getUserMessage() {
|
|
42
|
+
return this.message;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Check if error is recoverable
|
|
47
|
+
*/
|
|
48
|
+
isRecoverable() {
|
|
49
|
+
return false; // Override in subclasses
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* GitHub API related errors
|
|
55
|
+
*/
|
|
56
|
+
class GitHubAPIError extends InstallerError {
|
|
57
|
+
constructor(message, details = null, cause = null) {
|
|
58
|
+
const errorCode = GitHubAPIError.getErrorCode(details);
|
|
59
|
+
super(message, errorCode, details, cause);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
static getErrorCode(details) {
|
|
63
|
+
if (details?.status === 403 && details?.headers?.['x-ratelimit-remaining'] === '0') {
|
|
64
|
+
return 'GITHUB_RATE_LIMIT';
|
|
65
|
+
}
|
|
66
|
+
if (details?.status === 404) {
|
|
67
|
+
return 'GITHUB_NOT_FOUND';
|
|
68
|
+
}
|
|
69
|
+
if (details?.status >= 500) {
|
|
70
|
+
return 'GITHUB_SERVER_ERROR';
|
|
71
|
+
}
|
|
72
|
+
if (details?.code === 'ENOTFOUND' || details?.code === 'ECONNREFUSED') {
|
|
73
|
+
return 'GITHUB_CONNECTION_ERROR';
|
|
74
|
+
}
|
|
75
|
+
return 'GITHUB_API_ERROR';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
getUserMessage() {
|
|
79
|
+
switch (this.code) {
|
|
80
|
+
case 'GITHUB_RATE_LIMIT':
|
|
81
|
+
return 'GitHub API rate limit exceeded. Please wait a few minutes and try again, or use a GitHub token for higher limits.';
|
|
82
|
+
case 'GITHUB_NOT_FOUND':
|
|
83
|
+
return 'Repository or file not found on GitHub. Please check the repository URL and try again.';
|
|
84
|
+
case 'GITHUB_SERVER_ERROR':
|
|
85
|
+
return 'GitHub is experiencing server issues. Please try again in a few minutes.';
|
|
86
|
+
case 'GITHUB_CONNECTION_ERROR':
|
|
87
|
+
return 'Unable to connect to GitHub. Please check your internet connection and try again.';
|
|
88
|
+
default:
|
|
89
|
+
return 'Failed to fetch files from GitHub. Please try again or check your internet connection.';
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
isRecoverable() {
|
|
94
|
+
return ['GITHUB_RATE_LIMIT', 'GITHUB_SERVER_ERROR', 'GITHUB_CONNECTION_ERROR'].includes(this.code);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* File system operation errors
|
|
100
|
+
*/
|
|
101
|
+
class FileSystemError extends InstallerError {
|
|
102
|
+
constructor(message, details = null, cause = null) {
|
|
103
|
+
const errorCode = FileSystemError.getErrorCode(details);
|
|
104
|
+
super(message, errorCode, details, cause);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
static getErrorCode(details) {
|
|
108
|
+
if (details?.code === 'EACCES' || details?.code === 'EPERM') {
|
|
109
|
+
return 'FILESYSTEM_PERMISSION_DENIED';
|
|
110
|
+
}
|
|
111
|
+
if (details?.code === 'ENOENT') {
|
|
112
|
+
return 'FILESYSTEM_NOT_FOUND';
|
|
113
|
+
}
|
|
114
|
+
if (details?.code === 'EEXIST') {
|
|
115
|
+
return 'FILESYSTEM_ALREADY_EXISTS';
|
|
116
|
+
}
|
|
117
|
+
if (details?.code === 'ENOSPC') {
|
|
118
|
+
return 'FILESYSTEM_NO_SPACE';
|
|
119
|
+
}
|
|
120
|
+
if (details?.code === 'EMFILE' || details?.code === 'ENFILE') {
|
|
121
|
+
return 'FILESYSTEM_TOO_MANY_FILES';
|
|
122
|
+
}
|
|
123
|
+
return 'FILESYSTEM_ERROR';
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
getUserMessage() {
|
|
127
|
+
switch (this.code) {
|
|
128
|
+
case 'FILESYSTEM_PERMISSION_DENIED':
|
|
129
|
+
return 'Permission denied. Please run with appropriate permissions or choose a different directory.';
|
|
130
|
+
case 'FILESYSTEM_NOT_FOUND':
|
|
131
|
+
return 'Directory or file not found. Please check the path and try again.';
|
|
132
|
+
case 'FILESYSTEM_ALREADY_EXISTS':
|
|
133
|
+
return 'File or directory already exists. Use --force to overwrite or choose a different location.';
|
|
134
|
+
case 'FILESYSTEM_NO_SPACE':
|
|
135
|
+
return 'Not enough disk space to complete the installation.';
|
|
136
|
+
case 'FILESYSTEM_TOO_MANY_FILES':
|
|
137
|
+
return 'Too many open files. Please close some applications and try again.';
|
|
138
|
+
default:
|
|
139
|
+
return 'File system operation failed. Please check permissions and available space.';
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
isRecoverable() {
|
|
144
|
+
return ['FILESYSTEM_TOO_MANY_FILES'].includes(this.code);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Network related errors
|
|
150
|
+
*/
|
|
151
|
+
class NetworkError extends InstallerError {
|
|
152
|
+
constructor(message, details = null, cause = null) {
|
|
153
|
+
const errorCode = NetworkError.getErrorCode(details);
|
|
154
|
+
super(message, errorCode, details, cause);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
static getErrorCode(details) {
|
|
158
|
+
if (details?.code === 'ENOTFOUND') {
|
|
159
|
+
return 'NETWORK_DNS_ERROR';
|
|
160
|
+
}
|
|
161
|
+
if (details?.code === 'ECONNREFUSED') {
|
|
162
|
+
return 'NETWORK_CONNECTION_REFUSED';
|
|
163
|
+
}
|
|
164
|
+
if (details?.code === 'ETIMEDOUT') {
|
|
165
|
+
return 'NETWORK_TIMEOUT';
|
|
166
|
+
}
|
|
167
|
+
if (details?.code === 'CERT_HAS_EXPIRED' || details?.code === 'UNABLE_TO_VERIFY_LEAF_SIGNATURE') {
|
|
168
|
+
return 'NETWORK_SSL_ERROR';
|
|
169
|
+
}
|
|
170
|
+
return 'NETWORK_ERROR';
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
getUserMessage() {
|
|
174
|
+
switch (this.code) {
|
|
175
|
+
case 'NETWORK_DNS_ERROR':
|
|
176
|
+
return 'DNS resolution failed. Please check your internet connection and DNS settings.';
|
|
177
|
+
case 'NETWORK_CONNECTION_REFUSED':
|
|
178
|
+
return 'Connection refused. The server may be down or unreachable.';
|
|
179
|
+
case 'NETWORK_TIMEOUT':
|
|
180
|
+
return 'Network request timed out. Please check your internet connection and try again.';
|
|
181
|
+
case 'NETWORK_SSL_ERROR':
|
|
182
|
+
return 'SSL certificate error. Please check your system time and certificate store.';
|
|
183
|
+
default:
|
|
184
|
+
return 'Network error occurred. Please check your internet connection and try again.';
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
isRecoverable() {
|
|
189
|
+
return ['NETWORK_TIMEOUT', 'NETWORK_CONNECTION_REFUSED'].includes(this.code);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Input validation errors
|
|
195
|
+
*/
|
|
196
|
+
class ValidationError extends InstallerError {
|
|
197
|
+
constructor(message, field = null, details = null) {
|
|
198
|
+
super(message, 'VALIDATION_ERROR', { field, ...details });
|
|
199
|
+
this.field = field;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
getUserMessage() {
|
|
203
|
+
if (this.field) {
|
|
204
|
+
return `Invalid ${this.field}: ${this.message}`;
|
|
205
|
+
}
|
|
206
|
+
return `Validation error: ${this.message}`;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
isRecoverable() {
|
|
210
|
+
return true; // User can correct input
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Dependency check errors
|
|
216
|
+
*/
|
|
217
|
+
class DependencyError extends InstallerError {
|
|
218
|
+
constructor(message, dependency, details = null) {
|
|
219
|
+
super(message, 'DEPENDENCY_ERROR', { dependency, ...details });
|
|
220
|
+
this.dependency = dependency;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
getUserMessage() {
|
|
224
|
+
return `Missing dependency: ${this.dependency}. ${this.message}`;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
isRecoverable() {
|
|
228
|
+
return true; // User can install dependencies
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* User cancellation error
|
|
234
|
+
*/
|
|
235
|
+
class UserCancelledError extends InstallerError {
|
|
236
|
+
constructor(message = 'Installation cancelled by user') {
|
|
237
|
+
super(message, 'USER_CANCELLED');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
getUserMessage() {
|
|
241
|
+
return this.message;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
isRecoverable() {
|
|
245
|
+
return false;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
/**
|
|
250
|
+
* Configuration errors
|
|
251
|
+
*/
|
|
252
|
+
class ConfigurationError extends InstallerError {
|
|
253
|
+
constructor(message, configKey = null, details = null) {
|
|
254
|
+
super(message, 'CONFIGURATION_ERROR', { configKey, ...details });
|
|
255
|
+
this.configKey = configKey;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
getUserMessage() {
|
|
259
|
+
if (this.configKey) {
|
|
260
|
+
return `Configuration error in '${this.configKey}': ${this.message}`;
|
|
261
|
+
}
|
|
262
|
+
return `Configuration error: ${this.message}`;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
isRecoverable() {
|
|
266
|
+
return true; // User can fix configuration
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* Error factory for creating appropriate error types
|
|
272
|
+
*/
|
|
273
|
+
class ErrorFactory {
|
|
274
|
+
/**
|
|
275
|
+
* Create an error from a caught exception
|
|
276
|
+
*/
|
|
277
|
+
static fromCaught(error, context = null) {
|
|
278
|
+
if (error instanceof InstallerError) {
|
|
279
|
+
return error;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Network errors
|
|
283
|
+
if (error.code && ['ENOTFOUND', 'ECONNREFUSED', 'ETIMEDOUT'].includes(error.code)) {
|
|
284
|
+
return new NetworkError(error.message, { code: error.code, context }, error);
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// File system errors
|
|
288
|
+
if (error.code && ['EACCES', 'EPERM', 'ENOENT', 'EEXIST', 'ENOSPC'].includes(error.code)) {
|
|
289
|
+
return new FileSystemError(error.message, { code: error.code, context }, error);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// GitHub API errors (based on fetch response)
|
|
293
|
+
if (error.status || (context && context.includes('github'))) {
|
|
294
|
+
return new GitHubAPIError(error.message, { status: error.status, context }, error);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// Generic installer error
|
|
298
|
+
return new InstallerError(error.message, 'UNKNOWN_ERROR', { context }, error);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Create a GitHub API error
|
|
303
|
+
*/
|
|
304
|
+
static github(message, details) {
|
|
305
|
+
return new GitHubAPIError(message, details);
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Create a file system error
|
|
310
|
+
*/
|
|
311
|
+
static filesystem(message, details) {
|
|
312
|
+
return new FileSystemError(message, details);
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Create a network error
|
|
317
|
+
*/
|
|
318
|
+
static network(message, details) {
|
|
319
|
+
return new NetworkError(message, details);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* Create a validation error
|
|
324
|
+
*/
|
|
325
|
+
static validation(message, field, details) {
|
|
326
|
+
return new ValidationError(message, field, details);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Create a dependency error
|
|
331
|
+
*/
|
|
332
|
+
static dependency(message, dependency, details) {
|
|
333
|
+
return new DependencyError(message, dependency, details);
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* Create a user cancelled error
|
|
338
|
+
*/
|
|
339
|
+
static userCancelled(message) {
|
|
340
|
+
return new UserCancelledError(message);
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
/**
|
|
344
|
+
* Create a configuration error
|
|
345
|
+
*/
|
|
346
|
+
static configuration(message, configKey, details) {
|
|
347
|
+
return new ConfigurationError(message, configKey, details);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
module.exports = {
|
|
352
|
+
InstallerError,
|
|
353
|
+
GitHubAPIError,
|
|
354
|
+
FileSystemError,
|
|
355
|
+
NetworkError,
|
|
356
|
+
ValidationError,
|
|
357
|
+
DependencyError,
|
|
358
|
+
UserCancelledError,
|
|
359
|
+
ConfigurationError,
|
|
360
|
+
ErrorFactory
|
|
361
|
+
};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NPX Installer Utilities Module
|
|
3
|
+
* Centralized export for all utility functions and classes
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
// Core utilities
|
|
7
|
+
const logger = require('./logger');
|
|
8
|
+
const errors = require('./errors');
|
|
9
|
+
const platform = require('./platform');
|
|
10
|
+
const config = require('./config');
|
|
11
|
+
const retry = require('./retry');
|
|
12
|
+
const constants = require('./constants');
|
|
13
|
+
|
|
14
|
+
// Re-export all utilities for team integration
|
|
15
|
+
module.exports = {
|
|
16
|
+
// Logger utilities
|
|
17
|
+
logger,
|
|
18
|
+
Logger: logger.Logger,
|
|
19
|
+
|
|
20
|
+
// Error handling
|
|
21
|
+
...errors,
|
|
22
|
+
ErrorFactory: errors.ErrorFactory,
|
|
23
|
+
|
|
24
|
+
// Platform utilities
|
|
25
|
+
platform,
|
|
26
|
+
Platform: platform.Platform,
|
|
27
|
+
|
|
28
|
+
// Configuration management
|
|
29
|
+
config,
|
|
30
|
+
Config: config.Config,
|
|
31
|
+
|
|
32
|
+
// Retry mechanisms
|
|
33
|
+
retry: retry.retry,
|
|
34
|
+
RetryWrapper: retry.RetryWrapper,
|
|
35
|
+
CircuitBreaker: retry.CircuitBreaker,
|
|
36
|
+
retryPresets: retry.retryPresets,
|
|
37
|
+
|
|
38
|
+
// Constants and configuration
|
|
39
|
+
constants,
|
|
40
|
+
|
|
41
|
+
// Convenience exports for common patterns
|
|
42
|
+
GITHUB_URLS: constants.GITHUB_URLS,
|
|
43
|
+
ERROR_CODES: constants.ERROR_CODES,
|
|
44
|
+
FILE_PATHS: constants.FILE_PATHS,
|
|
45
|
+
RETRY_CONFIG: constants.RETRY_CONFIG
|
|
46
|
+
};
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logger utility for colored console output
|
|
3
|
+
* Provides consistent logging across the NPX installer with chalk-based colors
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
const chalk = require('chalk');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Log levels with corresponding colors and symbols
|
|
10
|
+
*/
|
|
11
|
+
const LOG_LEVELS = {
|
|
12
|
+
DEBUG: { color: chalk.gray, symbol: '🔧', level: 0 },
|
|
13
|
+
INFO: { color: chalk.blue, symbol: 'ℹ️', level: 1 },
|
|
14
|
+
SUCCESS: { color: chalk.green, symbol: '✅', level: 2 },
|
|
15
|
+
WARN: { color: chalk.yellow, symbol: '⚠️', level: 3 },
|
|
16
|
+
ERROR: { color: chalk.red, symbol: '❌', level: 4 },
|
|
17
|
+
SPINNER: { color: chalk.cyan, symbol: '⏳', level: 1 }
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Logger class with colored output and level filtering
|
|
22
|
+
*/
|
|
23
|
+
class Logger {
|
|
24
|
+
constructor(options = {}) {
|
|
25
|
+
this.level = options.level || 'INFO';
|
|
26
|
+
this.prefix = options.prefix || '@claude-code/setup-installer';
|
|
27
|
+
this.timestamps = options.timestamps || false;
|
|
28
|
+
this.silent = options.silent || false;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Check if message should be logged based on level
|
|
33
|
+
*/
|
|
34
|
+
shouldLog(messageLevel) {
|
|
35
|
+
if (this.silent) return false;
|
|
36
|
+
const currentLevel = LOG_LEVELS[this.level]?.level || 1;
|
|
37
|
+
const msgLevel = LOG_LEVELS[messageLevel]?.level || 1;
|
|
38
|
+
return msgLevel >= currentLevel;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Format a log message with prefix, timestamp, and color
|
|
43
|
+
*/
|
|
44
|
+
formatMessage(level, message, data = null) {
|
|
45
|
+
const config = LOG_LEVELS[level] || LOG_LEVELS.INFO;
|
|
46
|
+
const timestamp = this.timestamps ? chalk.gray(`[${new Date().toISOString()}]`) : '';
|
|
47
|
+
const prefix = chalk.bold(`[${this.prefix}]`);
|
|
48
|
+
const symbol = config.symbol;
|
|
49
|
+
const coloredMessage = config.color(message);
|
|
50
|
+
|
|
51
|
+
let formatted = `${timestamp} ${prefix} ${symbol} ${coloredMessage}`;
|
|
52
|
+
|
|
53
|
+
if (data) {
|
|
54
|
+
formatted += '\n' + this.formatData(data);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return formatted;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Format additional data for logging
|
|
62
|
+
*/
|
|
63
|
+
formatData(data) {
|
|
64
|
+
if (typeof data === 'object') {
|
|
65
|
+
return chalk.gray(JSON.stringify(data, null, 2));
|
|
66
|
+
}
|
|
67
|
+
return chalk.gray(String(data));
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Log a debug message
|
|
72
|
+
*/
|
|
73
|
+
debug(message, data) {
|
|
74
|
+
if (this.shouldLog('DEBUG')) {
|
|
75
|
+
console.log(this.formatMessage('DEBUG', message, data));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Log an info message
|
|
81
|
+
*/
|
|
82
|
+
info(message, data) {
|
|
83
|
+
if (this.shouldLog('INFO')) {
|
|
84
|
+
console.log(this.formatMessage('INFO', message, data));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Log a success message
|
|
90
|
+
*/
|
|
91
|
+
success(message, data) {
|
|
92
|
+
if (this.shouldLog('SUCCESS')) {
|
|
93
|
+
console.log(this.formatMessage('SUCCESS', message, data));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Log a warning message
|
|
99
|
+
*/
|
|
100
|
+
warn(message, data) {
|
|
101
|
+
if (this.shouldLog('WARN')) {
|
|
102
|
+
console.warn(this.formatMessage('WARN', message, data));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Log an error message
|
|
108
|
+
*/
|
|
109
|
+
error(message, data) {
|
|
110
|
+
if (this.shouldLog('ERROR')) {
|
|
111
|
+
console.error(this.formatMessage('ERROR', message, data));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Log a spinner/progress message
|
|
117
|
+
*/
|
|
118
|
+
spinner(message, data) {
|
|
119
|
+
if (this.shouldLog('SPINNER')) {
|
|
120
|
+
console.log(this.formatMessage('SPINNER', message, data));
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Create a new logger with different options
|
|
126
|
+
*/
|
|
127
|
+
child(options) {
|
|
128
|
+
return new Logger({
|
|
129
|
+
level: this.level,
|
|
130
|
+
prefix: this.prefix,
|
|
131
|
+
timestamps: this.timestamps,
|
|
132
|
+
silent: this.silent,
|
|
133
|
+
...options
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Set the log level
|
|
139
|
+
*/
|
|
140
|
+
setLevel(level) {
|
|
141
|
+
if (LOG_LEVELS[level]) {
|
|
142
|
+
this.level = level;
|
|
143
|
+
} else {
|
|
144
|
+
this.warn(`Invalid log level: ${level}. Using INFO instead.`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Enable or disable silent mode
|
|
150
|
+
*/
|
|
151
|
+
setSilent(silent) {
|
|
152
|
+
this.silent = silent;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Default logger instance
|
|
158
|
+
*/
|
|
159
|
+
const defaultLogger = new Logger();
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Convenience functions using default logger
|
|
163
|
+
*/
|
|
164
|
+
const logger = {
|
|
165
|
+
debug: (msg, data) => defaultLogger.debug(msg, data),
|
|
166
|
+
info: (msg, data) => defaultLogger.info(msg, data),
|
|
167
|
+
success: (msg, data) => defaultLogger.success(msg, data),
|
|
168
|
+
warn: (msg, data) => defaultLogger.warn(msg, data),
|
|
169
|
+
error: (msg, data) => defaultLogger.error(msg, data),
|
|
170
|
+
spinner: (msg, data) => defaultLogger.spinner(msg, data),
|
|
171
|
+
setLevel: (level) => defaultLogger.setLevel(level),
|
|
172
|
+
setSilent: (silent) => defaultLogger.setSilent(silent),
|
|
173
|
+
child: (options) => defaultLogger.child(options),
|
|
174
|
+
Logger
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
module.exports = logger;
|