agileflow 2.89.2 → 2.90.0
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 +10 -0
- package/README.md +3 -3
- package/lib/content-sanitizer.js +463 -0
- package/lib/error-codes.js +544 -0
- package/lib/errors.js +336 -5
- package/lib/feedback.js +561 -0
- package/lib/path-resolver.js +396 -0
- package/lib/placeholder-registry.js +617 -0
- package/lib/session-registry.js +461 -0
- package/lib/smart-json-file.js +653 -0
- package/lib/table-formatter.js +504 -0
- package/lib/transient-status.js +374 -0
- package/lib/ui-manager.js +612 -0
- package/lib/validate-args.js +213 -0
- package/lib/validate-names.js +143 -0
- package/lib/validate-paths.js +434 -0
- package/lib/validate.js +38 -584
- package/package.json +4 -1
- package/scripts/agileflow-configure.js +40 -1440
- package/scripts/agileflow-welcome.js +2 -1
- package/scripts/check-update.js +16 -3
- package/scripts/lib/configure-detect.js +383 -0
- package/scripts/lib/configure-features.js +811 -0
- package/scripts/lib/configure-repair.js +314 -0
- package/scripts/lib/configure-utils.js +115 -0
- package/scripts/lib/frontmatter-parser.js +3 -3
- package/scripts/lib/sessionRegistry.js +682 -0
- package/scripts/obtain-context.js +417 -113
- package/scripts/ralph-loop.js +1 -1
- package/scripts/session-manager.js +77 -10
- package/scripts/tui/App.js +176 -0
- package/scripts/tui/index.js +75 -0
- package/scripts/tui/lib/crashRecovery.js +302 -0
- package/scripts/tui/lib/eventStream.js +316 -0
- package/scripts/tui/lib/keyboard.js +252 -0
- package/scripts/tui/lib/loopControl.js +371 -0
- package/scripts/tui/panels/OutputPanel.js +278 -0
- package/scripts/tui/panels/SessionPanel.js +178 -0
- package/scripts/tui/panels/TracePanel.js +333 -0
- package/src/core/commands/tui.md +91 -0
- package/tools/cli/commands/config.js +10 -33
- package/tools/cli/commands/doctor.js +48 -40
- package/tools/cli/commands/list.js +49 -37
- package/tools/cli/commands/status.js +13 -37
- package/tools/cli/commands/uninstall.js +12 -41
- package/tools/cli/installers/core/installer.js +75 -12
- package/tools/cli/installers/ide/_interface.js +238 -0
- package/tools/cli/installers/ide/codex.js +2 -2
- package/tools/cli/installers/ide/manager.js +15 -0
- package/tools/cli/lib/command-context.js +374 -0
- package/tools/cli/lib/config-manager.js +394 -0
- package/tools/cli/lib/content-injector.js +69 -16
- package/tools/cli/lib/ide-errors.js +163 -29
- package/tools/cli/lib/ide-registry.js +186 -0
- package/tools/cli/lib/npm-utils.js +16 -3
- package/tools/cli/lib/self-update.js +148 -0
- package/tools/cli/lib/validation-middleware.js +491 -0
|
@@ -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
|
+
};
|