indusagi-coding-agent 0.1.22 → 0.1.24

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.
Files changed (222) hide show
  1. package/CHANGELOG.md +72 -11
  2. package/README.md +2 -36
  3. package/dist/cli/args.d.ts +117 -1
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +231 -64
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/cli/config-selector.d.ts +58 -2
  8. package/dist/cli/config-selector.d.ts.map +1 -1
  9. package/dist/cli/config-selector.js +130 -12
  10. package/dist/cli/config-selector.js.map +1 -1
  11. package/dist/cli/file-processor.d.ts +70 -2
  12. package/dist/cli/file-processor.d.ts.map +1 -1
  13. package/dist/cli/file-processor.js +240 -15
  14. package/dist/cli/file-processor.js.map +1 -1
  15. package/dist/cli/list-models.d.ts +63 -3
  16. package/dist/cli/list-models.d.ts.map +1 -1
  17. package/dist/cli/list-models.js +202 -27
  18. package/dist/cli/list-models.js.map +1 -1
  19. package/dist/cli/login-handler.d.ts +82 -8
  20. package/dist/cli/login-handler.d.ts.map +1 -1
  21. package/dist/cli/login-handler.js +410 -77
  22. package/dist/cli/login-handler.js.map +1 -1
  23. package/dist/cli/session-picker.d.ts +74 -2
  24. package/dist/cli/session-picker.d.ts.map +1 -1
  25. package/dist/cli/session-picker.js +236 -12
  26. package/dist/cli/session-picker.js.map +1 -1
  27. package/dist/core/agent-session.d.ts +214 -9
  28. package/dist/core/agent-session.d.ts.map +1 -1
  29. package/dist/core/agent-session.js +214 -9
  30. package/dist/core/agent-session.js.map +1 -1
  31. package/dist/core/bash-executor.d.ts +302 -12
  32. package/dist/core/bash-executor.d.ts.map +1 -1
  33. package/dist/core/bash-executor.js +302 -12
  34. package/dist/core/bash-executor.js.map +1 -1
  35. package/dist/core/diagnostics.d.ts +191 -0
  36. package/dist/core/diagnostics.d.ts.map +1 -1
  37. package/dist/core/diagnostics.js +142 -0
  38. package/dist/core/diagnostics.js.map +1 -1
  39. package/dist/core/event-bus.d.ts +146 -0
  40. package/dist/core/event-bus.d.ts.map +1 -1
  41. package/dist/core/event-bus.js +93 -0
  42. package/dist/core/event-bus.js.map +1 -1
  43. package/dist/core/export-html/ansi-to-html.d.ts +4 -0
  44. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  45. package/dist/core/export-html/ansi-to-html.js +4 -0
  46. package/dist/core/export-html/ansi-to-html.js.map +1 -1
  47. package/dist/core/export-html/index.d.ts +128 -0
  48. package/dist/core/export-html/index.d.ts.map +1 -1
  49. package/dist/core/export-html/index.js +128 -0
  50. package/dist/core/export-html/index.js.map +1 -1
  51. package/dist/core/export-html/tool-renderer.d.ts +4 -0
  52. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  53. package/dist/core/export-html/tool-renderer.js +4 -0
  54. package/dist/core/export-html/tool-renderer.js.map +1 -1
  55. package/dist/core/keybindings.d.ts +142 -0
  56. package/dist/core/keybindings.d.ts.map +1 -1
  57. package/dist/core/keybindings.js +142 -0
  58. package/dist/core/keybindings.js.map +1 -1
  59. package/dist/core/model-registry.d.ts +98 -1
  60. package/dist/core/model-registry.d.ts.map +1 -1
  61. package/dist/core/model-registry.js +98 -1
  62. package/dist/core/model-registry.js.map +1 -1
  63. package/dist/core/model-resolver.d.ts +99 -1
  64. package/dist/core/model-resolver.d.ts.map +1 -1
  65. package/dist/core/model-resolver.js +99 -1
  66. package/dist/core/model-resolver.js.map +1 -1
  67. package/dist/core/prompt-templates.js.map +1 -1
  68. package/dist/core/sdk.d.ts +1 -1
  69. package/dist/core/sdk.d.ts.map +1 -1
  70. package/dist/core/sdk.js +0 -2
  71. package/dist/core/sdk.js.map +1 -1
  72. package/dist/core/session-manager.d.ts +127 -0
  73. package/dist/core/session-manager.d.ts.map +1 -1
  74. package/dist/core/session-manager.js +125 -0
  75. package/dist/core/session-manager.js.map +1 -1
  76. package/dist/core/skills.js.map +1 -1
  77. package/dist/core/subagents.js.map +1 -1
  78. package/dist/core/tools/bash.d.ts +391 -11
  79. package/dist/core/tools/bash.d.ts.map +1 -1
  80. package/dist/core/tools/bash.js +269 -2
  81. package/dist/core/tools/bash.js.map +1 -1
  82. package/dist/core/tools/edit.d.ts +284 -6
  83. package/dist/core/tools/edit.d.ts.map +1 -1
  84. package/dist/core/tools/edit.js +238 -0
  85. package/dist/core/tools/edit.js.map +1 -1
  86. package/dist/core/tools/find.d.ts +169 -5
  87. package/dist/core/tools/find.d.ts.map +1 -1
  88. package/dist/core/tools/find.js +136 -0
  89. package/dist/core/tools/find.js.map +1 -1
  90. package/dist/core/tools/grep.d.ts +285 -5
  91. package/dist/core/tools/grep.d.ts.map +1 -1
  92. package/dist/core/tools/grep.js +247 -0
  93. package/dist/core/tools/grep.js.map +1 -1
  94. package/dist/core/tools/index.d.ts +0 -18
  95. package/dist/core/tools/index.d.ts.map +1 -1
  96. package/dist/core/tools/index.js +1 -23
  97. package/dist/core/tools/index.js.map +1 -1
  98. package/dist/core/tools/ls.d.ts +6 -0
  99. package/dist/core/tools/ls.d.ts.map +1 -1
  100. package/dist/core/tools/ls.js +6 -0
  101. package/dist/core/tools/ls.js.map +1 -1
  102. package/dist/core/tools/read.d.ts +308 -7
  103. package/dist/core/tools/read.d.ts.map +1 -1
  104. package/dist/core/tools/read.js +231 -0
  105. package/dist/core/tools/read.js.map +1 -1
  106. package/dist/core/tools/webfetch.d.ts +118 -3
  107. package/dist/core/tools/webfetch.d.ts.map +1 -1
  108. package/dist/core/tools/webfetch.js +118 -3
  109. package/dist/core/tools/webfetch.js.map +1 -1
  110. package/dist/core/tools/websearch.d.ts +130 -3
  111. package/dist/core/tools/websearch.d.ts.map +1 -1
  112. package/dist/core/tools/websearch.js +130 -3
  113. package/dist/core/tools/websearch.js.map +1 -1
  114. package/dist/core/tools/write.d.ts +251 -5
  115. package/dist/core/tools/write.d.ts.map +1 -1
  116. package/dist/core/tools/write.js +210 -0
  117. package/dist/core/tools/write.js.map +1 -1
  118. package/dist/modes/interactive/components/assistant-message.d.ts +164 -1
  119. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  120. package/dist/modes/interactive/components/assistant-message.js +164 -1
  121. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  122. package/dist/modes/interactive/components/bash-execution.d.ts +297 -1
  123. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  124. package/dist/modes/interactive/components/bash-execution.js +297 -1
  125. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  126. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  127. package/dist/modes/interactive/components/tool-execution.js +251 -1
  128. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  129. package/dist/modes/interactive/components/user-message.d.ts +186 -1
  130. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  131. package/dist/modes/interactive/components/user-message.js +186 -1
  132. package/dist/modes/interactive/components/user-message.js.map +1 -1
  133. package/dist/modes/interactive/interactive-mode.d.ts +1567 -13
  134. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  135. package/dist/modes/interactive/interactive-mode.js +1567 -13
  136. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  137. package/dist/modes/interactive/theme/theme.d.ts +422 -0
  138. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  139. package/dist/modes/interactive/theme/theme.js +422 -0
  140. package/dist/modes/interactive/theme/theme.js.map +1 -1
  141. package/dist/modes/print-mode.d.ts +538 -5
  142. package/dist/modes/print-mode.d.ts.map +1 -1
  143. package/dist/modes/print-mode.js +538 -5
  144. package/dist/modes/print-mode.js.map +1 -1
  145. package/dist/modes/rpc/rpc-client.d.ts +921 -8
  146. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  147. package/dist/modes/rpc/rpc-client.js +921 -8
  148. package/dist/modes/rpc/rpc-client.js.map +1 -1
  149. package/dist/modes/rpc/rpc-mode.d.ts +802 -9
  150. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  151. package/dist/modes/rpc/rpc-mode.js +802 -9
  152. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  153. package/dist/modes/rpc/rpc-types.d.ts +356 -3
  154. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  155. package/dist/modes/rpc/rpc-types.js +356 -3
  156. package/dist/modes/rpc/rpc-types.js.map +1 -1
  157. package/dist/modes/shared.d.ts +386 -0
  158. package/dist/modes/shared.d.ts.map +1 -0
  159. package/dist/modes/shared.js +543 -0
  160. package/dist/modes/shared.js.map +1 -0
  161. package/dist/utils/array.d.ts +389 -0
  162. package/dist/utils/array.d.ts.map +1 -0
  163. package/dist/utils/array.js +585 -0
  164. package/dist/utils/array.js.map +1 -0
  165. package/dist/utils/color-formatter.d.ts +318 -0
  166. package/dist/utils/color-formatter.d.ts.map +1 -0
  167. package/dist/utils/color-formatter.js +442 -0
  168. package/dist/utils/color-formatter.js.map +1 -0
  169. package/dist/utils/data-transformer.d.ts +326 -0
  170. package/dist/utils/data-transformer.d.ts.map +1 -0
  171. package/dist/utils/data-transformer.js +512 -0
  172. package/dist/utils/data-transformer.js.map +1 -0
  173. package/dist/utils/date-formatter.d.ts +281 -0
  174. package/dist/utils/date-formatter.d.ts.map +1 -0
  175. package/dist/utils/date-formatter.js +503 -0
  176. package/dist/utils/date-formatter.js.map +1 -0
  177. package/dist/utils/error-handler.d.ts +541 -0
  178. package/dist/utils/error-handler.d.ts.map +1 -0
  179. package/dist/utils/error-handler.js +726 -0
  180. package/dist/utils/error-handler.js.map +1 -0
  181. package/dist/utils/file-operations.d.ts +297 -0
  182. package/dist/utils/file-operations.d.ts.map +1 -0
  183. package/dist/utils/file-operations.js +505 -0
  184. package/dist/utils/file-operations.js.map +1 -0
  185. package/dist/utils/frontmatter.d.ts +268 -6
  186. package/dist/utils/frontmatter.d.ts.map +1 -1
  187. package/dist/utils/frontmatter.js +500 -21
  188. package/dist/utils/frontmatter.js.map +1 -1
  189. package/dist/utils/json-formatter.d.ts +259 -0
  190. package/dist/utils/json-formatter.d.ts.map +1 -0
  191. package/dist/utils/json-formatter.js +517 -0
  192. package/dist/utils/json-formatter.js.map +1 -0
  193. package/dist/utils/logger.d.ts +176 -0
  194. package/dist/utils/logger.d.ts.map +1 -0
  195. package/dist/utils/logger.js +346 -0
  196. package/dist/utils/logger.js.map +1 -0
  197. package/dist/utils/markdown-formatter.d.ts +211 -0
  198. package/dist/utils/markdown-formatter.d.ts.map +1 -0
  199. package/dist/utils/markdown-formatter.js +482 -0
  200. package/dist/utils/markdown-formatter.js.map +1 -0
  201. package/dist/utils/path-validator.d.ts +603 -0
  202. package/dist/utils/path-validator.d.ts.map +1 -0
  203. package/dist/utils/path-validator.js +870 -0
  204. package/dist/utils/path-validator.js.map +1 -0
  205. package/dist/utils/string-formatter.d.ts +609 -0
  206. package/dist/utils/string-formatter.d.ts.map +1 -0
  207. package/dist/utils/string-formatter.js +806 -0
  208. package/dist/utils/string-formatter.js.map +1 -0
  209. package/dist/utils/type-guards.d.ts +629 -0
  210. package/dist/utils/type-guards.d.ts.map +1 -0
  211. package/dist/utils/type-guards.js +662 -0
  212. package/dist/utils/type-guards.js.map +1 -0
  213. package/docs/COMPLETE-GUIDE.md +300 -0
  214. package/docs/MODES-ARCHITECTURE.md +565 -0
  215. package/docs/PRINT-MODE-GUIDE.md +456 -0
  216. package/docs/README.md +1 -2
  217. package/docs/RPC-GUIDE.md +705 -0
  218. package/docs/UTILS-IMPLEMENTATION-SUMMARY.md +647 -0
  219. package/docs/UTILS-MODULE-OVERVIEW.md +1480 -0
  220. package/docs/UTILS-QA-CHECKLIST.md +1061 -0
  221. package/docs/UTILS-USAGE-GUIDE.md +1419 -0
  222. package/package.json +3 -3
@@ -0,0 +1,726 @@
1
+ /**
2
+ * @fileoverview Error Handling and Recovery Utilities
3
+ *
4
+ * This module provides robust error handling utilities for transforming technical
5
+ * errors into user-friendly messages, categorizing errors, and providing recovery
6
+ * suggestions. Error handling is critical for:
7
+ *
8
+ * 1. **User Experience**: Transform cryptic technical errors into actionable messages
9
+ * 2. **Error Categorization**: Classify errors by type (TypeError, FileNotFound, etc.)
10
+ * 3. **Recovery Suggestions**: Provide users with steps to resolve issues
11
+ * 4. **Security**: Avoid leaking sensitive information in error messages
12
+ * 5. **Logging and Debugging**: Format errors for logs and debugging
13
+ * 6. **Error Codes**: Standardize error codes for programmatic error handling
14
+ *
15
+ * ## Error Code Conventions
16
+ *
17
+ * ### System Errors (E-prefix)
18
+ * - E001: Unknown error
19
+ * - E002: Validation error
20
+ * - E003: Configuration error
21
+ * - E004: Permission denied
22
+ * - E005: Resource not found
23
+ * - E006: Timeout error
24
+ * - E007: Network error
25
+ * - E008: Parse error
26
+ *
27
+ * ### Node.js System Errors (POSIX)
28
+ * - EACCES: Permission denied
29
+ * - EEXIST: File already exists
30
+ * - EISDIR: Is a directory
31
+ * - ENOENT: No such file or directory
32
+ * - ENOTDIR: Not a directory
33
+ * - EPERM: Operation not permitted
34
+ * - ETIMEDOUT: Connection timed out
35
+ * - ECONNREFUSED: Connection refused
36
+ *
37
+ * ## Error Type Hierarchy
38
+ *
39
+ * JavaScript error types provide context about what went wrong:
40
+ * - **Error**: Generic error, safe fallback
41
+ * - **TypeError**: Type mismatch or invalid operation
42
+ * - **ReferenceError**: Undefined variable or property
43
+ * - **RangeError**: Value out of valid range
44
+ * - **SyntaxError**: Malformed code or JSON
45
+ * - **EvalError**: eval() function error (rarely thrown)
46
+ * - **URIError**: Invalid URI function argument
47
+ *
48
+ * ## Security Considerations
49
+ *
50
+ * Error messages can leak sensitive information:
51
+ * - File system paths
52
+ * - Internal variable names
53
+ * - API endpoints
54
+ * - Database structure
55
+ * - Configuration secrets
56
+ *
57
+ * Always sanitize error messages before displaying to users.
58
+ *
59
+ * @author Coding Agent
60
+ * @version 1.0.0
61
+ */
62
+ /**
63
+ * Standard error code enum for consistent error identification.
64
+ *
65
+ * Error codes allow programmatic error handling and localization.
66
+ * Each code corresponds to an error category and recovery strategy.
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * if (error.code === ErrorCode.EACCES) {
71
+ * // Show permission error UI
72
+ * showPermissionError();
73
+ * }
74
+ * ```
75
+ */
76
+ export var ErrorCode;
77
+ (function (ErrorCode) {
78
+ // Generic errors
79
+ ErrorCode["UNKNOWN"] = "E001";
80
+ ErrorCode["VALIDATION"] = "E002";
81
+ ErrorCode["CONFIG"] = "E003";
82
+ ErrorCode["PERMISSION"] = "E004";
83
+ ErrorCode["NOT_FOUND"] = "E005";
84
+ ErrorCode["TIMEOUT"] = "E006";
85
+ ErrorCode["NETWORK"] = "E007";
86
+ ErrorCode["PARSE_ERROR"] = "E008";
87
+ // Node.js system errors
88
+ ErrorCode["EACCES"] = "EACCES";
89
+ ErrorCode["EEXIST"] = "EEXIST";
90
+ ErrorCode["EISDIR"] = "EISDIR";
91
+ ErrorCode["ENOENT"] = "ENOENT";
92
+ ErrorCode["ENOTDIR"] = "ENOTDIR";
93
+ ErrorCode["EPERM"] = "EPERM";
94
+ ErrorCode["ETIMEDOUT"] = "ETIMEDOUT";
95
+ ErrorCode["ECONNREFUSED"] = "ECONNREFUSED";
96
+ })(ErrorCode || (ErrorCode = {}));
97
+ /**
98
+ * Categorizes an error into a standard error type.
99
+ *
100
+ * Error type identification enables targeted error handling and appropriate
101
+ * UI/messaging responses.
102
+ *
103
+ * @param error - The error to categorize
104
+ * @returns Standard error type name
105
+ *
106
+ * @example
107
+ * ```typescript
108
+ * try {
109
+ * const value: any = null;
110
+ * value.property.nested = 123; // TypeError: Cannot read property 'property'
111
+ * } catch (error) {
112
+ * const type = categorizeError(error);
113
+ * // type === 'TypeError'
114
+ * if (type === 'TypeError') {
115
+ * showTypeErrorRecovery();
116
+ * }
117
+ * }
118
+ * ```
119
+ *
120
+ * @usage
121
+ * ```typescript
122
+ * // Error type routing
123
+ * function handleError(error: unknown) {
124
+ * const errorType = categorizeError(error);
125
+ *
126
+ * switch (errorType) {
127
+ * case 'TypeError':
128
+ * logMetric('type_error');
129
+ * break;
130
+ * case 'ReferenceError':
131
+ * logMetric('reference_error');
132
+ * break;
133
+ * case 'SyntaxError':
134
+ * logMetric('syntax_error');
135
+ * break;
136
+ * default:
137
+ * logMetric('unknown_error');
138
+ * }
139
+ * }
140
+ * ```
141
+ */
142
+ export function categorizeError(error) {
143
+ if (error instanceof TypeError)
144
+ return 'TypeError';
145
+ if (error instanceof ReferenceError)
146
+ return 'ReferenceError';
147
+ if (error instanceof RangeError)
148
+ return 'RangeError';
149
+ if (error instanceof SyntaxError)
150
+ return 'SyntaxError';
151
+ if (error instanceof URIError)
152
+ return 'URIError';
153
+ if (error instanceof EvalError)
154
+ return 'EvalError';
155
+ if (error instanceof Error)
156
+ return error.constructor.name || 'Error';
157
+ return 'UnknownError';
158
+ }
159
+ /**
160
+ * Extracts and formats stack trace from an error.
161
+ *
162
+ * Stack traces are essential for debugging but should never be shown to
163
+ * end users due to security concerns. Use for logging and diagnostics.
164
+ *
165
+ * @param error - The error to extract stack from
166
+ * @returns Formatted stack trace string or empty string
167
+ *
168
+ * @example
169
+ * ```typescript
170
+ * try {
171
+ * riskyOperation();
172
+ * } catch (error) {
173
+ * const stack = extractStackTrace(error);
174
+ * // stack:
175
+ * // "Error: Something went wrong
176
+ * // at riskyOperation (/path/to/file.ts:42:10)
177
+ * // at main (/path/to/file.ts:1:5)"
178
+ * logger.error(stack);
179
+ * }
180
+ * ```
181
+ *
182
+ * @usage
183
+ * ```typescript
184
+ * // Log error details without exposing to users
185
+ * function logErrorForSupport(error: unknown): void {
186
+ * const stack = extractStackTrace(error);
187
+ * const timestamp = new Date().toISOString();
188
+ * const entry = `[${timestamp}] ${String(error)}\n${stack}`;
189
+ *
190
+ * fs.appendFileSync('error.log', entry + '\n');
191
+ * }
192
+ *
193
+ * // Send to error tracking service
194
+ * function reportToSentry(error: unknown): void {
195
+ * const stack = extractStackTrace(error);
196
+ * Sentry.captureException(error, {
197
+ * extra: { stack }
198
+ * });
199
+ * }
200
+ * ```
201
+ */
202
+ export function extractStackTrace(error) {
203
+ if (error instanceof Error && error.stack) {
204
+ return error.stack;
205
+ }
206
+ if (typeof error === 'object' && error !== null && 'stack' in error) {
207
+ const stack = error.stack;
208
+ return typeof stack === 'string' ? stack : '';
209
+ }
210
+ return '';
211
+ }
212
+ /**
213
+ * Sanitizes error messages to prevent information leakage.
214
+ *
215
+ * Removes sensitive information like:
216
+ * - File system paths
217
+ * - Environment variables
218
+ * - Internal file names
219
+ * - Memory addresses
220
+ * - API endpoints
221
+ *
222
+ * @param message - Raw error message
223
+ * @returns Sanitized error message safe for user display
224
+ *
225
+ * @example
226
+ * ```typescript
227
+ * // Input (dangerous):
228
+ * const raw = 'Error reading /home/user/secret.key: EACCES';
229
+ * const safe = sanitizeErrorMessage(raw);
230
+ * // Output: 'Error reading file: Permission denied'
231
+ *
232
+ * // Input (dangerous):
233
+ * const raw2 = 'Failed to connect to DATABASE_URL=postgres://user:pass@host';
234
+ * const safe2 = sanitizeErrorMessage(raw2);
235
+ * // Output: 'Failed to connect to database'
236
+ * ```
237
+ *
238
+ * @usage
239
+ * ```typescript
240
+ * // Safe error display in UI
241
+ * function showUserError(error: unknown): void {
242
+ * const message = extractErrorMessage(error);
243
+ * const safe = sanitizeErrorMessage(message);
244
+ *
245
+ * showNotification({
246
+ * type: 'error',
247
+ * message: safe,
248
+ * duration: 5000
249
+ * });
250
+ * }
251
+ *
252
+ * // Log technical details separately
253
+ * function logErrorSecurely(error: unknown): void {
254
+ * const technical = extractErrorMessage(error);
255
+ * const safe = sanitizeErrorMessage(technical);
256
+ *
257
+ * // Log full details to secure server log
258
+ * internalLogger.error(technical);
259
+ *
260
+ * // Show safe version to user
261
+ * userNotification.error(safe);
262
+ * }
263
+ * ```
264
+ */
265
+ export function sanitizeErrorMessage(message) {
266
+ let sanitized = message;
267
+ // Remove file paths (Unix/Windows)
268
+ sanitized = sanitized.replace(/\/[^\s]*\//g, '/.../')
269
+ .replace(/C:\\[^\s]*/g, 'path\\...');
270
+ // Remove URLs and credentials
271
+ sanitized = sanitized.replace(/https?:\/\/[^\s]*/g, 'URL')
272
+ .replace(/([a-zA-Z0-9_-]+):([a-zA-Z0-9_-]+)@/g, 'credentials@');
273
+ // Remove environment variable patterns
274
+ sanitized = sanitized.replace(/\w+=.*?(?=\s|$)/g, (match) => {
275
+ if (match.includes('://') || match.includes('token') || match.includes('key')) {
276
+ return '[REDACTED]';
277
+ }
278
+ return match;
279
+ });
280
+ // Remove process/memory information
281
+ sanitized = sanitized.replace(/0x[0-9a-f]+/gi, 'address');
282
+ sanitized = sanitized.replace(/pid\s*\d+/gi, 'pid');
283
+ return sanitized;
284
+ }
285
+ /**
286
+ * Extracts the error message from various error types.
287
+ *
288
+ * Handles Error objects, plain objects with message property, and stringified errors.
289
+ *
290
+ * @param error - The error to extract message from
291
+ * @returns Error message string
292
+ *
293
+ * @example
294
+ * ```typescript
295
+ * extractErrorMessage(new Error('File not found'))
296
+ * // 'File not found'
297
+ *
298
+ * extractErrorMessage({ message: 'Custom error' })
299
+ * // 'Custom error'
300
+ *
301
+ * extractErrorMessage('Simple string error')
302
+ * // 'Simple string error'
303
+ *
304
+ * extractErrorMessage(null)
305
+ * // 'An unknown error occurred'
306
+ * ```
307
+ *
308
+ * @usage
309
+ * ```typescript
310
+ * // Unified error message extraction
311
+ * async function executeWithErrorHandling<T>(
312
+ * fn: () => Promise<T>
313
+ * ): Promise<T> {
314
+ * try {
315
+ * return await fn();
316
+ * } catch (error) {
317
+ * const message = extractErrorMessage(error);
318
+ * throw new Error(`Operation failed: ${message}`);
319
+ * }
320
+ * }
321
+ * ```
322
+ */
323
+ export function extractErrorMessage(error) {
324
+ if (error instanceof Error) {
325
+ return error.message;
326
+ }
327
+ if (typeof error === 'object' && error !== null && 'message' in error) {
328
+ const msg = error.message;
329
+ if (typeof msg === 'string')
330
+ return msg;
331
+ }
332
+ if (typeof error === 'string') {
333
+ return error;
334
+ }
335
+ return 'An unknown error occurred';
336
+ }
337
+ /**
338
+ * Gets recovery suggestions based on error type.
339
+ *
340
+ * Provides users with actionable steps to resolve common errors.
341
+ *
342
+ * @param error - The error to get suggestions for
343
+ * @param errorCode - Optional error code for more specific suggestions
344
+ * @returns Array of suggestion strings
345
+ *
346
+ * @example
347
+ * ```typescript
348
+ * const error = new Error('ENOENT: no such file or directory');
349
+ * const suggestions = getRecoverySuggestions(error, ErrorCode.ENOENT);
350
+ * // [
351
+ * // 'Check that the file path is correct',
352
+ * // 'Verify the file exists in the specified location',
353
+ * // 'Try using an absolute file path instead of relative'
354
+ * // ]
355
+ * ```
356
+ *
357
+ * @usage
358
+ * ```typescript
359
+ * // Show recovery steps in UI
360
+ * function showDetailedError(error: unknown) {
361
+ * const message = extractErrorMessage(error);
362
+ * const suggestions = getRecoverySuggestions(error);
363
+ *
364
+ * showErrorDialog({
365
+ * title: 'Operation Failed',
366
+ * message: sanitizeErrorMessage(message),
367
+ * suggestions: suggestions,
368
+ * actions: [
369
+ * { label: 'Try Again', handler: retry },
370
+ * { label: 'Cancel', handler: cancel }
371
+ * ]
372
+ * });
373
+ * }
374
+ * ```
375
+ */
376
+ export function getRecoverySuggestions(error, errorCode) {
377
+ const suggestions = [];
378
+ const message = extractErrorMessage(error);
379
+ const errorType = categorizeError(error);
380
+ // Code-based suggestions
381
+ if (errorCode === ErrorCode.ENOENT) {
382
+ suggestions.push('Check that the file path is correct');
383
+ suggestions.push('Verify the file exists in the specified location');
384
+ suggestions.push('Try using an absolute file path instead of relative');
385
+ }
386
+ else if (errorCode === ErrorCode.EACCES || errorCode === ErrorCode.PERMISSION) {
387
+ suggestions.push('Check file/directory permissions');
388
+ suggestions.push('Try running with elevated privileges if necessary');
389
+ suggestions.push('Ensure the file owner allows read/write access');
390
+ }
391
+ else if (errorCode === ErrorCode.ETIMEDOUT || errorCode === ErrorCode.TIMEOUT) {
392
+ suggestions.push('Check your internet connection');
393
+ suggestions.push('Try again in a few moments');
394
+ suggestions.push('Verify the server is online');
395
+ }
396
+ else if (errorCode === ErrorCode.ECONNREFUSED || errorCode === ErrorCode.NETWORK) {
397
+ suggestions.push('Verify the server address and port');
398
+ suggestions.push('Check your network connection');
399
+ suggestions.push('Ensure firewall is not blocking the connection');
400
+ }
401
+ else if (errorCode === ErrorCode.VALIDATION) {
402
+ suggestions.push('Check that all required fields are filled');
403
+ suggestions.push('Verify data formats match requirements');
404
+ suggestions.push('Review any validation error details above');
405
+ }
406
+ // Type-based suggestions
407
+ if (errorType === 'TypeError') {
408
+ suggestions.push('Verify that variables are initialized before use');
409
+ suggestions.push('Check that function arguments are of correct type');
410
+ suggestions.push('Ensure objects have expected properties');
411
+ }
412
+ else if (errorType === 'ReferenceError') {
413
+ suggestions.push('Check variable name spelling');
414
+ suggestions.push('Ensure variable is declared before use');
415
+ suggestions.push('Verify variable scope and imports');
416
+ }
417
+ else if (errorType === 'RangeError') {
418
+ suggestions.push('Check that values are within acceptable range');
419
+ suggestions.push('Verify numeric limits are not exceeded');
420
+ }
421
+ else if (errorType === 'SyntaxError') {
422
+ suggestions.push('Check file syntax for errors');
423
+ suggestions.push('Verify JSON structure if parsing JSON');
424
+ suggestions.push('Review recent changes to the file');
425
+ }
426
+ // Message-based suggestions
427
+ if (message.includes('memory')) {
428
+ suggestions.push('Close other applications to free memory');
429
+ suggestions.push('Increase available system memory');
430
+ suggestions.push('Break operation into smaller chunks');
431
+ }
432
+ else if (message.includes('timeout')) {
433
+ suggestions.push('Increase timeout duration');
434
+ suggestions.push('Check network connectivity');
435
+ suggestions.push('Optimize operation performance');
436
+ }
437
+ // Default suggestion if none matched
438
+ if (suggestions.length === 0) {
439
+ suggestions.push('Check the error message for more details');
440
+ suggestions.push('Try the operation again');
441
+ suggestions.push('Contact support if the problem persists');
442
+ }
443
+ return suggestions;
444
+ }
445
+ /**
446
+ * Main error formatting function for user-friendly error display.
447
+ *
448
+ * Transforms a raw error into a structured, sanitized error object suitable
449
+ * for display to end users while preserving technical details for logging.
450
+ *
451
+ * @param error - The error to format
452
+ * @param options - Optional formatting options
453
+ * @param options.code - Override error code
454
+ * @param options.includeStack - Include stack trace in output (default: false for users)
455
+ * @param options.sanitize - Sanitize message for user display (default: true)
456
+ * @returns Formatted error object with user-friendly message
457
+ *
458
+ * @throws Never throws, always returns a valid FormattedError
459
+ *
460
+ * @example
461
+ * ```typescript
462
+ * // File system error
463
+ * try {
464
+ * fs.readFileSync('/etc/shadow'); // EACCES
465
+ * } catch (error) {
466
+ * const formatted = formatErrorForUser(error, { code: ErrorCode.EACCES });
467
+ * // {
468
+ * // code: 'EACCES',
469
+ * // message: 'Permission denied. Check file permissions.',
470
+ * // technicalDetails: 'Error: EACCES: permission denied, open ...',
471
+ * // suggestions: [
472
+ * // 'Check file/directory permissions',
473
+ * // 'Try running with elevated privileges if necessary',
474
+ * // 'Ensure the file owner allows read/write access'
475
+ * // ],
476
+ * // timestamp: 2024-01-15T10:30:45.123Z
477
+ * // }
478
+ * }
479
+ * ```
480
+ *
481
+ * ```typescript
482
+ * // API validation error
483
+ * const error = new TypeError('Cannot read property "name" of undefined');
484
+ * const formatted = formatErrorForUser(error);
485
+ * // {
486
+ * // code: 'E002',
487
+ * // message: 'Invalid input provided',
488
+ * // technicalDetails: 'TypeError: Cannot read property "name" of undefined',
489
+ * // suggestions: [
490
+ * // 'Verify that variables are initialized before use',
491
+ * // 'Check that function arguments are of correct type',
492
+ * // 'Ensure objects have expected properties'
493
+ * // ],
494
+ * // timestamp: 2024-01-15T10:30:45.123Z
495
+ * // }
496
+ * ```
497
+ *
498
+ * ```typescript
499
+ * // Network timeout
500
+ * const error = new Error('ETIMEDOUT: connection timed out');
501
+ * const formatted = formatErrorForUser(error, { code: ErrorCode.ETIMEDOUT });
502
+ * // {
503
+ * // code: 'ETIMEDOUT',
504
+ * // message: 'Request timed out. Please try again.',
505
+ * // suggestions: [
506
+ * // 'Check your internet connection',
507
+ * // 'Try again in a few moments',
508
+ * // 'Verify the server is online'
509
+ * // ],
510
+ * // timestamp: 2024-01-15T10:30:45.123Z
511
+ * // }
512
+ * ```
513
+ *
514
+ * @usage
515
+ * ```typescript
516
+ * // In Express middleware
517
+ * app.use((err, req, res, next) => {
518
+ * const formatted = formatErrorForUser(err);
519
+ *
520
+ * // Log full technical details
521
+ * internalLogger.error(formatted.technicalDetails);
522
+ *
523
+ * // Send user-friendly response
524
+ * res.status(500).json({
525
+ * error: formatted.message,
526
+ * code: formatted.code,
527
+ * suggestions: formatted.suggestions
528
+ * });
529
+ * });
530
+ *
531
+ * // In CLI applications
532
+ * async function main() {
533
+ * try {
534
+ * await performAction();
535
+ * } catch (error) {
536
+ * const formatted = formatErrorForUser(error);
537
+ * console.error(`Error: ${formatted.message}`);
538
+ * console.error('Recovery steps:');
539
+ * formatted.suggestions.forEach((s, i) => {
540
+ * console.error(` ${i + 1}. ${s}`);
541
+ * });
542
+ * process.exit(1);
543
+ * }
544
+ * }
545
+ *
546
+ * // In React components
547
+ * function ErrorBoundary(props: any) {
548
+ * const [error, setError] = React.useState<FormattedError | null>(null);
549
+ *
550
+ * if (error) {
551
+ * const formatted = formatErrorForUser(error.originalError);
552
+ * return (
553
+ * <ErrorDisplay
554
+ * message={formatted.message}
555
+ * suggestions={formatted.suggestions}
556
+ * onRetry={retry}
557
+ * />
558
+ * );
559
+ * }
560
+ * }
561
+ * ```
562
+ */
563
+ export function formatErrorForUser(error, options) {
564
+ const sanitize = options?.sanitize !== false;
565
+ const includeStack = options?.includeStack ?? false;
566
+ const rawMessage = extractErrorMessage(error);
567
+ const errorType = categorizeError(error);
568
+ const stack = extractStackTrace(error);
569
+ const suggestions = getRecoverySuggestions(error, options?.code);
570
+ // Determine error code
571
+ let code = options?.code ?? ErrorCode.UNKNOWN;
572
+ if (!options?.code) {
573
+ // Try to infer code from error
574
+ if (error instanceof Error) {
575
+ if (rawMessage.includes('ENOENT'))
576
+ code = ErrorCode.ENOENT;
577
+ else if (rawMessage.includes('EACCES'))
578
+ code = ErrorCode.EACCES;
579
+ else if (rawMessage.includes('EISDIR'))
580
+ code = ErrorCode.EISDIR;
581
+ else if (rawMessage.includes('EEXIST'))
582
+ code = ErrorCode.EEXIST;
583
+ else if (rawMessage.includes('ETIMEDOUT'))
584
+ code = ErrorCode.ETIMEDOUT;
585
+ else if (rawMessage.includes('ECONNREFUSED'))
586
+ code = ErrorCode.ECONNREFUSED;
587
+ else if (errorType === 'TypeError')
588
+ code = ErrorCode.VALIDATION;
589
+ else if (errorType === 'SyntaxError')
590
+ code = ErrorCode.PARSE_ERROR;
591
+ }
592
+ }
593
+ // Create user-friendly message
594
+ let userMessage = sanitize ? sanitizeErrorMessage(rawMessage) : rawMessage;
595
+ // Enhance message with context if it's too generic
596
+ if (userMessage === 'An unknown error occurred' || userMessage.length < 5) {
597
+ if (code === ErrorCode.EACCES)
598
+ userMessage = 'Permission denied. Check your access rights.';
599
+ else if (code === ErrorCode.ENOENT)
600
+ userMessage = 'The requested file or resource was not found.';
601
+ else if (code === ErrorCode.TIMEOUT)
602
+ userMessage = 'The operation timed out. Please try again.';
603
+ else if (code === ErrorCode.NETWORK)
604
+ userMessage = 'A network error occurred. Check your connection.';
605
+ else if (code === ErrorCode.VALIDATION)
606
+ userMessage = 'The provided input is invalid.';
607
+ else if (code === ErrorCode.PARSE_ERROR)
608
+ userMessage = 'Failed to parse data. Check the format.';
609
+ else
610
+ userMessage = `An error occurred (${errorType}). Please try again.`;
611
+ }
612
+ return {
613
+ code,
614
+ message: userMessage,
615
+ technicalDetails: `${errorType}: ${rawMessage}${stack ? '\n' + stack : ''}`,
616
+ stack: includeStack ? stack : undefined,
617
+ suggestions,
618
+ originalError: error,
619
+ timestamp: new Date(),
620
+ };
621
+ }
622
+ /**
623
+ * Wraps a promise to handle errors gracefully.
624
+ *
625
+ * Returns [data, error] tuple similar to Go's error handling pattern.
626
+ * Makes error handling explicit and type-safe.
627
+ *
628
+ * @param promise - Promise to wrap
629
+ * @returns Tuple of [data, error]
630
+ *
631
+ * @example
632
+ * ```typescript
633
+ * const [data, error] = await handlePromise(fetch('/api/users'));
634
+ *
635
+ * if (error) {
636
+ * const formatted = formatErrorForUser(error);
637
+ * showErrorNotification(formatted.message);
638
+ * return;
639
+ * }
640
+ *
641
+ * // data is guaranteed to exist here
642
+ * processUsers(data);
643
+ * ```
644
+ *
645
+ * @usage
646
+ * ```typescript
647
+ * // Cleaner async/await error handling
648
+ * async function loadUserData(userId: string) {
649
+ * const [user, error] = await handlePromise(
650
+ * fetch(`/api/users/${userId}`).then(r => r.json())
651
+ * );
652
+ *
653
+ * if (error) {
654
+ * return { success: false, error: formatErrorForUser(error) };
655
+ * }
656
+ *
657
+ * return { success: true, data: user };
658
+ * }
659
+ * ```
660
+ */
661
+ export async function handlePromise(promise) {
662
+ try {
663
+ const data = await promise;
664
+ return [data, null];
665
+ }
666
+ catch (error) {
667
+ const err = error instanceof Error ? error : new Error(String(error));
668
+ return [null, err];
669
+ }
670
+ }
671
+ /**
672
+ * Retries an operation with exponential backoff.
673
+ *
674
+ * Useful for transient failures (network issues, temporary unavailability).
675
+ *
676
+ * @param fn - Async function to retry
677
+ * @param maxAttempts - Maximum number of attempts (default: 3)
678
+ * @param baseDelay - Base delay in milliseconds (default: 1000)
679
+ * @returns Promise that resolves with function result or rejects with last error
680
+ *
681
+ * @example
682
+ * ```typescript
683
+ * const data = await retryWithBackoff(
684
+ * () => fetch('/api/data').then(r => r.json()),
685
+ * 3,
686
+ * 1000
687
+ * );
688
+ * // Attempts:
689
+ * // 1. Immediately
690
+ * // 2. After ~1000ms
691
+ * // 3. After ~2000ms
692
+ * ```
693
+ *
694
+ * @usage
695
+ * ```typescript
696
+ * // Resilient API calls
697
+ * async function fetchUserWithRetry(userId: string) {
698
+ * return retryWithBackoff(
699
+ * async () => {
700
+ * const response = await fetch(`/api/users/${userId}`);
701
+ * if (!response.ok) throw new Error('API error');
702
+ * return response.json();
703
+ * },
704
+ * 3,
705
+ * 1000
706
+ * );
707
+ * }
708
+ * ```
709
+ */
710
+ export async function retryWithBackoff(fn, maxAttempts = 3, baseDelay = 1000) {
711
+ let lastError = null;
712
+ for (let attempt = 0; attempt < maxAttempts; attempt++) {
713
+ try {
714
+ return await fn();
715
+ }
716
+ catch (error) {
717
+ lastError = error instanceof Error ? error : new Error(String(error));
718
+ if (attempt < maxAttempts - 1) {
719
+ const delay = baseDelay * Math.pow(2, attempt);
720
+ await new Promise((resolve) => setTimeout(resolve, delay));
721
+ }
722
+ }
723
+ }
724
+ throw lastError || new Error('Operation failed after retries');
725
+ }
726
+ //# sourceMappingURL=error-handler.js.map