@orbytautomation/engine 0.2.4 → 0.4.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.
Files changed (156) hide show
  1. package/README.md +1 -1
  2. package/dist/adapters/AdapterRegistry.d.ts.map +1 -1
  3. package/dist/adapters/AdapterRegistry.js +6 -0
  4. package/dist/adapters/AdapterRegistry.js.map +1 -1
  5. package/dist/context/VariableResolver.d.ts.map +1 -1
  6. package/dist/context/VariableResolver.js +7 -0
  7. package/dist/context/VariableResolver.js.map +1 -1
  8. package/dist/core/OrbytEngine.d.ts +19 -0
  9. package/dist/core/OrbytEngine.d.ts.map +1 -1
  10. package/dist/core/OrbytEngine.js +79 -3
  11. package/dist/core/OrbytEngine.js.map +1 -1
  12. package/dist/core/index.d.ts +1 -1
  13. package/dist/core/index.d.ts.map +1 -1
  14. package/dist/core/index.js +1 -1
  15. package/dist/core/index.js.map +1 -1
  16. package/dist/errors/ErrorCodes.d.ts +205 -6
  17. package/dist/errors/ErrorCodes.d.ts.map +1 -1
  18. package/dist/errors/ErrorCodes.js +398 -5
  19. package/dist/errors/ErrorCodes.js.map +1 -1
  20. package/dist/errors/ErrorDebugger.d.ts +98 -0
  21. package/dist/errors/ErrorDebugger.d.ts.map +1 -0
  22. package/dist/errors/ErrorDebugger.js +290 -0
  23. package/dist/errors/ErrorDebugger.js.map +1 -0
  24. package/dist/errors/ErrorDetector.d.ts +148 -0
  25. package/dist/errors/ErrorDetector.d.ts.map +1 -0
  26. package/dist/errors/ErrorDetector.js +370 -0
  27. package/dist/errors/ErrorDetector.js.map +1 -0
  28. package/dist/errors/ErrorFormatter.d.ts +92 -3
  29. package/dist/errors/ErrorFormatter.d.ts.map +1 -1
  30. package/dist/errors/ErrorFormatter.js +220 -4
  31. package/dist/errors/ErrorFormatter.js.map +1 -1
  32. package/dist/errors/ErrorHandler.d.ts +259 -0
  33. package/dist/errors/ErrorHandler.d.ts.map +1 -0
  34. package/dist/errors/ErrorHandler.js +378 -0
  35. package/dist/errors/ErrorHandler.js.map +1 -0
  36. package/dist/errors/FieldRegistry.d.ts +39 -0
  37. package/dist/errors/FieldRegistry.d.ts.map +1 -1
  38. package/dist/errors/FieldRegistry.js +172 -74
  39. package/dist/errors/FieldRegistry.js.map +1 -1
  40. package/dist/errors/OrbytError.d.ts +85 -3
  41. package/dist/errors/OrbytError.d.ts.map +1 -1
  42. package/dist/errors/OrbytError.js +151 -4
  43. package/dist/errors/OrbytError.js.map +1 -1
  44. package/dist/errors/SchedulerError.d.ts +93 -1
  45. package/dist/errors/SchedulerError.d.ts.map +1 -1
  46. package/dist/errors/SchedulerError.js +145 -1
  47. package/dist/errors/SchedulerError.js.map +1 -1
  48. package/dist/errors/SecurityErrors.d.ts +94 -12
  49. package/dist/errors/SecurityErrors.d.ts.map +1 -1
  50. package/dist/errors/SecurityErrors.js +162 -18
  51. package/dist/errors/SecurityErrors.js.map +1 -1
  52. package/dist/errors/StepError.d.ts +111 -1
  53. package/dist/errors/StepError.d.ts.map +1 -1
  54. package/dist/errors/StepError.js +182 -1
  55. package/dist/errors/StepError.js.map +1 -1
  56. package/dist/errors/WorkflowError.d.ts +139 -2
  57. package/dist/errors/WorkflowError.d.ts.map +1 -1
  58. package/dist/errors/WorkflowError.js +264 -22
  59. package/dist/errors/WorkflowError.js.map +1 -1
  60. package/dist/errors/index.d.ts +5 -1
  61. package/dist/errors/index.d.ts.map +1 -1
  62. package/dist/errors/index.js +7 -4
  63. package/dist/errors/index.js.map +1 -1
  64. package/dist/execution/ExecutionEngine.d.ts.map +1 -1
  65. package/dist/execution/ExecutionEngine.js +36 -6
  66. package/dist/execution/ExecutionEngine.js.map +1 -1
  67. package/dist/execution/ExecutionPlan.d.ts.map +1 -1
  68. package/dist/execution/ExecutionPlan.js +21 -1
  69. package/dist/execution/ExecutionPlan.js.map +1 -1
  70. package/dist/execution/IntentAnalyzer.d.ts.map +1 -1
  71. package/dist/execution/IntentAnalyzer.js +20 -0
  72. package/dist/execution/IntentAnalyzer.js.map +1 -1
  73. package/dist/execution/StepExecutor.d.ts.map +1 -1
  74. package/dist/execution/StepExecutor.js +109 -29
  75. package/dist/execution/StepExecutor.js.map +1 -1
  76. package/dist/execution/WorkflowExecutor.d.ts.map +1 -1
  77. package/dist/execution/WorkflowExecutor.js +31 -0
  78. package/dist/execution/WorkflowExecutor.js.map +1 -1
  79. package/dist/explanation/ExplanationGenerator.d.ts +105 -0
  80. package/dist/explanation/ExplanationGenerator.d.ts.map +1 -0
  81. package/dist/explanation/ExplanationGenerator.js +814 -0
  82. package/dist/explanation/ExplanationGenerator.js.map +1 -0
  83. package/dist/explanation/ExplanationLogger.d.ts +50 -0
  84. package/dist/explanation/ExplanationLogger.d.ts.map +1 -0
  85. package/dist/explanation/ExplanationLogger.js +284 -0
  86. package/dist/explanation/ExplanationLogger.js.map +1 -0
  87. package/dist/explanation/ExplanationTypes.d.ts +252 -0
  88. package/dist/explanation/ExplanationTypes.d.ts.map +1 -0
  89. package/dist/explanation/ExplanationTypes.js +10 -0
  90. package/dist/explanation/ExplanationTypes.js.map +1 -0
  91. package/dist/explanation/index.d.ts +12 -0
  92. package/dist/explanation/index.d.ts.map +1 -0
  93. package/dist/explanation/index.js +11 -0
  94. package/dist/explanation/index.js.map +1 -0
  95. package/dist/hooks/HookManager.d.ts.map +1 -1
  96. package/dist/hooks/HookManager.js +8 -0
  97. package/dist/hooks/HookManager.js.map +1 -1
  98. package/dist/index.d.ts +3 -0
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +2 -0
  101. package/dist/index.js.map +1 -1
  102. package/dist/lifecycle/ShutdownManager.d.ts.map +1 -1
  103. package/dist/lifecycle/ShutdownManager.js +22 -9
  104. package/dist/lifecycle/ShutdownManager.js.map +1 -1
  105. package/dist/lifecycle/StartupManager.d.ts.map +1 -1
  106. package/dist/lifecycle/StartupManager.js +16 -5
  107. package/dist/lifecycle/StartupManager.js.map +1 -1
  108. package/dist/loader/WorkflowLoader.d.ts +83 -21
  109. package/dist/loader/WorkflowLoader.d.ts.map +1 -1
  110. package/dist/loader/WorkflowLoader.js +169 -55
  111. package/dist/loader/WorkflowLoader.js.map +1 -1
  112. package/dist/logging/EngineLogger.d.ts +492 -0
  113. package/dist/logging/EngineLogger.d.ts.map +1 -0
  114. package/dist/logging/EngineLogger.js +1170 -0
  115. package/dist/logging/EngineLogger.js.map +1 -0
  116. package/dist/logging/LoggerManager.d.ts +49 -0
  117. package/dist/logging/LoggerManager.d.ts.map +1 -0
  118. package/dist/logging/LoggerManager.js +94 -0
  119. package/dist/logging/LoggerManager.js.map +1 -0
  120. package/dist/logging/index.d.ts +2 -1
  121. package/dist/logging/index.d.ts.map +1 -1
  122. package/dist/logging/index.js +2 -3
  123. package/dist/logging/index.js.map +1 -1
  124. package/dist/parser/SchemaValidator.d.ts.map +1 -1
  125. package/dist/parser/SchemaValidator.js +8 -1
  126. package/dist/parser/SchemaValidator.js.map +1 -1
  127. package/dist/parser/StepParser.d.ts +6 -1
  128. package/dist/parser/StepParser.d.ts.map +1 -1
  129. package/dist/parser/StepParser.js +14 -1
  130. package/dist/parser/StepParser.js.map +1 -1
  131. package/dist/parser/WorkflowParser.d.ts.map +1 -1
  132. package/dist/parser/WorkflowParser.js +53 -28
  133. package/dist/parser/WorkflowParser.js.map +1 -1
  134. package/dist/scheduling/ScheduleParser.d.ts.map +1 -1
  135. package/dist/scheduling/ScheduleParser.js +7 -0
  136. package/dist/scheduling/ScheduleParser.js.map +1 -1
  137. package/dist/scheduling/Scheduler.d.ts.map +1 -1
  138. package/dist/scheduling/Scheduler.js +13 -0
  139. package/dist/scheduling/Scheduler.js.map +1 -1
  140. package/dist/types/log-types.d.ts +105 -0
  141. package/dist/types/log-types.d.ts.map +1 -0
  142. package/dist/types/log-types.js +42 -0
  143. package/dist/types/log-types.js.map +1 -0
  144. package/package.json +1 -1
  145. package/dist/core/EngineLogger.d.ts +0 -182
  146. package/dist/core/EngineLogger.d.ts.map +0 -1
  147. package/dist/core/EngineLogger.js +0 -293
  148. package/dist/core/EngineLogger.js.map +0 -1
  149. package/dist/logging/LogLevel.d.ts +0 -2
  150. package/dist/logging/LogLevel.d.ts.map +0 -1
  151. package/dist/logging/LogLevel.js +0 -2
  152. package/dist/logging/LogLevel.js.map +0 -1
  153. package/dist/logging/Logger.d.ts +0 -2
  154. package/dist/logging/Logger.d.ts.map +0 -1
  155. package/dist/logging/Logger.js +0 -2
  156. package/dist/logging/Logger.js.map +0 -1
@@ -0,0 +1,1170 @@
1
+ /**
2
+ * Engine Logger
3
+ *
4
+ * Provides structured logging for the Orbyt Engine using ecosystem-core utilities.
5
+ * Supports multiple output formats and log levels with proper filtering.
6
+ *
7
+ * Features:
8
+ * - Severity-based log level filtering using LogLevelSeverity
9
+ * - Multiple output formats (pretty, text, json, structured)
10
+ * - Color support with ANSI codes
11
+ * - Engine-generated timestamps (consistent across CLI, API, web dashboards)
12
+ * - Context and error tracking
13
+ * - Performance measurement with automatic severity adjustment
14
+ * - Efficient level comparison using numeric severity
15
+ *
16
+ * Timestamps are generated by the engine to ensure consistency across:
17
+ * - CLI output
18
+ * - API responses
19
+ * - Web dashboard logs
20
+ * - Monitoring systems
21
+ * - Audit trails
22
+ *
23
+ * @module core
24
+ */
25
+ import { LogLevel, LogLevelSeverity, formatLog, createLogEntry, shouldLog, formatTimestamp, } from '@dev-ecosystem/core';
26
+ import { EngineLogType } from '../types/log-types.js';
27
+ /**
28
+ * Re-export formatTimestamp for external use
29
+ * Allows other parts of the system to format timestamps consistently
30
+ */
31
+ export { formatTimestamp };
32
+ /**
33
+ * Engine Logger
34
+ *
35
+ * Wraps ecosystem-core logging utilities with engine-specific configuration.
36
+ */
37
+ export class EngineLogger {
38
+ config;
39
+ formatOptions;
40
+ eventListeners;
41
+ logBuffer; // Structured JSON log buffer
42
+ maxBufferSize = 10000; // Prevent memory leaks
43
+ constructor(config) {
44
+ this.config = {
45
+ level: config.level,
46
+ format: config.format || 'text',
47
+ colors: config.colors ?? true,
48
+ timestamp: config.timestamp ?? true,
49
+ source: config.source || 'Orbyt',
50
+ structuredEvents: config.structuredEvents ?? true, // Default to true for JSON collection
51
+ };
52
+ this.formatOptions = {
53
+ format: this.config.format,
54
+ colors: this.config.colors,
55
+ timestamp: this.config.timestamp,
56
+ includeSource: true,
57
+ };
58
+ this.eventListeners = new Map();
59
+ this.logBuffer = [];
60
+ }
61
+ /**
62
+ * Log a debug message
63
+ */
64
+ debug(message, context) {
65
+ this.log(LogLevel.DEBUG, message, context);
66
+ }
67
+ /**
68
+ * Log an info message
69
+ */
70
+ info(message, context) {
71
+ this.log(LogLevel.INFO, message, context);
72
+ }
73
+ /**
74
+ * Log a warning message
75
+ */
76
+ warn(message, context) {
77
+ this.log(LogLevel.WARN, message, context);
78
+ }
79
+ /**
80
+ * Log an error message
81
+ */
82
+ error(message, error, context) {
83
+ this.log(LogLevel.ERROR, message, context, error);
84
+ }
85
+ /**
86
+ * Log a fatal error message
87
+ */
88
+ fatal(message, error, context) {
89
+ this.log(LogLevel.FATAL, message, context, error);
90
+ }
91
+ // ============================================================================
92
+ // WORKFLOW LIFECYCLE LOGGING
93
+ // ============================================================================
94
+ /**
95
+ * Log workflow started event
96
+ */
97
+ workflowStarted(workflowName, context) {
98
+ this.logEvent({
99
+ type: EngineLogType.WORKFLOW_STARTED,
100
+ timestamp: new Date(),
101
+ message: `Workflow "${workflowName}" started`,
102
+ context,
103
+ });
104
+ }
105
+ /**
106
+ * Log workflow completed event
107
+ */
108
+ workflowCompleted(workflowName, duration, context) {
109
+ this.logEvent({
110
+ type: EngineLogType.WORKFLOW_COMPLETED,
111
+ timestamp: new Date(),
112
+ message: `Workflow "${workflowName}" completed successfully`,
113
+ context,
114
+ metrics: { duration },
115
+ });
116
+ }
117
+ /**
118
+ * Log workflow failed event
119
+ */
120
+ workflowFailed(workflowName, error, duration, context) {
121
+ this.logEvent({
122
+ type: EngineLogType.WORKFLOW_FAILED,
123
+ timestamp: new Date(),
124
+ message: `Workflow "${workflowName}" failed: ${error.message}`,
125
+ context,
126
+ error,
127
+ metrics: { duration },
128
+ });
129
+ }
130
+ /**
131
+ * Log workflow validation event
132
+ */
133
+ workflowValidation(workflowName, isValid, errors) {
134
+ this.logEvent({
135
+ type: EngineLogType.WORKFLOW_VALIDATION,
136
+ timestamp: new Date(),
137
+ message: `Workflow "${workflowName}" validation: ${isValid ? 'PASSED' : 'FAILED'}`,
138
+ context: errors ? { errors } : undefined,
139
+ });
140
+ }
141
+ // ============================================================================
142
+ // STEP LIFECYCLE LOGGING
143
+ // ============================================================================
144
+ /**
145
+ * Log step started event
146
+ */
147
+ stepStarted(stepId, stepName, context) {
148
+ this.logEvent({
149
+ type: EngineLogType.STEP_STARTED,
150
+ timestamp: new Date(),
151
+ message: `Step "${stepName}" (${stepId}) started`,
152
+ context,
153
+ });
154
+ }
155
+ /**
156
+ * Log step completed event
157
+ */
158
+ stepCompleted(stepId, stepName, duration, context) {
159
+ this.logEvent({
160
+ type: EngineLogType.STEP_COMPLETED,
161
+ timestamp: new Date(),
162
+ message: `Step "${stepName}" (${stepId}) completed`,
163
+ context,
164
+ metrics: { duration },
165
+ });
166
+ }
167
+ /**
168
+ * Log step failed event
169
+ */
170
+ stepFailed(stepId, stepName, error, context) {
171
+ this.logEvent({
172
+ type: EngineLogType.STEP_FAILED,
173
+ timestamp: new Date(),
174
+ message: `Step "${stepName}" (${stepId}) failed: ${error.message}`,
175
+ context,
176
+ error,
177
+ });
178
+ }
179
+ /**
180
+ * Log step retry event
181
+ */
182
+ stepRetry(stepId, stepName, attempt, maxAttempts) {
183
+ this.logEvent({
184
+ type: EngineLogType.STEP_RETRY,
185
+ timestamp: new Date(),
186
+ message: `Step "${stepName}" (${stepId}) retry ${attempt}/${maxAttempts}`,
187
+ context: { attempt, maxAttempts },
188
+ });
189
+ }
190
+ /**
191
+ * Log step timeout event
192
+ */
193
+ stepTimeout(stepId, stepName, timeout) {
194
+ this.logEvent({
195
+ type: EngineLogType.STEP_TIMEOUT,
196
+ timestamp: new Date(),
197
+ message: `Step "${stepName}" (${stepId}) timed out after ${timeout}ms`,
198
+ context: { timeout },
199
+ });
200
+ }
201
+ // ============================================================================
202
+ // EXPLANATION LOGGING
203
+ // ============================================================================
204
+ /**
205
+ * Log explanation generated event
206
+ */
207
+ explanationGenerated(workflowName, stepCount, strategy) {
208
+ this.logEvent({
209
+ type: EngineLogType.EXPLANATION_GENERATED,
210
+ timestamp: new Date(),
211
+ message: `Explanation generated for "${workflowName}" (${stepCount} steps, ${strategy} strategy)`,
212
+ context: { workflowName, stepCount, strategy },
213
+ });
214
+ }
215
+ /**
216
+ * Log circular dependencies detected
217
+ */
218
+ explanationCycles(workflowName, cycles) {
219
+ this.logEvent({
220
+ type: EngineLogType.EXPLANATION_CYCLES,
221
+ timestamp: new Date(),
222
+ message: `Circular dependencies detected in "${workflowName}"`,
223
+ context: { cycles },
224
+ });
225
+ }
226
+ // ============================================================================
227
+ // ADAPTER & PLUGIN LOGGING
228
+ // ============================================================================
229
+ /**
230
+ * Log adapter loaded event
231
+ */
232
+ adapterLoaded(adapterName, version) {
233
+ this.logEvent({
234
+ type: EngineLogType.ADAPTER_LOADED,
235
+ timestamp: new Date(),
236
+ message: `Adapter "${adapterName}" loaded${version ? ` (v${version})` : ''}`,
237
+ context: { adapterName, version },
238
+ });
239
+ }
240
+ /**
241
+ * Log adapter failed event
242
+ */
243
+ adapterFailed(adapterName, error) {
244
+ this.logEvent({
245
+ type: EngineLogType.ADAPTER_FAILED,
246
+ timestamp: new Date(),
247
+ message: `Adapter "${adapterName}" failed: ${error.message}`,
248
+ context: { adapterName },
249
+ error,
250
+ });
251
+ }
252
+ /**
253
+ * Log plugin installed event
254
+ */
255
+ pluginInstalled(pluginName, source) {
256
+ this.logEvent({
257
+ type: EngineLogType.PLUGIN_INSTALLED,
258
+ timestamp: new Date(),
259
+ message: `Plugin "${pluginName}" installed from ${source}`,
260
+ context: { pluginName, source },
261
+ });
262
+ }
263
+ /**
264
+ * Log plugin verified event
265
+ */
266
+ pluginVerified(pluginName, verified) {
267
+ this.logEvent({
268
+ type: EngineLogType.PLUGIN_VERIFIED,
269
+ timestamp: new Date(),
270
+ message: `Plugin "${pluginName}" verification: ${verified ? 'PASSED' : 'FAILED'}`,
271
+ context: { pluginName, verified },
272
+ });
273
+ }
274
+ // ============================================================================
275
+ // ERROR & DEBUG LOGGING
276
+ // ============================================================================
277
+ /**
278
+ * Log error detected event
279
+ */
280
+ errorDetected(error, context) {
281
+ this.logEvent({
282
+ type: EngineLogType.ERROR_DETECTED,
283
+ timestamp: new Date(),
284
+ message: `Error detected: ${error.message}`,
285
+ context,
286
+ error,
287
+ });
288
+ }
289
+ /**
290
+ * Log error debugged event (with debugging info)
291
+ */
292
+ errorDebugged(error, debugInfo) {
293
+ this.logEvent({
294
+ type: EngineLogType.ERROR_DEBUGGED,
295
+ timestamp: new Date(),
296
+ message: `Error debugged: ${error.message}`,
297
+ context: debugInfo,
298
+ error,
299
+ });
300
+ }
301
+ /**
302
+ * Log validation error event
303
+ */
304
+ validationError(message, errors) {
305
+ this.logEvent({
306
+ type: EngineLogType.VALIDATION_ERROR,
307
+ timestamp: new Date(),
308
+ message,
309
+ context: { errors },
310
+ });
311
+ }
312
+ // ============================================================================
313
+ // PERFORMANCE LOGGING
314
+ // ============================================================================
315
+ /**
316
+ * Log performance metric
317
+ */
318
+ performanceMetric(label, metrics) {
319
+ this.logEvent({
320
+ type: EngineLogType.PERFORMANCE_METRIC,
321
+ timestamp: new Date(),
322
+ message: `Performance: ${label}`,
323
+ metrics,
324
+ });
325
+ }
326
+ /**
327
+ * Log execution time
328
+ */
329
+ executionTime(label, duration, context) {
330
+ this.logEvent({
331
+ type: EngineLogType.EXECUTION_TIME,
332
+ timestamp: new Date(),
333
+ message: `${label}: ${duration}ms`,
334
+ context,
335
+ metrics: { duration },
336
+ });
337
+ }
338
+ // ============================================================================
339
+ // FIELD-LEVEL EXECUTION LOGGING (Dynamic Explanation)
340
+ // ============================================================================
341
+ /**
342
+ * Log field execution - captures every field that gets executed
343
+ * This enables dynamic explanation generation from runtime logs
344
+ */
345
+ fieldExecution(type, field, value, context) {
346
+ // Filter out internal fields (starting with _)
347
+ if (field.startsWith('_'))
348
+ return;
349
+ this.debug(`[Field] ${type}.${field} = ${this.formatValue(value)}`, {
350
+ fieldType: type,
351
+ fieldName: field,
352
+ value: this.sanitizeValue(value),
353
+ ...context,
354
+ });
355
+ }
356
+ /**
357
+ * Log input processing
358
+ */
359
+ inputProcessed(inputName, value, source) {
360
+ this.debug(`[Input] ${inputName} received from ${source}`, {
361
+ input: inputName,
362
+ source,
363
+ value: this.sanitizeValue(value),
364
+ });
365
+ }
366
+ /**
367
+ * Log output generation
368
+ */
369
+ outputGenerated(outputName, value, step) {
370
+ this.debug(`[Output] ${outputName} generated${step ? ` by ${step}` : ''}`, {
371
+ output: outputName,
372
+ step,
373
+ value: this.sanitizeValue(value),
374
+ });
375
+ }
376
+ /**
377
+ * Log context variable access
378
+ */
379
+ contextAccessed(variable, value, step) {
380
+ this.debug(`[Context] ${variable} accessed by ${step}`, {
381
+ variable,
382
+ step,
383
+ value: this.sanitizeValue(value),
384
+ });
385
+ }
386
+ /**
387
+ * Log secret access (without exposing values)
388
+ */
389
+ secretAccessed(secretKey, step) {
390
+ this.debug(`[Secret] ${secretKey} accessed by ${step}`, {
391
+ secretKey,
392
+ step,
393
+ exposed: false, // Never log secret values
394
+ });
395
+ }
396
+ /**
397
+ * Log variable resolution
398
+ */
399
+ variableResolved(variable, resolvedValue, context) {
400
+ this.debug(`[Variable] ${variable} resolved`, {
401
+ variable,
402
+ resolved: this.sanitizeValue(resolvedValue),
403
+ ...context,
404
+ });
405
+ }
406
+ /**
407
+ * Log adapter action execution
408
+ */
409
+ adapterActionExecuted(adapter, action, duration, success) {
410
+ const message = `[Adapter] ${adapter}.${action} ${success ? 'completed' : 'failed'} in ${duration}ms`;
411
+ const context = { adapter, action, duration, success };
412
+ if (success) {
413
+ this.info(message, context);
414
+ }
415
+ else {
416
+ this.error(message, undefined, context);
417
+ }
418
+ }
419
+ // ============================================================================
420
+ // PARSING & VALIDATION LOGGING
421
+ // ============================================================================
422
+ /**
423
+ * Log parsing start
424
+ */
425
+ parsingStarted(source, format) {
426
+ this.debug(`[Parser] Parsing ${format} from ${source}`, {
427
+ source,
428
+ format,
429
+ });
430
+ }
431
+ /**
432
+ * Log parsing success
433
+ */
434
+ parsingCompleted(source, duration, stats) {
435
+ this.info(`[Parser] Parsed successfully in ${duration}ms`, {
436
+ source,
437
+ duration,
438
+ ...stats,
439
+ });
440
+ }
441
+ /**
442
+ * Log parsing error
443
+ */
444
+ parsingFailed(source, error, context) {
445
+ this.error(`[Parser] Parsing failed: ${error.message}`, error, {
446
+ source,
447
+ ...context,
448
+ });
449
+ }
450
+ /**
451
+ * Log validation start
452
+ */
453
+ validationStarted(target, type) {
454
+ this.debug(`[Validator] Validating ${type}: ${target}`, {
455
+ target,
456
+ type,
457
+ });
458
+ }
459
+ /**
460
+ * Log validation success
461
+ */
462
+ validationPassed(target, type, duration) {
463
+ this.info(`[Validator] Validation passed: ${target}`, {
464
+ target,
465
+ type,
466
+ duration,
467
+ });
468
+ }
469
+ /**
470
+ * Log validation failure
471
+ */
472
+ validationFailed(target, type, errors) {
473
+ this.error(`[Validator] Validation failed: ${target}`, undefined, {
474
+ target,
475
+ type,
476
+ errors,
477
+ errorCount: errors.length,
478
+ });
479
+ }
480
+ // ============================================================================
481
+ // ERROR DETECTION & DEBUGGING LOGGING
482
+ // ============================================================================
483
+ /**
484
+ * Log error enrichment (when ErrorDetector adds debugging info)
485
+ */
486
+ errorEnriched(error, debugInfo) {
487
+ this.debug(`[ErrorDetector] Error enriched with debugging info`, {
488
+ errorType: error.name,
489
+ errorMessage: error.message,
490
+ ...debugInfo,
491
+ });
492
+ }
493
+ /**
494
+ * Log error debugging output
495
+ */
496
+ errorDebugOutput(error, explanation, fixSteps) {
497
+ this.info(`[ErrorDebugger] Generated debugging output for ${error.name}`, {
498
+ errorType: error.name,
499
+ explanation,
500
+ fixSteps,
501
+ stepCount: fixSteps.length,
502
+ });
503
+ }
504
+ // ============================================================================
505
+ // EXECUTION PHASE LOGGING
506
+ // ============================================================================
507
+ /**
508
+ * Log execution phase start
509
+ */
510
+ phaseStarted(phase, stepIds) {
511
+ this.info(`[Execution] Phase ${phase} started with ${stepIds.length} step(s)`, {
512
+ phase,
513
+ stepIds,
514
+ stepCount: stepIds.length,
515
+ });
516
+ }
517
+ /**
518
+ * Log execution phase completion
519
+ */
520
+ phaseCompleted(phase, duration, successCount, failureCount) {
521
+ this.info(`[Execution] Phase ${phase} completed in ${duration}ms`, {
522
+ phase,
523
+ duration,
524
+ successCount,
525
+ failureCount,
526
+ totalSteps: successCount + failureCount,
527
+ });
528
+ }
529
+ // ============================================================================
530
+ // UTILITY METHODS
531
+ // ============================================================================
532
+ /**
533
+ * Format value for logging (truncate large values)
534
+ */
535
+ formatValue(value) {
536
+ if (value === null)
537
+ return 'null';
538
+ if (value === undefined)
539
+ return 'undefined';
540
+ if (typeof value === 'string') {
541
+ return value.length > 100 ? `${value.substring(0, 97)}...` : value;
542
+ }
543
+ if (typeof value === 'object') {
544
+ const str = JSON.stringify(value);
545
+ return str.length > 200 ? `${str.substring(0, 197)}...` : str;
546
+ }
547
+ return String(value);
548
+ }
549
+ /**
550
+ * Sanitize value for logging (remove sensitive data)
551
+ */
552
+ sanitizeValue(value) {
553
+ if (value === null || value === undefined)
554
+ return value;
555
+ // For objects, recursively sanitize
556
+ if (typeof value === 'object' && !Array.isArray(value)) {
557
+ const sanitized = {};
558
+ for (const [key, val] of Object.entries(value)) {
559
+ // Skip internal fields
560
+ if (key.startsWith('_'))
561
+ continue;
562
+ // Mask sensitive fields
563
+ if (this.isSensitiveField(key)) {
564
+ sanitized[key] = '***REDACTED***';
565
+ }
566
+ else if (typeof val === 'object') {
567
+ sanitized[key] = this.sanitizeValue(val);
568
+ }
569
+ else {
570
+ sanitized[key] = val;
571
+ }
572
+ }
573
+ return sanitized;
574
+ }
575
+ return value;
576
+ }
577
+ /**
578
+ * Check if field name suggests sensitive data
579
+ */
580
+ isSensitiveField(fieldName) {
581
+ const sensitivePatterns = [
582
+ 'password', 'secret', 'token', 'key', 'credential',
583
+ 'apikey', 'api_key', 'auth', 'private',
584
+ ];
585
+ const lowerField = fieldName.toLowerCase();
586
+ return sensitivePatterns.some(pattern => lowerField.includes(pattern));
587
+ }
588
+ /**
589
+ * Log with a custom level
590
+ */
591
+ logWithLevel(level, message, context) {
592
+ this.log(level, message, context);
593
+ }
594
+ /**
595
+ * Log only if severity meets minimum threshold
596
+ */
597
+ logIfSeverity(minSeverity, level, message, context) {
598
+ if (LogLevelSeverity[level] >= minSeverity) {
599
+ this.log(level, message, context);
600
+ }
601
+ }
602
+ /**
603
+ * Measure and log execution time with appropriate log level based on duration
604
+ */
605
+ async measureExecution(label, fn, thresholds) {
606
+ const start = Date.now();
607
+ try {
608
+ const result = await fn();
609
+ const duration = Date.now() - start;
610
+ // Choose log level based on duration thresholds
611
+ let level = LogLevel.DEBUG;
612
+ if (thresholds?.error && duration > thresholds.error) {
613
+ level = LogLevel.ERROR;
614
+ }
615
+ else if (thresholds?.warn && duration > thresholds.warn) {
616
+ level = LogLevel.WARN;
617
+ }
618
+ else {
619
+ level = LogLevel.INFO;
620
+ }
621
+ this.log(level, `${label} completed`, { duration: `${duration}ms` });
622
+ return result;
623
+ }
624
+ catch (error) {
625
+ const duration = Date.now() - start;
626
+ this.log(LogLevel.ERROR, `${label} failed`, { duration: `${duration}ms` }, error instanceof Error ? error : new Error(String(error)));
627
+ throw error;
628
+ }
629
+ }
630
+ /**
631
+ * Log a structured engine event
632
+ */
633
+ logEvent(event) {
634
+ // Add to JSON buffer (always, regardless of log level)
635
+ this.addToBuffer(event);
636
+ // Emit event to listeners if structured events enabled
637
+ if (this.config.structuredEvents) {
638
+ this.emitEvent(event);
639
+ }
640
+ // Determine log level based on event type
641
+ const level = this.getLogLevelForEventType(event.type);
642
+ // Check if this level should be logged
643
+ if (!this.shouldLogLevel(level)) {
644
+ return;
645
+ }
646
+ // Build context with metrics if present
647
+ const fullContext = {
648
+ ...event.context,
649
+ ...(event.metrics && { metrics: event.metrics }),
650
+ };
651
+ // Log through standard log method
652
+ this.log(level, event.message, fullContext, event.error);
653
+ }
654
+ /**
655
+ * Get appropriate log level for event type
656
+ */
657
+ getLogLevelForEventType(type) {
658
+ // Error events
659
+ if (type.includes('failed') || type.includes('error') || type.includes('timeout')) {
660
+ return LogLevel.ERROR;
661
+ }
662
+ // Warning events
663
+ if (type.includes('retry') || type.includes('cycles') || type === EngineLogType.WARNING) {
664
+ return LogLevel.WARN;
665
+ }
666
+ // Debug events
667
+ if (type === EngineLogType.DEBUG || type.includes('debug')) {
668
+ return LogLevel.DEBUG;
669
+ }
670
+ // Default to INFO
671
+ return LogLevel.INFO;
672
+ }
673
+ /**
674
+ * Emit event to registered listeners
675
+ */
676
+ emitEvent(event) {
677
+ const listeners = this.eventListeners.get(event.type) || [];
678
+ for (const listener of listeners) {
679
+ try {
680
+ listener(event);
681
+ }
682
+ catch (error) {
683
+ // Don't let listener errors crash the logger
684
+ console.error('Error in log event listener:', error);
685
+ }
686
+ }
687
+ // Also emit to wildcard listeners
688
+ const wildcardListeners = this.eventListeners.get(EngineLogType.INFO) || [];
689
+ for (const listener of wildcardListeners) {
690
+ try {
691
+ listener(event);
692
+ }
693
+ catch (error) {
694
+ console.error('Error in wildcard log event listener:', error);
695
+ }
696
+ }
697
+ }
698
+ /**
699
+ * Subscribe to specific log event types
700
+ */
701
+ on(type, listener) {
702
+ if (!this.eventListeners.has(type)) {
703
+ this.eventListeners.set(type, []);
704
+ }
705
+ this.eventListeners.get(type).push(listener);
706
+ // Return unsubscribe function
707
+ return () => {
708
+ const listeners = this.eventListeners.get(type);
709
+ if (listeners) {
710
+ const index = listeners.indexOf(listener);
711
+ if (index > -1) {
712
+ listeners.splice(index, 1);
713
+ }
714
+ }
715
+ };
716
+ }
717
+ /**
718
+ * Internal log method
719
+ */
720
+ log(level, message, context, error) {
721
+ // Check if this level should be logged (using severity for better performance)
722
+ if (!this.shouldLogLevel(level)) {
723
+ return;
724
+ }
725
+ // Create log entry
726
+ const entry = createLogEntry(level, message, {
727
+ source: this.config.source,
728
+ context,
729
+ error,
730
+ });
731
+ // Add basic logs to buffer as well (for comprehensive JSON output)
732
+ this.addToBuffer({
733
+ type: this.mapLogLevelToEventType(level),
734
+ timestamp: new Date(),
735
+ message,
736
+ context,
737
+ error,
738
+ });
739
+ // Format and output
740
+ const formatted = formatLog(entry, this.formatOptions);
741
+ console.log(formatted);
742
+ }
743
+ /**
744
+ * Map LogLevel to EngineLogType
745
+ */
746
+ mapLogLevelToEventType(level) {
747
+ switch (level) {
748
+ case LogLevel.DEBUG: return EngineLogType.DEBUG;
749
+ case LogLevel.INFO: return EngineLogType.INFO;
750
+ case LogLevel.WARN: return EngineLogType.WARNING;
751
+ case LogLevel.ERROR:
752
+ case LogLevel.FATAL: return EngineLogType.ERROR;
753
+ default: return EngineLogType.INFO;
754
+ }
755
+ }
756
+ /**
757
+ * Check if a level should be logged using severity comparison
758
+ */
759
+ shouldLogLevel(level) {
760
+ return LogLevelSeverity[level] >= LogLevelSeverity[this.config.level];
761
+ }
762
+ /**
763
+ * Check if a level is more severe than another
764
+ */
765
+ isMoreSevere(level, compareWith) {
766
+ return LogLevelSeverity[level] > LogLevelSeverity[compareWith];
767
+ }
768
+ /**
769
+ * Get severity difference between two levels
770
+ */
771
+ getSeverityDiff(level1, level2) {
772
+ return LogLevelSeverity[level1] - LogLevelSeverity[level2];
773
+ }
774
+ /**
775
+ * Get the numeric severity of the current log level
776
+ */
777
+ getCurrentSeverity() {
778
+ return LogLevelSeverity[this.config.level];
779
+ }
780
+ /**
781
+ * Get the numeric severity of a log level
782
+ */
783
+ getSeverity(level) {
784
+ return LogLevelSeverity[level];
785
+ }
786
+ /**
787
+ * Update logger configuration
788
+ */
789
+ setLevel(level) {
790
+ this.config.level = level;
791
+ }
792
+ /**
793
+ * Set level by severity (0-4)
794
+ */
795
+ setLevelBySeverity(severity) {
796
+ const levels = Object.entries(LogLevelSeverity)
797
+ .find(([_, sev]) => sev === severity);
798
+ if (levels) {
799
+ this.config.level = levels[0];
800
+ }
801
+ }
802
+ /**
803
+ * Update colors setting
804
+ */
805
+ setColors(enabled) {
806
+ this.config.colors = enabled;
807
+ this.formatOptions.colors = enabled;
808
+ }
809
+ /**
810
+ * Update format
811
+ */
812
+ setFormat(format) {
813
+ this.config.format = format;
814
+ this.formatOptions.format = format;
815
+ }
816
+ /**
817
+ * Update timestamp setting
818
+ */
819
+ setTimestamp(enabled) {
820
+ this.config.timestamp = enabled;
821
+ this.formatOptions.timestamp = enabled;
822
+ }
823
+ /**
824
+ * Update timestamp format
825
+ *
826
+ * @param _format - 'time' | 'datetime' | 'full' (reserved for future use)
827
+ */
828
+ setTimestampFormat(_format) {
829
+ // Timestamp format is handled by ecosystem-core formatTimestamp function
830
+ // This method is kept for API compatibility but doesn't modify formatOptions
831
+ }
832
+ /**
833
+ * Format a timestamp using engine's timestamp formatter
834
+ * Useful for consistent timestamp formatting across the system
835
+ *
836
+ * @param date - Date to format (defaults to current time)
837
+ * @param format - Format type ('time', 'datetime', or 'full')
838
+ * @returns Formatted timestamp string
839
+ */
840
+ formatTimestamp(date, format = 'time') {
841
+ return formatTimestamp(date || new Date(), format);
842
+ }
843
+ /**
844
+ * Check if a level will be logged (uses shouldLog from ecosystem-core)
845
+ */
846
+ willLog(level) {
847
+ return shouldLog(level, this.config.level);
848
+ }
849
+ /**
850
+ * Get current configuration
851
+ */
852
+ getConfig() {
853
+ return { ...this.config };
854
+ }
855
+ /**
856
+ * Check if debug logging is enabled
857
+ */
858
+ isDebugEnabled() {
859
+ return this.willLog(LogLevel.DEBUG);
860
+ }
861
+ /**
862
+ * Check if info logging is enabled
863
+ */
864
+ isInfoEnabled() {
865
+ return this.willLog(LogLevel.INFO);
866
+ }
867
+ /**
868
+ * Check if warn logging is enabled
869
+ */
870
+ isWarnEnabled() {
871
+ return this.willLog(LogLevel.WARN);
872
+ }
873
+ /**
874
+ * Check if error logging is enabled
875
+ */
876
+ isErrorEnabled() {
877
+ return this.willLog(LogLevel.ERROR);
878
+ }
879
+ // ============================================================================
880
+ // JSON LOG BUFFER MANAGEMENT
881
+ // ============================================================================
882
+ /**
883
+ * Add event to JSON log buffer
884
+ */
885
+ addToBuffer(event) {
886
+ // Add to buffer
887
+ this.logBuffer.push(event);
888
+ // Prevent buffer overflow
889
+ if (this.logBuffer.length > this.maxBufferSize) {
890
+ this.logBuffer.shift(); // Remove oldest log
891
+ }
892
+ }
893
+ /**
894
+ * Get all logs as JSON array
895
+ * This is what CLI, API, dashboards, and explanation system will consume
896
+ */
897
+ getJSONLogs() {
898
+ return [...this.logBuffer]; // Return copy to prevent external mutations
899
+ }
900
+ /**
901
+ * Get logs filtered by type
902
+ */
903
+ getLogsByType(type) {
904
+ return this.logBuffer.filter(log => log.type === type);
905
+ }
906
+ /**
907
+ * Get logs filtered by time range
908
+ */
909
+ getLogsByTimeRange(startTime, endTime) {
910
+ return this.logBuffer.filter(log => log.timestamp >= startTime && log.timestamp <= endTime);
911
+ }
912
+ /**
913
+ * Get logs filtered by multiple criteria
914
+ */
915
+ getLogsFiltered(filter) {
916
+ let filtered = this.logBuffer;
917
+ if (filter.types) {
918
+ filtered = filtered.filter(log => filter.types.includes(log.type));
919
+ }
920
+ if (filter.startTime) {
921
+ filtered = filtered.filter(log => log.timestamp >= filter.startTime);
922
+ }
923
+ if (filter.endTime) {
924
+ filtered = filtered.filter(log => log.timestamp <= filter.endTime);
925
+ }
926
+ if (filter.hasError !== undefined) {
927
+ filtered = filtered.filter(log => filter.hasError ? !!log.error : !log.error);
928
+ }
929
+ if (filter.searchText) {
930
+ const searchLower = filter.searchText.toLowerCase();
931
+ filtered = filtered.filter(log => log.message.toLowerCase().includes(searchLower));
932
+ }
933
+ return filtered;
934
+ }
935
+ /**
936
+ * Get logs by category: Parse events
937
+ */
938
+ getParseLogEvents() {
939
+ return this.logBuffer.filter(log => log.type === EngineLogType.WORKFLOW_VALIDATION);
940
+ }
941
+ /**
942
+ * Get logs by category: Validation events
943
+ */
944
+ getValidationLogEvents() {
945
+ return this.logBuffer.filter(log => log.type === EngineLogType.WORKFLOW_VALIDATION ||
946
+ log.type === EngineLogType.VALIDATION_ERROR);
947
+ }
948
+ /**
949
+ * Get logs by category: Execution events
950
+ */
951
+ getExecutionLogEvents() {
952
+ return this.logBuffer.filter(log => log.type === EngineLogType.WORKFLOW_STARTED ||
953
+ log.type === EngineLogType.WORKFLOW_COMPLETED ||
954
+ log.type === EngineLogType.WORKFLOW_FAILED ||
955
+ log.type === EngineLogType.STEP_STARTED ||
956
+ log.type === EngineLogType.STEP_COMPLETED ||
957
+ log.type === EngineLogType.STEP_FAILED ||
958
+ log.type === EngineLogType.STEP_RETRY ||
959
+ log.type === EngineLogType.STEP_TIMEOUT ||
960
+ log.type === EngineLogType.EXECUTION_TIME ||
961
+ log.type === EngineLogType.QUEUE_PROCESSING);
962
+ }
963
+ /**
964
+ * Get logs by category: Error events
965
+ */
966
+ getErrorLogEvents() {
967
+ return this.logBuffer.filter(log => log.type === EngineLogType.ERROR_DETECTED ||
968
+ log.type === EngineLogType.ERROR_DEBUGGED ||
969
+ log.type === EngineLogType.VALIDATION_ERROR ||
970
+ log.type === EngineLogType.WORKFLOW_FAILED ||
971
+ log.type === EngineLogType.STEP_FAILED ||
972
+ log.type === EngineLogType.ADAPTER_FAILED ||
973
+ log.type === EngineLogType.ERROR);
974
+ }
975
+ /**
976
+ * Get logs by category: Lifecycle events
977
+ */
978
+ getLifecycleLogEvents() {
979
+ return this.logBuffer.filter(log => log.type === EngineLogType.ENGINE_STARTED ||
980
+ log.type === EngineLogType.ENGINE_STOPPED ||
981
+ log.type === EngineLogType.ADAPTER_LOADED ||
982
+ log.type === EngineLogType.PLUGIN_INSTALLED ||
983
+ log.type === EngineLogType.PLUGIN_VERIFIED);
984
+ }
985
+ /**
986
+ * Get logs by category: Performance events
987
+ */
988
+ getPerformanceLogEvents() {
989
+ return this.logBuffer.filter(log => log.type === EngineLogType.PERFORMANCE_METRIC ||
990
+ log.type === EngineLogType.EXECUTION_TIME);
991
+ }
992
+ /**
993
+ * Export logs as formatted JSON string
994
+ */
995
+ exportLogsAsJSON(pretty = true) {
996
+ return JSON.stringify(this.logBuffer, null, pretty ? 2 : 0);
997
+ }
998
+ /**
999
+ * Export logs grouped by type
1000
+ */
1001
+ exportLogsGrouped() {
1002
+ const grouped = {};
1003
+ for (const log of this.logBuffer) {
1004
+ const type = log.type;
1005
+ if (!grouped[type]) {
1006
+ grouped[type] = [];
1007
+ }
1008
+ grouped[type].push(log);
1009
+ }
1010
+ return grouped;
1011
+ }
1012
+ /**
1013
+ * Get log statistics
1014
+ */
1015
+ getLogStats() {
1016
+ const stats = {
1017
+ total: this.logBuffer.length,
1018
+ byType: {},
1019
+ withErrors: 0,
1020
+ withMetrics: 0,
1021
+ timeRange: {
1022
+ first: this.logBuffer[0]?.timestamp,
1023
+ last: this.logBuffer[this.logBuffer.length - 1]?.timestamp,
1024
+ },
1025
+ };
1026
+ for (const log of this.logBuffer) {
1027
+ // Count by type
1028
+ stats.byType[log.type] = (stats.byType[log.type] || 0) + 1;
1029
+ // Count errors and metrics
1030
+ if (log.error)
1031
+ stats.withErrors++;
1032
+ if (log.metrics)
1033
+ stats.withMetrics++;
1034
+ }
1035
+ return stats;
1036
+ }
1037
+ /**
1038
+ * Clear log buffer
1039
+ */
1040
+ clearLogs() {
1041
+ this.logBuffer = [];
1042
+ }
1043
+ /**
1044
+ * Set maximum buffer size
1045
+ */
1046
+ setMaxBufferSize(size) {
1047
+ this.maxBufferSize = size;
1048
+ // Trim buffer if needed
1049
+ while (this.logBuffer.length > this.maxBufferSize) {
1050
+ this.logBuffer.shift();
1051
+ }
1052
+ }
1053
+ /**
1054
+ * Get current buffer size
1055
+ */
1056
+ getBufferSize() {
1057
+ return this.logBuffer.length;
1058
+ }
1059
+ /**
1060
+ * Export logs in a comprehensive format for consumers (CLI, API, dashboards)
1061
+ */
1062
+ exportLogs() {
1063
+ const stats = this.getLogStats();
1064
+ const grouped = this.exportLogsGrouped();
1065
+ // Build execution summary from logs
1066
+ const execution = this.buildExecutionSummary();
1067
+ return {
1068
+ raw: this.getJSONLogs(),
1069
+ grouped,
1070
+ stats,
1071
+ execution,
1072
+ };
1073
+ }
1074
+ /**
1075
+ * Build execution summary from collected logs
1076
+ * This powers dynamic explanation generation
1077
+ */
1078
+ buildExecutionSummary() {
1079
+ const workflowLogs = this.logBuffer.filter(log => log.type === EngineLogType.WORKFLOW_STARTED ||
1080
+ log.type === EngineLogType.WORKFLOW_COMPLETED ||
1081
+ log.type === EngineLogType.WORKFLOW_FAILED);
1082
+ const stepLogs = this.logBuffer.filter(log => log.type === EngineLogType.STEP_STARTED ||
1083
+ log.type === EngineLogType.STEP_COMPLETED ||
1084
+ log.type === EngineLogType.STEP_FAILED);
1085
+ const errorLogs = this.logBuffer.filter(log => log.error !== undefined ||
1086
+ log.type === EngineLogType.ERROR_DETECTED ||
1087
+ log.type === EngineLogType.VALIDATION_ERROR);
1088
+ const metricLogs = this.logBuffer.filter(log => log.type === EngineLogType.PERFORMANCE_METRIC ||
1089
+ log.type === EngineLogType.EXECUTION_TIME);
1090
+ // Extract workflow info
1091
+ let workflow;
1092
+ const workflowStarted = workflowLogs.find(log => log.type === EngineLogType.WORKFLOW_STARTED);
1093
+ const workflowEnded = workflowLogs.find(log => log.type === EngineLogType.WORKFLOW_COMPLETED ||
1094
+ log.type === EngineLogType.WORKFLOW_FAILED);
1095
+ if (workflowStarted && workflowEnded) {
1096
+ workflow = {
1097
+ name: workflowStarted.context?.workflowName || 'Unknown',
1098
+ status: workflowEnded.type === EngineLogType.WORKFLOW_COMPLETED ? 'completed' : 'failed',
1099
+ duration: workflowEnded.metrics?.duration,
1100
+ };
1101
+ }
1102
+ // Extract step info
1103
+ const steps = [];
1104
+ const stepMap = new Map();
1105
+ for (const log of stepLogs) {
1106
+ const stepId = log.context?.stepId || '';
1107
+ const stepName = log.context?.stepName || '';
1108
+ if (!stepMap.has(stepId)) {
1109
+ stepMap.set(stepId, { id: stepId, name: stepName });
1110
+ }
1111
+ const step = stepMap.get(stepId);
1112
+ if (log.type === EngineLogType.STEP_COMPLETED) {
1113
+ step.status = 'completed';
1114
+ step.duration = log.metrics?.duration;
1115
+ }
1116
+ else if (log.type === EngineLogType.STEP_FAILED) {
1117
+ step.status = 'failed';
1118
+ }
1119
+ else {
1120
+ step.status = 'started';
1121
+ }
1122
+ }
1123
+ steps.push(...stepMap.values());
1124
+ // Extract error info
1125
+ const errors = errorLogs.map(log => ({
1126
+ step: log.context?.stepId || log.context?.stepName,
1127
+ message: log.message,
1128
+ error: log.error,
1129
+ }));
1130
+ // Extract metrics
1131
+ const metrics = metricLogs.map(log => ({
1132
+ label: log.context?.label || 'Unknown',
1133
+ duration: log.metrics?.duration,
1134
+ memory: log.metrics?.memory,
1135
+ }));
1136
+ return {
1137
+ workflow,
1138
+ steps,
1139
+ errors,
1140
+ metrics,
1141
+ };
1142
+ }
1143
+ }
1144
+ /**
1145
+ * Create a logger instance from engine config
1146
+ */
1147
+ export function createEngineLogger(logLevel, verbose = false) {
1148
+ // Silent mode - no logger
1149
+ if (logLevel === 'silent') {
1150
+ return null;
1151
+ }
1152
+ // Map engine log level to ecosystem LogLevel
1153
+ const levelMap = {
1154
+ debug: LogLevel.DEBUG,
1155
+ info: LogLevel.INFO,
1156
+ warn: LogLevel.WARN,
1157
+ error: LogLevel.ERROR,
1158
+ fatal: LogLevel.FATAL,
1159
+ };
1160
+ const level = levelMap[logLevel] || LogLevel.INFO;
1161
+ return new EngineLogger({
1162
+ level,
1163
+ format: verbose ? 'pretty' : 'text',
1164
+ colors: true,
1165
+ timestamp: true, // Enable human-readable timestamps
1166
+ source: 'Orbyt',
1167
+ structuredEvents: true, // Always collect structured JSON logs
1168
+ });
1169
+ }
1170
+ //# sourceMappingURL=EngineLogger.js.map