agileflow 2.89.1 → 2.89.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.
@@ -0,0 +1,544 @@
1
+ /**
2
+ * error-codes.js - Centralized error codes for auto-recovery
3
+ *
4
+ * Provides standardized error codes with metadata for:
5
+ * - Automated diagnosis
6
+ * - Suggested fixes
7
+ * - Recovery actions
8
+ *
9
+ * Usage:
10
+ * const { ErrorCodes, getErrorCode, attachErrorCode, isRecoverable } = require('./error-codes');
11
+ *
12
+ * // Get error details
13
+ * const code = getErrorCode('ENOENT');
14
+ * console.log(code.suggestedFix);
15
+ *
16
+ * // Create typed error
17
+ * const error = attachErrorCode(new Error('File not found'), 'ENOENT');
18
+ * if (isRecoverable(error)) {
19
+ * console.log('Can recover:', error.suggestedFix);
20
+ * }
21
+ */
22
+
23
+ /**
24
+ * Severity levels for errors
25
+ * @enum {string}
26
+ */
27
+ const Severity = {
28
+ CRITICAL: 'critical', // Blocks operation, requires immediate attention
29
+ HIGH: 'high', // Serious issue, likely prevents feature from working
30
+ MEDIUM: 'medium', // Degraded functionality, can continue
31
+ LOW: 'low', // Minor issue, informational
32
+ };
33
+
34
+ /**
35
+ * Error categories for grouping
36
+ * @enum {string}
37
+ */
38
+ const Category = {
39
+ FILESYSTEM: 'filesystem', // File/directory operations
40
+ PERMISSION: 'permission', // Access control issues
41
+ CONFIGURATION: 'configuration', // Config file problems
42
+ NETWORK: 'network', // Network/connectivity issues
43
+ VALIDATION: 'validation', // Input validation failures
44
+ STATE: 'state', // Application state issues
45
+ DEPENDENCY: 'dependency', // Missing/incompatible dependencies
46
+ };
47
+
48
+ /**
49
+ * Standard error codes with metadata
50
+ * @type {Object.<string, {
51
+ * code: string,
52
+ * message: string,
53
+ * severity: string,
54
+ * category: string,
55
+ * recoverable: boolean,
56
+ * suggestedFix: string,
57
+ * autoFix?: string
58
+ * }>}
59
+ */
60
+ const ErrorCodes = {
61
+ // Filesystem errors
62
+ ENOENT: {
63
+ code: 'ENOENT',
64
+ message: 'File or directory not found',
65
+ severity: Severity.HIGH,
66
+ category: Category.FILESYSTEM,
67
+ recoverable: true,
68
+ suggestedFix:
69
+ 'Check if the file path is correct or run "npx agileflow setup" to create missing files',
70
+ autoFix: 'create-missing-file',
71
+ },
72
+
73
+ ENODIR: {
74
+ code: 'ENODIR',
75
+ message: 'Directory does not exist',
76
+ severity: Severity.HIGH,
77
+ category: Category.FILESYSTEM,
78
+ recoverable: true,
79
+ suggestedFix: 'Create the missing directory or run "npx agileflow setup" to initialize',
80
+ autoFix: 'create-directory',
81
+ },
82
+
83
+ EEXIST: {
84
+ code: 'EEXIST',
85
+ message: 'File or directory already exists',
86
+ severity: Severity.MEDIUM,
87
+ category: Category.FILESYSTEM,
88
+ recoverable: true,
89
+ suggestedFix: 'Use --force flag to overwrite or choose a different path',
90
+ autoFix: null,
91
+ },
92
+
93
+ EISDIR: {
94
+ code: 'EISDIR',
95
+ message: 'Expected file but found directory',
96
+ severity: Severity.HIGH,
97
+ category: Category.FILESYSTEM,
98
+ recoverable: false,
99
+ suggestedFix: 'Remove the directory or use the correct file path',
100
+ autoFix: null,
101
+ },
102
+
103
+ ENOTDIR: {
104
+ code: 'ENOTDIR',
105
+ message: 'Expected directory but found file',
106
+ severity: Severity.HIGH,
107
+ category: Category.FILESYSTEM,
108
+ recoverable: false,
109
+ suggestedFix: 'Remove the file or use the correct directory path',
110
+ autoFix: null,
111
+ },
112
+
113
+ EEMPTYDIR: {
114
+ code: 'EEMPTYDIR',
115
+ message: 'Directory is empty',
116
+ severity: Severity.MEDIUM,
117
+ category: Category.FILESYSTEM,
118
+ recoverable: true,
119
+ suggestedFix: 'Populate the directory or run "npx agileflow setup" to initialize content',
120
+ autoFix: 'populate-directory',
121
+ },
122
+
123
+ // Permission errors
124
+ EACCES: {
125
+ code: 'EACCES',
126
+ message: 'Permission denied',
127
+ severity: Severity.CRITICAL,
128
+ category: Category.PERMISSION,
129
+ recoverable: false,
130
+ suggestedFix:
131
+ 'Check file/directory permissions. Try "chmod +rw <path>" or run with appropriate permissions',
132
+ autoFix: null,
133
+ },
134
+
135
+ EPERM: {
136
+ code: 'EPERM',
137
+ message: 'Operation not permitted',
138
+ severity: Severity.CRITICAL,
139
+ category: Category.PERMISSION,
140
+ recoverable: false,
141
+ suggestedFix: 'This operation requires elevated privileges or different permissions',
142
+ autoFix: null,
143
+ },
144
+
145
+ EROFS: {
146
+ code: 'EROFS',
147
+ message: 'Read-only file system',
148
+ severity: Severity.CRITICAL,
149
+ category: Category.PERMISSION,
150
+ recoverable: false,
151
+ suggestedFix: 'Cannot write to read-only filesystem. Check mount options or disk status',
152
+ autoFix: null,
153
+ },
154
+
155
+ // Configuration errors
156
+ ECONFIG: {
157
+ code: 'ECONFIG',
158
+ message: 'Configuration file is invalid or missing',
159
+ severity: Severity.HIGH,
160
+ category: Category.CONFIGURATION,
161
+ recoverable: true,
162
+ suggestedFix:
163
+ 'Check configuration syntax or run "npx agileflow doctor --fix" to recreate defaults',
164
+ autoFix: 'recreate-config',
165
+ },
166
+
167
+ EPARSE: {
168
+ code: 'EPARSE',
169
+ message: 'Failed to parse configuration file',
170
+ severity: Severity.HIGH,
171
+ category: Category.CONFIGURATION,
172
+ recoverable: true,
173
+ suggestedFix:
174
+ 'Check JSON/YAML syntax. Common issues: trailing commas, unquoted strings, invalid encoding',
175
+ autoFix: null,
176
+ },
177
+
178
+ ESCHEMA: {
179
+ code: 'ESCHEMA',
180
+ message: 'Configuration schema validation failed',
181
+ severity: Severity.MEDIUM,
182
+ category: Category.CONFIGURATION,
183
+ recoverable: true,
184
+ suggestedFix:
185
+ 'Review configuration against expected schema. Run "npx agileflow doctor" for details',
186
+ autoFix: 'validate-config',
187
+ },
188
+
189
+ EVERSION: {
190
+ code: 'EVERSION',
191
+ message: 'Version mismatch or incompatible version',
192
+ severity: Severity.MEDIUM,
193
+ category: Category.CONFIGURATION,
194
+ recoverable: true,
195
+ suggestedFix: 'Run "npx agileflow update" to upgrade to compatible version',
196
+ autoFix: 'update-version',
197
+ },
198
+
199
+ // Network errors
200
+ ENETWORK: {
201
+ code: 'ENETWORK',
202
+ message: 'Network error or connection failed',
203
+ severity: Severity.HIGH,
204
+ category: Category.NETWORK,
205
+ recoverable: true,
206
+ suggestedFix: 'Check internet connection, firewall settings, or try again later',
207
+ autoFix: 'retry-network',
208
+ },
209
+
210
+ ETIMEOUT: {
211
+ code: 'ETIMEOUT',
212
+ message: 'Operation timed out',
213
+ severity: Severity.HIGH,
214
+ category: Category.NETWORK,
215
+ recoverable: true,
216
+ suggestedFix: 'Check network speed and stability. Try increasing timeout or retrying',
217
+ autoFix: 'retry-timeout',
218
+ },
219
+
220
+ ENOTFOUND: {
221
+ code: 'ENOTFOUND',
222
+ message: 'Host or resource not found',
223
+ severity: Severity.HIGH,
224
+ category: Category.NETWORK,
225
+ recoverable: true,
226
+ suggestedFix: 'Check URL/hostname spelling and DNS settings',
227
+ autoFix: null,
228
+ },
229
+
230
+ // Validation errors
231
+ EINVAL: {
232
+ code: 'EINVAL',
233
+ message: 'Invalid argument or parameter',
234
+ severity: Severity.MEDIUM,
235
+ category: Category.VALIDATION,
236
+ recoverable: true,
237
+ suggestedFix: 'Check input format and required parameters. Use --help for usage information',
238
+ autoFix: null,
239
+ },
240
+
241
+ EMISSING: {
242
+ code: 'EMISSING',
243
+ message: 'Required value is missing',
244
+ severity: Severity.HIGH,
245
+ category: Category.VALIDATION,
246
+ recoverable: true,
247
+ suggestedFix: 'Provide the required value. Check command usage with --help',
248
+ autoFix: null,
249
+ },
250
+
251
+ ERANGE: {
252
+ code: 'ERANGE',
253
+ message: 'Value is out of valid range',
254
+ severity: Severity.MEDIUM,
255
+ category: Category.VALIDATION,
256
+ recoverable: true,
257
+ suggestedFix: 'Provide a value within the valid range',
258
+ autoFix: null,
259
+ },
260
+
261
+ // State errors
262
+ ESTATE: {
263
+ code: 'ESTATE',
264
+ message: 'Invalid application state',
265
+ severity: Severity.HIGH,
266
+ category: Category.STATE,
267
+ recoverable: true,
268
+ suggestedFix: 'Run "npx agileflow doctor --fix" to repair state or clear cache',
269
+ autoFix: 'repair-state',
270
+ },
271
+
272
+ ECONFLICT: {
273
+ code: 'ECONFLICT',
274
+ message: 'Operation conflicts with current state',
275
+ severity: Severity.MEDIUM,
276
+ category: Category.STATE,
277
+ recoverable: true,
278
+ suggestedFix: 'Resolve the conflict or use --force flag if appropriate',
279
+ autoFix: null,
280
+ },
281
+
282
+ ELOCK: {
283
+ code: 'ELOCK',
284
+ message: 'Resource is locked by another process',
285
+ severity: Severity.MEDIUM,
286
+ category: Category.STATE,
287
+ recoverable: true,
288
+ suggestedFix: 'Wait for the other process to complete or remove stale lock file',
289
+ autoFix: 'remove-lock',
290
+ },
291
+
292
+ // Migration errors
293
+ EMIGRATION: {
294
+ code: 'EMIGRATION',
295
+ message: 'Migration required or migration failed',
296
+ severity: Severity.HIGH,
297
+ category: Category.STATE,
298
+ recoverable: true,
299
+ suggestedFix:
300
+ 'Run "npx agileflow update" to perform migration or "npx agileflow doctor --fix" to repair',
301
+ autoFix: 'run-migration',
302
+ },
303
+
304
+ // Dependency errors
305
+ EDEP: {
306
+ code: 'EDEP',
307
+ message: 'Missing or incompatible dependency',
308
+ severity: Severity.CRITICAL,
309
+ category: Category.DEPENDENCY,
310
+ recoverable: true,
311
+ suggestedFix: 'Install required dependencies: npm install',
312
+ autoFix: 'install-deps',
313
+ },
314
+
315
+ ENODE: {
316
+ code: 'ENODE',
317
+ message: 'Node.js version requirement not met',
318
+ severity: Severity.CRITICAL,
319
+ category: Category.DEPENDENCY,
320
+ recoverable: false,
321
+ suggestedFix: 'Upgrade Node.js to version 18.0.0 or higher',
322
+ autoFix: null,
323
+ },
324
+
325
+ // Generic errors
326
+ EUNKNOWN: {
327
+ code: 'EUNKNOWN',
328
+ message: 'An unknown error occurred',
329
+ severity: Severity.HIGH,
330
+ category: Category.STATE,
331
+ recoverable: false,
332
+ suggestedFix: 'Check logs for more details or report the issue',
333
+ autoFix: null,
334
+ },
335
+ };
336
+
337
+ /**
338
+ * Get error code details by code string
339
+ * @param {string} code - Error code (e.g., 'ENOENT')
340
+ * @returns {object|null} Error code details or null if not found
341
+ */
342
+ function getErrorCode(code) {
343
+ return ErrorCodes[code] || null;
344
+ }
345
+
346
+ /**
347
+ * Get error code from system error
348
+ * @param {Error} error - Error object
349
+ * @returns {object} Error code details (defaults to EUNKNOWN)
350
+ */
351
+ function getErrorCodeFromError(error) {
352
+ if (!error) return ErrorCodes.EUNKNOWN;
353
+
354
+ // Check if already typed
355
+ if (error.errorCode && ErrorCodes[error.errorCode]) {
356
+ return ErrorCodes[error.errorCode];
357
+ }
358
+
359
+ // Map system error codes
360
+ const systemCode = error.code || error.errno;
361
+ if (systemCode && ErrorCodes[systemCode]) {
362
+ return ErrorCodes[systemCode];
363
+ }
364
+
365
+ // Try to detect from message
366
+ const message = (error.message || '').toLowerCase();
367
+
368
+ if (message.includes('permission denied')) return ErrorCodes.EACCES;
369
+ if (message.includes('no such file') || message.includes('not found')) return ErrorCodes.ENOENT;
370
+ if (message.includes('directory') && message.includes('not exist')) return ErrorCodes.ENODIR;
371
+ if (message.includes('already exists')) return ErrorCodes.EEXIST;
372
+ if (message.includes('timed out') || message.includes('timeout')) return ErrorCodes.ETIMEOUT;
373
+ if (message.includes('network') || message.includes('connection')) return ErrorCodes.ENETWORK;
374
+ if (message.includes('parse') || message.includes('json') || message.includes('yaml')) {
375
+ return ErrorCodes.EPARSE;
376
+ }
377
+ if (message.includes('invalid') || message.includes('argument')) return ErrorCodes.EINVAL;
378
+
379
+ return ErrorCodes.EUNKNOWN;
380
+ }
381
+
382
+ /**
383
+ * Attach error code metadata to an error
384
+ * @param {Error} error - Error object to enhance
385
+ * @param {string} code - Error code to attach
386
+ * @returns {Error} Enhanced error with code metadata
387
+ */
388
+ function attachErrorCode(error, code) {
389
+ const codeData = ErrorCodes[code] || ErrorCodes.EUNKNOWN;
390
+
391
+ error.errorCode = codeData.code;
392
+ error.severity = codeData.severity;
393
+ error.category = codeData.category;
394
+ error.recoverable = codeData.recoverable;
395
+ error.suggestedFix = codeData.suggestedFix;
396
+ error.autoFix = codeData.autoFix || null;
397
+
398
+ return error;
399
+ }
400
+
401
+ /**
402
+ * Create a typed error with error code
403
+ * @param {string} message - Error message
404
+ * @param {string} code - Error code
405
+ * @param {object} [options] - Additional options
406
+ * @param {Error} [options.cause] - Original error
407
+ * @param {object} [options.context] - Additional context
408
+ * @returns {Error} Typed error with code metadata
409
+ */
410
+ function createTypedError(message, code, options = {}) {
411
+ const error = new Error(message);
412
+ const codeData = ErrorCodes[code] || ErrorCodes.EUNKNOWN;
413
+
414
+ error.errorCode = codeData.code;
415
+ error.severity = codeData.severity;
416
+ error.category = codeData.category;
417
+ error.recoverable = codeData.recoverable;
418
+ error.suggestedFix = codeData.suggestedFix;
419
+ error.autoFix = codeData.autoFix || null;
420
+
421
+ if (options.cause) {
422
+ error.cause = options.cause;
423
+ }
424
+
425
+ if (options.context) {
426
+ error.context = options.context;
427
+ }
428
+
429
+ return error;
430
+ }
431
+
432
+ /**
433
+ * Check if an error is recoverable
434
+ * @param {Error} error - Error to check
435
+ * @returns {boolean} True if recoverable
436
+ */
437
+ function isRecoverable(error) {
438
+ if (!error) return false;
439
+
440
+ // Check if already typed
441
+ if (typeof error.recoverable === 'boolean') {
442
+ return error.recoverable;
443
+ }
444
+
445
+ // Get code and check
446
+ const codeData = getErrorCodeFromError(error);
447
+ return codeData.recoverable;
448
+ }
449
+
450
+ /**
451
+ * Get suggested fix for an error
452
+ * @param {Error} error - Error to get fix for
453
+ * @returns {string} Suggested fix message
454
+ */
455
+ function getSuggestedFix(error) {
456
+ if (!error) return 'Unknown error occurred';
457
+
458
+ // Check if already typed
459
+ if (error.suggestedFix) {
460
+ return error.suggestedFix;
461
+ }
462
+
463
+ // Get code and return fix
464
+ const codeData = getErrorCodeFromError(error);
465
+ return codeData.suggestedFix;
466
+ }
467
+
468
+ /**
469
+ * Get auto-fix action for an error
470
+ * @param {Error} error - Error to get auto-fix for
471
+ * @returns {string|null} Auto-fix action name or null
472
+ */
473
+ function getAutoFix(error) {
474
+ if (!error) return null;
475
+
476
+ // Check if already typed
477
+ if (error.autoFix !== undefined) {
478
+ return error.autoFix;
479
+ }
480
+
481
+ // Get code and return auto-fix
482
+ const codeData = getErrorCodeFromError(error);
483
+ return codeData.autoFix || null;
484
+ }
485
+
486
+ /**
487
+ * Format error for display with code information
488
+ * @param {Error} error - Error to format
489
+ * @param {object} [options] - Format options
490
+ * @param {boolean} [options.includeStack=false] - Include stack trace
491
+ * @param {boolean} [options.includeSuggestion=true] - Include suggested fix
492
+ * @returns {string} Formatted error string
493
+ */
494
+ function formatError(error, options = {}) {
495
+ const { includeStack = false, includeSuggestion = true } = options;
496
+
497
+ if (!error) return 'Unknown error';
498
+
499
+ const codeData = getErrorCodeFromError(error);
500
+ const lines = [];
501
+
502
+ // Main error line
503
+ lines.push(`[${codeData.code}] ${error.message || codeData.message}`);
504
+
505
+ // Severity and category
506
+ lines.push(` Severity: ${codeData.severity} | Category: ${codeData.category}`);
507
+
508
+ // Suggested fix
509
+ if (includeSuggestion && codeData.suggestedFix) {
510
+ lines.push(` Fix: ${codeData.suggestedFix}`);
511
+ }
512
+
513
+ // Auto-fix availability
514
+ if (codeData.autoFix) {
515
+ lines.push(` Auto-fix available: npx agileflow doctor --fix`);
516
+ }
517
+
518
+ // Stack trace
519
+ if (includeStack && error.stack) {
520
+ lines.push('');
521
+ lines.push(error.stack);
522
+ }
523
+
524
+ return lines.join('\n');
525
+ }
526
+
527
+ module.exports = {
528
+ // Enums
529
+ Severity,
530
+ Category,
531
+
532
+ // Error codes
533
+ ErrorCodes,
534
+
535
+ // Functions
536
+ getErrorCode,
537
+ getErrorCodeFromError,
538
+ attachErrorCode,
539
+ createTypedError,
540
+ isRecoverable,
541
+ getSuggestedFix,
542
+ getAutoFix,
543
+ formatError,
544
+ };