groundswell 0.0.3 → 1.0.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/LICENSE +21 -0
- package/README.md +26 -9
- package/dist/cache/cache-key.d.ts +20 -0
- package/dist/cache/cache-key.d.ts.map +1 -1
- package/dist/cache/cache-key.js +9 -0
- package/dist/cache/cache-key.js.map +1 -1
- package/dist/core/agent.d.ts +120 -29
- package/dist/core/agent.d.ts.map +1 -1
- package/dist/core/agent.js +584 -177
- package/dist/core/agent.js.map +1 -1
- package/dist/core/mcp-handler.d.ts +63 -5
- package/dist/core/mcp-handler.d.ts.map +1 -1
- package/dist/core/mcp-handler.js +184 -4
- package/dist/core/mcp-handler.js.map +1 -1
- package/dist/core/workflow-context.d.ts +6 -2
- package/dist/core/workflow-context.d.ts.map +1 -1
- package/dist/core/workflow-context.js +99 -4
- package/dist/core/workflow-context.js.map +1 -1
- package/dist/core/workflow.d.ts +315 -13
- package/dist/core/workflow.d.ts.map +1 -1
- package/dist/core/workflow.js +552 -30
- package/dist/core/workflow.js.map +1 -1
- package/dist/debugger/event-replayer.d.ts +422 -0
- package/dist/debugger/event-replayer.d.ts.map +1 -0
- package/dist/debugger/event-replayer.js +639 -0
- package/dist/debugger/event-replayer.js.map +1 -0
- package/dist/debugger/tree-debugger.d.ts +170 -1
- package/dist/debugger/tree-debugger.d.ts.map +1 -1
- package/dist/debugger/tree-debugger.js +423 -1
- package/dist/debugger/tree-debugger.js.map +1 -1
- package/dist/decorators/step.d.ts.map +1 -1
- package/dist/decorators/step.js +129 -47
- package/dist/decorators/step.js.map +1 -1
- package/dist/harnesses/claude-code-harness.d.ts +391 -0
- package/dist/harnesses/claude-code-harness.d.ts.map +1 -0
- package/dist/harnesses/claude-code-harness.js +1076 -0
- package/dist/harnesses/claude-code-harness.js.map +1 -0
- package/dist/harnesses/harness-registry.d.ts +440 -0
- package/dist/harnesses/harness-registry.d.ts.map +1 -0
- package/dist/harnesses/harness-registry.js +543 -0
- package/dist/harnesses/harness-registry.js.map +1 -0
- package/dist/harnesses/index.d.ts +12 -0
- package/dist/harnesses/index.d.ts.map +1 -0
- package/dist/harnesses/index.js +11 -0
- package/dist/harnesses/index.js.map +1 -0
- package/dist/harnesses/pi-harness.d.ts +219 -0
- package/dist/harnesses/pi-harness.d.ts.map +1 -0
- package/dist/harnesses/pi-harness.js +676 -0
- package/dist/harnesses/pi-harness.js.map +1 -0
- package/dist/harnesses/pi-schema-converter.d.ts +24 -0
- package/dist/harnesses/pi-schema-converter.d.ts.map +1 -0
- package/dist/harnesses/pi-schema-converter.js +81 -0
- package/dist/harnesses/pi-schema-converter.js.map +1 -0
- package/dist/harnesses/register-defaults.d.ts +24 -0
- package/dist/harnesses/register-defaults.d.ts.map +1 -0
- package/dist/harnesses/register-defaults.js +40 -0
- package/dist/harnesses/register-defaults.js.map +1 -0
- package/dist/harnesses/session-store.d.ts +201 -0
- package/dist/harnesses/session-store.d.ts.map +1 -0
- package/dist/harnesses/session-store.js +254 -0
- package/dist/harnesses/session-store.js.map +1 -0
- package/dist/index.d.ts +12 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -1
- package/dist/reflection/reflection.d.ts.map +1 -1
- package/dist/reflection/reflection.js +19 -4
- package/dist/reflection/reflection.js.map +1 -1
- package/dist/types/agent.d.ts +1253 -2
- package/dist/types/agent.d.ts.map +1 -1
- package/dist/types/agent.js +418 -1
- package/dist/types/agent.js.map +1 -1
- package/dist/types/decorators.d.ts +10 -1
- package/dist/types/decorators.d.ts.map +1 -1
- package/dist/types/events.d.ts +26 -0
- package/dist/types/events.d.ts.map +1 -1
- package/dist/types/harnesses.d.ts +474 -0
- package/dist/types/harnesses.d.ts.map +1 -0
- package/dist/types/harnesses.js +2 -0
- package/dist/types/harnesses.js.map +1 -0
- package/dist/types/index.d.ts +9 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/providers.d.ts +691 -0
- package/dist/types/providers.d.ts.map +1 -0
- package/dist/types/providers.js +14 -0
- package/dist/types/providers.js.map +1 -0
- package/dist/types/restart.d.ts +132 -0
- package/dist/types/restart.d.ts.map +1 -0
- package/dist/types/restart.js +2 -0
- package/dist/types/restart.js.map +1 -0
- package/dist/types/streaming.d.ts +194 -0
- package/dist/types/streaming.d.ts.map +1 -0
- package/dist/types/streaming.js +67 -0
- package/dist/types/streaming.js.map +1 -0
- package/dist/types/workflow-context.d.ts +137 -1
- package/dist/types/workflow-context.d.ts.map +1 -1
- package/dist/utils/agent-validation.d.ts +88 -0
- package/dist/utils/agent-validation.d.ts.map +1 -0
- package/dist/utils/agent-validation.js +87 -0
- package/dist/utils/agent-validation.js.map +1 -0
- package/dist/utils/delay.d.ts +7 -0
- package/dist/utils/delay.d.ts.map +1 -0
- package/dist/utils/delay.js +9 -0
- package/dist/utils/delay.js.map +1 -0
- package/dist/utils/harness-config.d.ts +180 -0
- package/dist/utils/harness-config.d.ts.map +1 -0
- package/dist/utils/harness-config.js +311 -0
- package/dist/utils/harness-config.js.map +1 -0
- package/dist/utils/index.d.ts +9 -1
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +8 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/model-spec.d.ts +110 -0
- package/dist/utils/model-spec.d.ts.map +1 -0
- package/dist/utils/model-spec.js +149 -0
- package/dist/utils/model-spec.js.map +1 -0
- package/dist/utils/provider-config.d.ts +10 -0
- package/dist/utils/provider-config.d.ts.map +1 -0
- package/dist/utils/provider-config.js +10 -0
- package/dist/utils/provider-config.js.map +1 -0
- package/dist/utils/restart-analysis.d.ts +202 -0
- package/dist/utils/restart-analysis.d.ts.map +1 -0
- package/dist/utils/restart-analysis.js +426 -0
- package/dist/utils/restart-analysis.js.map +1 -0
- package/dist/utils/session-serialization.d.ts +118 -0
- package/dist/utils/session-serialization.d.ts.map +1 -0
- package/dist/utils/session-serialization.js +217 -0
- package/dist/utils/session-serialization.js.map +1 -0
- package/package.json +31 -5
- package/CHANGELOG.md +0 -188
- package/dist/__tests__/adversarial/attachChild-performance.test.d.ts +0 -16
- package/dist/__tests__/adversarial/attachChild-performance.test.d.ts.map +0 -1
- package/dist/__tests__/adversarial/attachChild-performance.test.js +0 -187
- package/dist/__tests__/adversarial/attachChild-performance.test.js.map +0 -1
- package/dist/__tests__/adversarial/circular-reference.test.d.ts +0 -13
- package/dist/__tests__/adversarial/circular-reference.test.d.ts.map +0 -1
- package/dist/__tests__/adversarial/circular-reference.test.js +0 -92
- package/dist/__tests__/adversarial/circular-reference.test.js.map +0 -1
- package/dist/__tests__/adversarial/complex-circular-reference.test.d.ts +0 -16
- package/dist/__tests__/adversarial/complex-circular-reference.test.d.ts.map +0 -1
- package/dist/__tests__/adversarial/complex-circular-reference.test.js +0 -127
- package/dist/__tests__/adversarial/complex-circular-reference.test.js.map +0 -1
- package/dist/__tests__/adversarial/concurrent-task-failures.test.d.ts +0 -21
- package/dist/__tests__/adversarial/concurrent-task-failures.test.d.ts.map +0 -1
- package/dist/__tests__/adversarial/concurrent-task-failures.test.js +0 -667
- package/dist/__tests__/adversarial/concurrent-task-failures.test.js.map +0 -1
- package/dist/__tests__/adversarial/deep-analysis.test.d.ts +0 -6
- package/dist/__tests__/adversarial/deep-analysis.test.d.ts.map +0 -1
- package/dist/__tests__/adversarial/deep-analysis.test.js +0 -877
- package/dist/__tests__/adversarial/deep-analysis.test.js.map +0 -1
- package/dist/__tests__/adversarial/deep-hierarchy-stress.test.d.ts +0 -13
- package/dist/__tests__/adversarial/deep-hierarchy-stress.test.d.ts.map +0 -1
- package/dist/__tests__/adversarial/deep-hierarchy-stress.test.js +0 -186
- package/dist/__tests__/adversarial/deep-hierarchy-stress.test.js.map +0 -1
- package/dist/__tests__/adversarial/e2e-prd-validation.test.d.ts +0 -6
- package/dist/__tests__/adversarial/e2e-prd-validation.test.d.ts.map +0 -1
- package/dist/__tests__/adversarial/e2e-prd-validation.test.js +0 -626
- package/dist/__tests__/adversarial/e2e-prd-validation.test.js.map +0 -1
- package/dist/__tests__/adversarial/edge-case.test.d.ts +0 -6
- package/dist/__tests__/adversarial/edge-case.test.d.ts.map +0 -1
- package/dist/__tests__/adversarial/edge-case.test.js +0 -857
- package/dist/__tests__/adversarial/edge-case.test.js.map +0 -1
- package/dist/__tests__/adversarial/error-merge-strategy.test.d.ts +0 -20
- package/dist/__tests__/adversarial/error-merge-strategy.test.d.ts.map +0 -1
- package/dist/__tests__/adversarial/error-merge-strategy.test.js +0 -907
- package/dist/__tests__/adversarial/error-merge-strategy.test.js.map +0 -1
- package/dist/__tests__/adversarial/incremental-performance.test.d.ts +0 -2
- package/dist/__tests__/adversarial/incremental-performance.test.d.ts.map +0 -1
- package/dist/__tests__/adversarial/incremental-performance.test.js +0 -113
- package/dist/__tests__/adversarial/incremental-performance.test.js.map +0 -1
- package/dist/__tests__/adversarial/node-map-update-benchmarks.test.d.ts +0 -22
- package/dist/__tests__/adversarial/node-map-update-benchmarks.test.d.ts.map +0 -1
- package/dist/__tests__/adversarial/node-map-update-benchmarks.test.js +0 -383
- package/dist/__tests__/adversarial/node-map-update-benchmarks.test.js.map +0 -1
- package/dist/__tests__/adversarial/observer-propagation.test.d.ts +0 -21
- package/dist/__tests__/adversarial/observer-propagation.test.d.ts.map +0 -1
- package/dist/__tests__/adversarial/observer-propagation.test.js +0 -404
- package/dist/__tests__/adversarial/observer-propagation.test.js.map +0 -1
- package/dist/__tests__/adversarial/parent-validation.test.d.ts +0 -13
- package/dist/__tests__/adversarial/parent-validation.test.d.ts.map +0 -1
- package/dist/__tests__/adversarial/parent-validation.test.js +0 -128
- package/dist/__tests__/adversarial/parent-validation.test.js.map +0 -1
- package/dist/__tests__/adversarial/prd-12-2-compliance.test.d.ts +0 -20
- package/dist/__tests__/adversarial/prd-12-2-compliance.test.d.ts.map +0 -1
- package/dist/__tests__/adversarial/prd-12-2-compliance.test.js +0 -482
- package/dist/__tests__/adversarial/prd-12-2-compliance.test.js.map +0 -1
- package/dist/__tests__/adversarial/prd-compliance.test.d.ts +0 -6
- package/dist/__tests__/adversarial/prd-compliance.test.d.ts.map +0 -1
- package/dist/__tests__/adversarial/prd-compliance.test.js +0 -886
- package/dist/__tests__/adversarial/prd-compliance.test.js.map +0 -1
- package/dist/__tests__/compatibility/backward-compatibility.test.d.ts +0 -22
- package/dist/__tests__/compatibility/backward-compatibility.test.d.ts.map +0 -1
- package/dist/__tests__/compatibility/backward-compatibility.test.js +0 -1843
- package/dist/__tests__/compatibility/backward-compatibility.test.js.map +0 -1
- package/dist/__tests__/helpers/index.d.ts +0 -10
- package/dist/__tests__/helpers/index.d.ts.map +0 -1
- package/dist/__tests__/helpers/index.js +0 -10
- package/dist/__tests__/helpers/index.js.map +0 -1
- package/dist/__tests__/helpers/tree-verification.d.ts +0 -90
- package/dist/__tests__/helpers/tree-verification.d.ts.map +0 -1
- package/dist/__tests__/helpers/tree-verification.js +0 -202
- package/dist/__tests__/helpers/tree-verification.js.map +0 -1
- package/dist/__tests__/integration/agent-workflow.test.d.ts +0 -2
- package/dist/__tests__/integration/agent-workflow.test.d.ts.map +0 -1
- package/dist/__tests__/integration/agent-workflow.test.js +0 -256
- package/dist/__tests__/integration/agent-workflow.test.js.map +0 -1
- package/dist/__tests__/integration/bidirectional-consistency.test.d.ts +0 -14
- package/dist/__tests__/integration/bidirectional-consistency.test.d.ts.map +0 -1
- package/dist/__tests__/integration/bidirectional-consistency.test.js +0 -668
- package/dist/__tests__/integration/bidirectional-consistency.test.js.map +0 -1
- package/dist/__tests__/integration/observer-logging.test.d.ts +0 -2
- package/dist/__tests__/integration/observer-logging.test.d.ts.map +0 -1
- package/dist/__tests__/integration/observer-logging.test.js +0 -517
- package/dist/__tests__/integration/observer-logging.test.js.map +0 -1
- package/dist/__tests__/integration/tree-mirroring.test.d.ts +0 -2
- package/dist/__tests__/integration/tree-mirroring.test.d.ts.map +0 -1
- package/dist/__tests__/integration/tree-mirroring.test.js +0 -117
- package/dist/__tests__/integration/tree-mirroring.test.js.map +0 -1
- package/dist/__tests__/integration/workflow-reparenting.test.d.ts +0 -12
- package/dist/__tests__/integration/workflow-reparenting.test.d.ts.map +0 -1
- package/dist/__tests__/integration/workflow-reparenting.test.js +0 -239
- package/dist/__tests__/integration/workflow-reparenting.test.js.map +0 -1
- package/dist/__tests__/unit/agent.test.d.ts +0 -2
- package/dist/__tests__/unit/agent.test.d.ts.map +0 -1
- package/dist/__tests__/unit/agent.test.js +0 -143
- package/dist/__tests__/unit/agent.test.js.map +0 -1
- package/dist/__tests__/unit/cache-key.test.d.ts +0 -5
- package/dist/__tests__/unit/cache-key.test.d.ts.map +0 -1
- package/dist/__tests__/unit/cache-key.test.js +0 -145
- package/dist/__tests__/unit/cache-key.test.js.map +0 -1
- package/dist/__tests__/unit/cache.test.d.ts +0 -5
- package/dist/__tests__/unit/cache.test.d.ts.map +0 -1
- package/dist/__tests__/unit/cache.test.js +0 -132
- package/dist/__tests__/unit/cache.test.js.map +0 -1
- package/dist/__tests__/unit/context.test.d.ts +0 -2
- package/dist/__tests__/unit/context.test.d.ts.map +0 -1
- package/dist/__tests__/unit/context.test.js +0 -220
- package/dist/__tests__/unit/context.test.js.map +0 -1
- package/dist/__tests__/unit/decorators.test.d.ts +0 -2
- package/dist/__tests__/unit/decorators.test.d.ts.map +0 -1
- package/dist/__tests__/unit/decorators.test.js +0 -162
- package/dist/__tests__/unit/decorators.test.js.map +0 -1
- package/dist/__tests__/unit/introspection-tools.test.d.ts +0 -5
- package/dist/__tests__/unit/introspection-tools.test.d.ts.map +0 -1
- package/dist/__tests__/unit/introspection-tools.test.js +0 -191
- package/dist/__tests__/unit/introspection-tools.test.js.map +0 -1
- package/dist/__tests__/unit/logger.test.d.ts +0 -2
- package/dist/__tests__/unit/logger.test.d.ts.map +0 -1
- package/dist/__tests__/unit/logger.test.js +0 -241
- package/dist/__tests__/unit/logger.test.js.map +0 -1
- package/dist/__tests__/unit/observable.test.d.ts +0 -2
- package/dist/__tests__/unit/observable.test.d.ts.map +0 -1
- package/dist/__tests__/unit/observable.test.js +0 -251
- package/dist/__tests__/unit/observable.test.js.map +0 -1
- package/dist/__tests__/unit/prompt.test.d.ts +0 -2
- package/dist/__tests__/unit/prompt.test.d.ts.map +0 -1
- package/dist/__tests__/unit/prompt.test.js +0 -113
- package/dist/__tests__/unit/prompt.test.js.map +0 -1
- package/dist/__tests__/unit/reflection.test.d.ts +0 -5
- package/dist/__tests__/unit/reflection.test.d.ts.map +0 -1
- package/dist/__tests__/unit/reflection.test.js +0 -160
- package/dist/__tests__/unit/reflection.test.js.map +0 -1
- package/dist/__tests__/unit/tree-debugger-incremental.test.d.ts +0 -2
- package/dist/__tests__/unit/tree-debugger-incremental.test.d.ts.map +0 -1
- package/dist/__tests__/unit/tree-debugger-incremental.test.js +0 -136
- package/dist/__tests__/unit/tree-debugger-incremental.test.js.map +0 -1
- package/dist/__tests__/unit/tree-debugger.test.d.ts +0 -2
- package/dist/__tests__/unit/tree-debugger.test.d.ts.map +0 -1
- package/dist/__tests__/unit/tree-debugger.test.js +0 -69
- package/dist/__tests__/unit/tree-debugger.test.js.map +0 -1
- package/dist/__tests__/unit/utils/workflow-error-utils.test.d.ts +0 -2
- package/dist/__tests__/unit/utils/workflow-error-utils.test.d.ts.map +0 -1
- package/dist/__tests__/unit/utils/workflow-error-utils.test.js +0 -154
- package/dist/__tests__/unit/utils/workflow-error-utils.test.js.map +0 -1
- package/dist/__tests__/unit/workflow-detachChild.test.d.ts +0 -2
- package/dist/__tests__/unit/workflow-detachChild.test.d.ts.map +0 -1
- package/dist/__tests__/unit/workflow-detachChild.test.js +0 -76
- package/dist/__tests__/unit/workflow-detachChild.test.js.map +0 -1
- package/dist/__tests__/unit/workflow-emitEvent-childDetached.test.d.ts +0 -2
- package/dist/__tests__/unit/workflow-emitEvent-childDetached.test.d.ts.map +0 -1
- package/dist/__tests__/unit/workflow-emitEvent-childDetached.test.js +0 -122
- package/dist/__tests__/unit/workflow-emitEvent-childDetached.test.js.map +0 -1
- package/dist/__tests__/unit/workflow-isDescendantOf.test.d.ts +0 -2
- package/dist/__tests__/unit/workflow-isDescendantOf.test.d.ts.map +0 -1
- package/dist/__tests__/unit/workflow-isDescendantOf.test.js +0 -140
- package/dist/__tests__/unit/workflow-isDescendantOf.test.js.map +0 -1
- package/dist/__tests__/unit/workflow.test.d.ts +0 -2
- package/dist/__tests__/unit/workflow.test.d.ts.map +0 -1
- package/dist/__tests__/unit/workflow.test.js +0 -330
- package/dist/__tests__/unit/workflow.test.js.map +0 -1
|
@@ -12,11 +12,38 @@ export declare class WorkflowTreeDebugger implements WorkflowObserver {
|
|
|
12
12
|
readonly events: Observable<WorkflowEvent>;
|
|
13
13
|
/** Node lookup map for quick access */
|
|
14
14
|
private nodeMap;
|
|
15
|
+
/** Event history for persistence (only when persistEvents is true) */
|
|
16
|
+
private eventHistory;
|
|
17
|
+
/** Whether to persist events to memory */
|
|
18
|
+
private persistEvents;
|
|
19
|
+
/** Maximum event history size (optional, for memory management) */
|
|
20
|
+
private maxEventHistorySize?;
|
|
15
21
|
/**
|
|
16
22
|
* Create a tree debugger attached to a workflow
|
|
17
23
|
* @param workflow The root workflow to debug
|
|
24
|
+
* @param options Configuration options
|
|
25
|
+
* @param options.persistEvents Whether to accumulate event history (default: false)
|
|
26
|
+
* @param options.maxEventHistorySize Maximum number of events to keep (optional, FIFO eviction)
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* // Without persistence (default)
|
|
31
|
+
* const debugger = new WorkflowTreeDebugger(workflow);
|
|
32
|
+
*
|
|
33
|
+
* // With persistence enabled
|
|
34
|
+
* const debugger = new WorkflowTreeDebugger(workflow, { persistEvents: true });
|
|
35
|
+
*
|
|
36
|
+
* // With persistence and size limit
|
|
37
|
+
* const debugger = new WorkflowTreeDebugger(workflow, {
|
|
38
|
+
* persistEvents: true,
|
|
39
|
+
* maxEventHistorySize: 10000,
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
18
42
|
*/
|
|
19
|
-
constructor(workflow: Workflow
|
|
43
|
+
constructor(workflow: Workflow, options?: {
|
|
44
|
+
persistEvents?: boolean;
|
|
45
|
+
maxEventHistorySize?: number;
|
|
46
|
+
});
|
|
20
47
|
/**
|
|
21
48
|
* Build node lookup map recursively
|
|
22
49
|
*/
|
|
@@ -28,6 +55,12 @@ export declare class WorkflowTreeDebugger implements WorkflowObserver {
|
|
|
28
55
|
*/
|
|
29
56
|
private removeSubtreeNodes;
|
|
30
57
|
onLog(_entry: LogEntry): void;
|
|
58
|
+
/**
|
|
59
|
+
* Handle workflow events from observer interface
|
|
60
|
+
* Captures events for history if persistence enabled, handles structural updates, forwards to stream
|
|
61
|
+
*
|
|
62
|
+
* @param event - The workflow event to handle
|
|
63
|
+
*/
|
|
31
64
|
onEvent(event: WorkflowEvent): void;
|
|
32
65
|
onStateUpdated(_node: WorkflowNode): void;
|
|
33
66
|
onTreeChanged(root: WorkflowNode): void;
|
|
@@ -67,5 +100,141 @@ export declare class WorkflowTreeDebugger implements WorkflowObserver {
|
|
|
67
100
|
totalEvents: number;
|
|
68
101
|
};
|
|
69
102
|
private collectStats;
|
|
103
|
+
/**
|
|
104
|
+
* Get the accumulated event history
|
|
105
|
+
* Returns a copy to prevent external modification
|
|
106
|
+
*
|
|
107
|
+
* @returns Copy of event history array, or empty array if persistence disabled
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```typescript
|
|
111
|
+
* const debugger = new WorkflowTreeDebugger(workflow, { persistEvents: true });
|
|
112
|
+
* await workflow.run();
|
|
113
|
+
* const events = debugger.getEventHistory();
|
|
114
|
+
* console.log(`Captured ${events.length} events`);
|
|
115
|
+
* ```
|
|
116
|
+
*/
|
|
117
|
+
getEventHistory(): WorkflowEvent[];
|
|
118
|
+
/**
|
|
119
|
+
* Serialize a WorkflowEvent to JSON-safe format
|
|
120
|
+
* Extracts only primitive fields to avoid circular references in WorkflowNode objects
|
|
121
|
+
*
|
|
122
|
+
* **Strategy:**
|
|
123
|
+
* - Extract nodeId and nodeName from WorkflowNode references
|
|
124
|
+
* - Skip WorkflowNode.parent, WorkflowNode.children (circular refs)
|
|
125
|
+
* - Skip WorkflowError.original (could be circular)
|
|
126
|
+
* - Add timestamp for chronological ordering
|
|
127
|
+
*
|
|
128
|
+
* **Circular Reference Handling:**
|
|
129
|
+
* - WorkflowNode has bidirectional links (parent ↔ children)
|
|
130
|
+
* - WorkflowNode.events[] contains WorkflowEvents that reference WorkflowNodes
|
|
131
|
+
* - JSON.stringify would throw TypeError without selective extraction
|
|
132
|
+
*
|
|
133
|
+
* @param event - The workflow event to serialize
|
|
134
|
+
* @returns JSON-safe object with primitive fields only
|
|
135
|
+
*
|
|
136
|
+
* @example
|
|
137
|
+
* ```typescript
|
|
138
|
+
* const event: WorkflowEvent = {
|
|
139
|
+
* type: 'stateSnapshot',
|
|
140
|
+
* node: { id: 'wf-123', name: 'MyWorkflow', ... }
|
|
141
|
+
* };
|
|
142
|
+
* const serialized = serializeEvent(event);
|
|
143
|
+
* // { type: 'stateSnapshot', timestamp: 1234567890, nodeId: 'wf-123', nodeName: 'MyWorkflow', stateSnapshot: {...} }
|
|
144
|
+
* ```
|
|
145
|
+
*/
|
|
146
|
+
private serializeEvent;
|
|
147
|
+
/**
|
|
148
|
+
* Save event history to a JSON file
|
|
149
|
+
* Serializes events to avoid circular references and writes to disk
|
|
150
|
+
*
|
|
151
|
+
* **Serialization Strategy:**
|
|
152
|
+
* - Uses serializeEvent() to extract primitive fields only
|
|
153
|
+
* - Avoids circular references in WorkflowNode objects
|
|
154
|
+
* - Adds timestamp for chronological ordering
|
|
155
|
+
*
|
|
156
|
+
* **Error Handling:**
|
|
157
|
+
* - Throws descriptive errors for file system issues
|
|
158
|
+
* - Does not modify internal event history on failure
|
|
159
|
+
*
|
|
160
|
+
* @param path - File path to write event history
|
|
161
|
+
* @throws {Error} If file cannot be written (permission denied, disk full, etc.)
|
|
162
|
+
* @throws {Error} If event persistence is not enabled
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* const debugger = new WorkflowTreeDebugger(workflow, { persistEvents: true });
|
|
167
|
+
* await workflow.run();
|
|
168
|
+
* await debugger.saveEventHistory('./workflow-execution.json');
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
saveEventHistory(path: string): Promise<void>;
|
|
172
|
+
/**
|
|
173
|
+
* Load event history from a JSON file
|
|
174
|
+
* Static method that can be called without instantiating WorkflowTreeDebugger
|
|
175
|
+
*
|
|
176
|
+
* **Error Handling:**
|
|
177
|
+
* - Throws descriptive errors for file system issues
|
|
178
|
+
* - Throws descriptive errors for invalid JSON
|
|
179
|
+
*
|
|
180
|
+
* @param path - File path to read event history from
|
|
181
|
+
* @returns Parsed event array (unknown[] - caller should validate structure)
|
|
182
|
+
* @throws {Error} If file does not exist
|
|
183
|
+
* @throws {Error} If file cannot be read (permission denied, etc.)
|
|
184
|
+
* @throws {Error} If file contains invalid JSON
|
|
185
|
+
*
|
|
186
|
+
* @example
|
|
187
|
+
* ```typescript
|
|
188
|
+
* const events = await WorkflowTreeDebugger.loadEventHistory('./workflow-execution.json');
|
|
189
|
+
*
|
|
190
|
+
* // Use with WorkflowEventReplayer
|
|
191
|
+
* const replayer = new WorkflowEventReplayer();
|
|
192
|
+
* const tree = replayer.replay(events as WorkflowEvent[]);
|
|
193
|
+
* ```
|
|
194
|
+
*/
|
|
195
|
+
static loadEventHistory(path: string): Promise<unknown[]>;
|
|
196
|
+
/**
|
|
197
|
+
* Replay workflow execution from saved event history file.
|
|
198
|
+
*
|
|
199
|
+
* This is a convenience method that combines loadEventHistory and
|
|
200
|
+
* WorkflowEventReplayer.replay() for one-call restoration of workflow trees.
|
|
201
|
+
*
|
|
202
|
+
* **Use Case**: Time-travel debugging - reconstruct workflow tree from saved events
|
|
203
|
+
* to inspect execution after completion without requiring the live workflow instance.
|
|
204
|
+
*
|
|
205
|
+
* **Workflow**:
|
|
206
|
+
* 1. Load events from file using loadEventHistory()
|
|
207
|
+
* 2. Create WorkflowEventReplayer instance
|
|
208
|
+
* 3. Replay events and return reconstructed tree
|
|
209
|
+
*
|
|
210
|
+
* **Error Handling**:
|
|
211
|
+
* - Throws descriptive errors for file operations (delegated to loadEventHistory)
|
|
212
|
+
* - Wraps replay errors with file path context
|
|
213
|
+
*
|
|
214
|
+
* **Returns**: Read-only WorkflowNode tree (no live workflow attached)
|
|
215
|
+
*
|
|
216
|
+
* @param path - File path to saved event history JSON file
|
|
217
|
+
* @returns Reconstructed workflow tree root node
|
|
218
|
+
* @throws {Error} If file cannot be read or parsed
|
|
219
|
+
* @throws {Error} If events cannot be replayed (empty events, no root established)
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```typescript
|
|
223
|
+
* // Save event history during execution
|
|
224
|
+
* const debugger = new WorkflowTreeDebugger(workflow, { persistEvents: true });
|
|
225
|
+
* await workflow.run();
|
|
226
|
+
* await debugger.saveEventHistory('./workflow-events.json');
|
|
227
|
+
*
|
|
228
|
+
* // Later, replay the events to reconstruct the tree
|
|
229
|
+
* const tree = await WorkflowTreeDebugger.replay('./workflow-events.json');
|
|
230
|
+
* console.log(`Restored tree with ${tree.children.length} children`);
|
|
231
|
+
*
|
|
232
|
+
* // Use debugger instance to inspect the reconstructed tree
|
|
233
|
+
* const debugInstance = new WorkflowTreeDebugger({ getNode: () => tree });
|
|
234
|
+
* console.log(debugInstance.toTreeString(tree));
|
|
235
|
+
* console.log(debugInstance.getStats());
|
|
236
|
+
* ```
|
|
237
|
+
*/
|
|
238
|
+
static replay(path: string): Promise<WorkflowNode>;
|
|
70
239
|
}
|
|
71
240
|
//# sourceMappingURL=tree-debugger.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree-debugger.d.ts","sourceRoot":"","sources":["../../src/debugger/tree-debugger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,QAAQ,EACT,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"tree-debugger.d.ts","sourceRoot":"","sources":["../../src/debugger/tree-debugger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,QAAQ,EACT,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAepD;;;GAGG;AACH,qBAAa,oBAAqB,YAAW,gBAAgB;IAC3D,qCAAqC;IACrC,OAAO,CAAC,IAAI,CAAe;IAE3B,2CAA2C;IAC3C,SAAgB,MAAM,EAAE,UAAU,CAAC,aAAa,CAAC,CAAC;IAElD,uCAAuC;IACvC,OAAO,CAAC,OAAO,CAAwC;IAEvD,sEAAsE;IACtE,OAAO,CAAC,YAAY,CAAuB;IAE3C,0CAA0C;IAC1C,OAAO,CAAC,aAAa,CAAkB;IAEvC,mEAAmE;IACnE,OAAO,CAAC,mBAAmB,CAAC,CAAS;IAErC;;;;;;;;;;;;;;;;;;;;;OAqBG;gBAED,QAAQ,EAAE,QAAQ,EAClB,OAAO,CAAC,EAAE;QAAE,aAAa,CAAC,EAAE,OAAO,CAAC;QAAC,mBAAmB,CAAC,EAAE,MAAM,CAAA;KAAE;IAqBrE;;OAEG;IACH,OAAO,CAAC,YAAY;IAOpB;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAuB1B,KAAK,CAAC,MAAM,EAAE,QAAQ,GAAG,IAAI;IAI7B;;;;;OAKG;IACH,OAAO,CAAC,KAAK,EAAE,aAAa,GAAG,IAAI;IAuCnC,cAAc,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI;IAIzC,aAAa,CAAC,IAAI,EAAE,YAAY,GAAG,IAAI;IAUvC;;OAEG;IACH,OAAO,IAAI,YAAY;IAIvB;;OAEG;IACH,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAI7C;;;OAGG;IACH,YAAY,CAAC,IAAI,CAAC,EAAE,YAAY,GAAG,MAAM;IAIzC;;OAEG;IACH,OAAO,CAAC,UAAU;IA8BlB;;;OAGG;IACH,WAAW,CAAC,IAAI,CAAC,EAAE,YAAY,GAAG,MAAM;IAiBxC;;OAEG;IACH,OAAO,CAAC,WAAW;IAUnB;;OAEG;IACH,QAAQ,IAAI;QACV,UAAU,EAAE,MAAM,CAAC;QACnB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;KACrB;IAYD,OAAO,CAAC,YAAY;IAkBpB;;;;;;;;;;;;;OAaG;IACH,eAAe,IAAI,aAAa,EAAE;IAQlC;;;;;;;;;;;;;;;;;;;;;;;;;;;OA2BG;IACH,OAAO,CAAC,cAAc;IAiLtB;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACG,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA6CnD;;;;;;;;;;;;;;;;;;;;;;OAsBG;WACU,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC;IA2C/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAyCG;WACU,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;CAkBzD"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { Observable } from '../utils/observable.js';
|
|
2
|
+
import { writeFile, readFile } from 'fs/promises';
|
|
3
|
+
import { WorkflowEventReplayer } from './event-replayer.js';
|
|
2
4
|
/**
|
|
3
5
|
* Status symbols for tree visualization
|
|
4
6
|
*/
|
|
@@ -20,13 +22,44 @@ export class WorkflowTreeDebugger {
|
|
|
20
22
|
events;
|
|
21
23
|
/** Node lookup map for quick access */
|
|
22
24
|
nodeMap = new Map();
|
|
25
|
+
/** Event history for persistence (only when persistEvents is true) */
|
|
26
|
+
eventHistory = [];
|
|
27
|
+
/** Whether to persist events to memory */
|
|
28
|
+
persistEvents = false;
|
|
29
|
+
/** Maximum event history size (optional, for memory management) */
|
|
30
|
+
maxEventHistorySize;
|
|
23
31
|
/**
|
|
24
32
|
* Create a tree debugger attached to a workflow
|
|
25
33
|
* @param workflow The root workflow to debug
|
|
34
|
+
* @param options Configuration options
|
|
35
|
+
* @param options.persistEvents Whether to accumulate event history (default: false)
|
|
36
|
+
* @param options.maxEventHistorySize Maximum number of events to keep (optional, FIFO eviction)
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```typescript
|
|
40
|
+
* // Without persistence (default)
|
|
41
|
+
* const debugger = new WorkflowTreeDebugger(workflow);
|
|
42
|
+
*
|
|
43
|
+
* // With persistence enabled
|
|
44
|
+
* const debugger = new WorkflowTreeDebugger(workflow, { persistEvents: true });
|
|
45
|
+
*
|
|
46
|
+
* // With persistence and size limit
|
|
47
|
+
* const debugger = new WorkflowTreeDebugger(workflow, {
|
|
48
|
+
* persistEvents: true,
|
|
49
|
+
* maxEventHistorySize: 10000,
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
26
52
|
*/
|
|
27
|
-
constructor(workflow) {
|
|
53
|
+
constructor(workflow, options) {
|
|
28
54
|
this.root = workflow.getNode();
|
|
29
55
|
this.events = new Observable();
|
|
56
|
+
// Extract options with defaults
|
|
57
|
+
this.persistEvents = options?.persistEvents ?? false;
|
|
58
|
+
this.maxEventHistorySize = options?.maxEventHistorySize;
|
|
59
|
+
// Initialize event history if persistence enabled
|
|
60
|
+
if (this.persistEvents) {
|
|
61
|
+
this.eventHistory = [];
|
|
62
|
+
}
|
|
30
63
|
// Build initial node map
|
|
31
64
|
this.buildNodeMap(this.root);
|
|
32
65
|
// Register as observer on the workflow
|
|
@@ -68,7 +101,22 @@ export class WorkflowTreeDebugger {
|
|
|
68
101
|
onLog(_entry) {
|
|
69
102
|
// Events are forwarded through the event stream
|
|
70
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Handle workflow events from observer interface
|
|
106
|
+
* Captures events for history if persistence enabled, handles structural updates, forwards to stream
|
|
107
|
+
*
|
|
108
|
+
* @param event - The workflow event to handle
|
|
109
|
+
*/
|
|
71
110
|
onEvent(event) {
|
|
111
|
+
// Capture event for history if persistence enabled
|
|
112
|
+
if (this.persistEvents) {
|
|
113
|
+
// Handle max size limit (FIFO eviction)
|
|
114
|
+
if (this.maxEventHistorySize &&
|
|
115
|
+
this.eventHistory.length >= this.maxEventHistorySize) {
|
|
116
|
+
this.eventHistory.shift(); // Remove oldest event
|
|
117
|
+
}
|
|
118
|
+
this.eventHistory.push(event);
|
|
119
|
+
}
|
|
72
120
|
// Handle structural events with incremental updates
|
|
73
121
|
switch (event.type) {
|
|
74
122
|
case 'childAttached':
|
|
@@ -194,5 +242,379 @@ export class WorkflowTreeDebugger {
|
|
|
194
242
|
this.collectStats(child, stats);
|
|
195
243
|
}
|
|
196
244
|
}
|
|
245
|
+
// ============================================================
|
|
246
|
+
// Event Persistence API
|
|
247
|
+
// ============================================================
|
|
248
|
+
/**
|
|
249
|
+
* Get the accumulated event history
|
|
250
|
+
* Returns a copy to prevent external modification
|
|
251
|
+
*
|
|
252
|
+
* @returns Copy of event history array, or empty array if persistence disabled
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* ```typescript
|
|
256
|
+
* const debugger = new WorkflowTreeDebugger(workflow, { persistEvents: true });
|
|
257
|
+
* await workflow.run();
|
|
258
|
+
* const events = debugger.getEventHistory();
|
|
259
|
+
* console.log(`Captured ${events.length} events`);
|
|
260
|
+
* ```
|
|
261
|
+
*/
|
|
262
|
+
getEventHistory() {
|
|
263
|
+
if (!this.persistEvents) {
|
|
264
|
+
return [];
|
|
265
|
+
}
|
|
266
|
+
// Return copy to prevent external modification
|
|
267
|
+
return [...this.eventHistory];
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Serialize a WorkflowEvent to JSON-safe format
|
|
271
|
+
* Extracts only primitive fields to avoid circular references in WorkflowNode objects
|
|
272
|
+
*
|
|
273
|
+
* **Strategy:**
|
|
274
|
+
* - Extract nodeId and nodeName from WorkflowNode references
|
|
275
|
+
* - Skip WorkflowNode.parent, WorkflowNode.children (circular refs)
|
|
276
|
+
* - Skip WorkflowError.original (could be circular)
|
|
277
|
+
* - Add timestamp for chronological ordering
|
|
278
|
+
*
|
|
279
|
+
* **Circular Reference Handling:**
|
|
280
|
+
* - WorkflowNode has bidirectional links (parent ↔ children)
|
|
281
|
+
* - WorkflowNode.events[] contains WorkflowEvents that reference WorkflowNodes
|
|
282
|
+
* - JSON.stringify would throw TypeError without selective extraction
|
|
283
|
+
*
|
|
284
|
+
* @param event - The workflow event to serialize
|
|
285
|
+
* @returns JSON-safe object with primitive fields only
|
|
286
|
+
*
|
|
287
|
+
* @example
|
|
288
|
+
* ```typescript
|
|
289
|
+
* const event: WorkflowEvent = {
|
|
290
|
+
* type: 'stateSnapshot',
|
|
291
|
+
* node: { id: 'wf-123', name: 'MyWorkflow', ... }
|
|
292
|
+
* };
|
|
293
|
+
* const serialized = serializeEvent(event);
|
|
294
|
+
* // { type: 'stateSnapshot', timestamp: 1234567890, nodeId: 'wf-123', nodeName: 'MyWorkflow', stateSnapshot: {...} }
|
|
295
|
+
* ```
|
|
296
|
+
*/
|
|
297
|
+
serializeEvent(event) {
|
|
298
|
+
const timestamp = Date.now();
|
|
299
|
+
switch (event.type) {
|
|
300
|
+
// Core events
|
|
301
|
+
case 'childAttached':
|
|
302
|
+
return {
|
|
303
|
+
type: event.type,
|
|
304
|
+
timestamp,
|
|
305
|
+
parentId: event.parentId,
|
|
306
|
+
childId: event.child.id,
|
|
307
|
+
childName: event.child.name,
|
|
308
|
+
childStatus: event.child.status,
|
|
309
|
+
};
|
|
310
|
+
case 'childDetached':
|
|
311
|
+
return {
|
|
312
|
+
type: event.type,
|
|
313
|
+
timestamp,
|
|
314
|
+
parentId: event.parentId,
|
|
315
|
+
childId: event.childId,
|
|
316
|
+
};
|
|
317
|
+
case 'stateSnapshot':
|
|
318
|
+
return {
|
|
319
|
+
type: event.type,
|
|
320
|
+
timestamp,
|
|
321
|
+
nodeId: event.node.id,
|
|
322
|
+
nodeName: event.node.name,
|
|
323
|
+
stateSnapshot: event.node.stateSnapshot,
|
|
324
|
+
};
|
|
325
|
+
case 'stepStart':
|
|
326
|
+
return {
|
|
327
|
+
type: event.type,
|
|
328
|
+
timestamp,
|
|
329
|
+
nodeId: event.node.id,
|
|
330
|
+
nodeName: event.node.name,
|
|
331
|
+
step: event.step,
|
|
332
|
+
};
|
|
333
|
+
case 'stepEnd':
|
|
334
|
+
return {
|
|
335
|
+
type: event.type,
|
|
336
|
+
timestamp,
|
|
337
|
+
nodeId: event.node.id,
|
|
338
|
+
nodeName: event.node.name,
|
|
339
|
+
step: event.step,
|
|
340
|
+
duration: event.duration,
|
|
341
|
+
};
|
|
342
|
+
case 'error':
|
|
343
|
+
return {
|
|
344
|
+
type: event.type,
|
|
345
|
+
timestamp,
|
|
346
|
+
nodeId: event.node.id,
|
|
347
|
+
nodeName: event.node.name,
|
|
348
|
+
error: {
|
|
349
|
+
message: event.error.message,
|
|
350
|
+
workflowId: event.error.workflowId,
|
|
351
|
+
state: event.error.state,
|
|
352
|
+
logs: event.error.logs,
|
|
353
|
+
stack: event.error.stack,
|
|
354
|
+
// Skip 'original' field - could be circular
|
|
355
|
+
},
|
|
356
|
+
};
|
|
357
|
+
case 'taskStart':
|
|
358
|
+
case 'taskEnd':
|
|
359
|
+
return {
|
|
360
|
+
type: event.type,
|
|
361
|
+
timestamp,
|
|
362
|
+
nodeId: event.node.id,
|
|
363
|
+
nodeName: event.node.name,
|
|
364
|
+
task: event.task,
|
|
365
|
+
};
|
|
366
|
+
case 'treeUpdated':
|
|
367
|
+
return {
|
|
368
|
+
type: event.type,
|
|
369
|
+
timestamp,
|
|
370
|
+
rootId: event.root.id,
|
|
371
|
+
rootName: event.root.name,
|
|
372
|
+
};
|
|
373
|
+
// Agent/Prompt events
|
|
374
|
+
case 'agentPromptStart':
|
|
375
|
+
return {
|
|
376
|
+
type: event.type,
|
|
377
|
+
timestamp,
|
|
378
|
+
agentId: event.agentId,
|
|
379
|
+
agentName: event.agentName,
|
|
380
|
+
promptId: event.promptId,
|
|
381
|
+
nodeId: event.node.id,
|
|
382
|
+
nodeName: event.node.name,
|
|
383
|
+
};
|
|
384
|
+
case 'agentPromptEnd':
|
|
385
|
+
return {
|
|
386
|
+
type: event.type,
|
|
387
|
+
timestamp,
|
|
388
|
+
agentId: event.agentId,
|
|
389
|
+
agentName: event.agentName,
|
|
390
|
+
promptId: event.promptId,
|
|
391
|
+
nodeId: event.node.id,
|
|
392
|
+
nodeName: event.node.name,
|
|
393
|
+
duration: event.duration,
|
|
394
|
+
tokenUsage: event.tokenUsage,
|
|
395
|
+
};
|
|
396
|
+
// Tool events
|
|
397
|
+
case 'toolInvocation':
|
|
398
|
+
return {
|
|
399
|
+
type: event.type,
|
|
400
|
+
timestamp,
|
|
401
|
+
toolName: event.toolName,
|
|
402
|
+
input: event.input,
|
|
403
|
+
output: event.output,
|
|
404
|
+
duration: event.duration,
|
|
405
|
+
nodeId: event.node.id,
|
|
406
|
+
nodeName: event.node.name,
|
|
407
|
+
};
|
|
408
|
+
// MCP events
|
|
409
|
+
case 'mcpEvent':
|
|
410
|
+
return {
|
|
411
|
+
type: event.type,
|
|
412
|
+
timestamp,
|
|
413
|
+
serverName: event.serverName,
|
|
414
|
+
event: event.event,
|
|
415
|
+
payload: event.payload,
|
|
416
|
+
nodeId: event.node.id,
|
|
417
|
+
nodeName: event.node.name,
|
|
418
|
+
};
|
|
419
|
+
// Reflection events
|
|
420
|
+
case 'reflectionStart':
|
|
421
|
+
return {
|
|
422
|
+
type: event.type,
|
|
423
|
+
timestamp,
|
|
424
|
+
level: event.level,
|
|
425
|
+
nodeId: event.node.id,
|
|
426
|
+
nodeName: event.node.name,
|
|
427
|
+
};
|
|
428
|
+
case 'reflectionEnd':
|
|
429
|
+
return {
|
|
430
|
+
type: event.type,
|
|
431
|
+
timestamp,
|
|
432
|
+
level: event.level,
|
|
433
|
+
success: event.success,
|
|
434
|
+
nodeId: event.node.id,
|
|
435
|
+
nodeName: event.node.name,
|
|
436
|
+
};
|
|
437
|
+
// Cache events
|
|
438
|
+
case 'cacheHit':
|
|
439
|
+
case 'cacheMiss':
|
|
440
|
+
return {
|
|
441
|
+
type: event.type,
|
|
442
|
+
timestamp,
|
|
443
|
+
key: event.key,
|
|
444
|
+
nodeId: event.node.id,
|
|
445
|
+
nodeName: event.node.name,
|
|
446
|
+
};
|
|
447
|
+
default:
|
|
448
|
+
// Should not happen with TypeScript discriminated union
|
|
449
|
+
// But handle gracefully for unknown event types
|
|
450
|
+
return {
|
|
451
|
+
type: event.type,
|
|
452
|
+
timestamp,
|
|
453
|
+
rawData: JSON.stringify(event),
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Save event history to a JSON file
|
|
459
|
+
* Serializes events to avoid circular references and writes to disk
|
|
460
|
+
*
|
|
461
|
+
* **Serialization Strategy:**
|
|
462
|
+
* - Uses serializeEvent() to extract primitive fields only
|
|
463
|
+
* - Avoids circular references in WorkflowNode objects
|
|
464
|
+
* - Adds timestamp for chronological ordering
|
|
465
|
+
*
|
|
466
|
+
* **Error Handling:**
|
|
467
|
+
* - Throws descriptive errors for file system issues
|
|
468
|
+
* - Does not modify internal event history on failure
|
|
469
|
+
*
|
|
470
|
+
* @param path - File path to write event history
|
|
471
|
+
* @throws {Error} If file cannot be written (permission denied, disk full, etc.)
|
|
472
|
+
* @throws {Error} If event persistence is not enabled
|
|
473
|
+
*
|
|
474
|
+
* @example
|
|
475
|
+
* ```typescript
|
|
476
|
+
* const debugger = new WorkflowTreeDebugger(workflow, { persistEvents: true });
|
|
477
|
+
* await workflow.run();
|
|
478
|
+
* await debugger.saveEventHistory('./workflow-execution.json');
|
|
479
|
+
* ```
|
|
480
|
+
*/
|
|
481
|
+
async saveEventHistory(path) {
|
|
482
|
+
if (!this.persistEvents) {
|
|
483
|
+
throw new Error('Event persistence is not enabled. Initialize with { persistEvents: true }');
|
|
484
|
+
}
|
|
485
|
+
try {
|
|
486
|
+
// Serialize all events
|
|
487
|
+
const serialized = this.eventHistory.map((event) => this.serializeEvent(event));
|
|
488
|
+
// Convert to JSON string
|
|
489
|
+
const json = JSON.stringify(serialized, null, 2);
|
|
490
|
+
// Write to file
|
|
491
|
+
await writeFile(path, json, 'utf-8');
|
|
492
|
+
}
|
|
493
|
+
catch (error) {
|
|
494
|
+
const err = error;
|
|
495
|
+
// Enhance error messages with context
|
|
496
|
+
if (err.code === 'ENOENT') {
|
|
497
|
+
throw new Error(`Cannot save event history: Directory does not exist: ${path}`);
|
|
498
|
+
}
|
|
499
|
+
if (err.code === 'EACCES') {
|
|
500
|
+
throw new Error(`Cannot save event history: Permission denied: ${path}`);
|
|
501
|
+
}
|
|
502
|
+
if (err.code === 'ENOSPC') {
|
|
503
|
+
throw new Error(`Cannot save event history: No space left on device`);
|
|
504
|
+
}
|
|
505
|
+
// Re-throw with context
|
|
506
|
+
throw new Error(`Failed to save event history to ${path}: ${err.message}`);
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
/**
|
|
510
|
+
* Load event history from a JSON file
|
|
511
|
+
* Static method that can be called without instantiating WorkflowTreeDebugger
|
|
512
|
+
*
|
|
513
|
+
* **Error Handling:**
|
|
514
|
+
* - Throws descriptive errors for file system issues
|
|
515
|
+
* - Throws descriptive errors for invalid JSON
|
|
516
|
+
*
|
|
517
|
+
* @param path - File path to read event history from
|
|
518
|
+
* @returns Parsed event array (unknown[] - caller should validate structure)
|
|
519
|
+
* @throws {Error} If file does not exist
|
|
520
|
+
* @throws {Error} If file cannot be read (permission denied, etc.)
|
|
521
|
+
* @throws {Error} If file contains invalid JSON
|
|
522
|
+
*
|
|
523
|
+
* @example
|
|
524
|
+
* ```typescript
|
|
525
|
+
* const events = await WorkflowTreeDebugger.loadEventHistory('./workflow-execution.json');
|
|
526
|
+
*
|
|
527
|
+
* // Use with WorkflowEventReplayer
|
|
528
|
+
* const replayer = new WorkflowEventReplayer();
|
|
529
|
+
* const tree = replayer.replay(events as WorkflowEvent[]);
|
|
530
|
+
* ```
|
|
531
|
+
*/
|
|
532
|
+
static async loadEventHistory(path) {
|
|
533
|
+
try {
|
|
534
|
+
// Read file
|
|
535
|
+
const content = await readFile(path, 'utf-8');
|
|
536
|
+
// Parse JSON
|
|
537
|
+
const parsed = JSON.parse(content);
|
|
538
|
+
// Validate it's an array
|
|
539
|
+
if (!Array.isArray(parsed)) {
|
|
540
|
+
throw new Error(`Invalid event history file: Expected array, got ${typeof parsed}`);
|
|
541
|
+
}
|
|
542
|
+
return parsed;
|
|
543
|
+
}
|
|
544
|
+
catch (error) {
|
|
545
|
+
const err = error;
|
|
546
|
+
// Handle file not found
|
|
547
|
+
if (err.code === 'ENOENT') {
|
|
548
|
+
throw new Error(`Event history file not found: ${path}`);
|
|
549
|
+
}
|
|
550
|
+
// Handle permission denied
|
|
551
|
+
if (err.code === 'EACCES') {
|
|
552
|
+
throw new Error(`Permission denied reading file: ${path}`);
|
|
553
|
+
}
|
|
554
|
+
// Handle invalid JSON
|
|
555
|
+
if (err instanceof SyntaxError) {
|
|
556
|
+
throw new Error(`Invalid JSON in event history file: ${path}\n${err.message}`);
|
|
557
|
+
}
|
|
558
|
+
// Re-throw with context
|
|
559
|
+
throw new Error(`Failed to load event history from ${path}: ${err.message}`);
|
|
560
|
+
}
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Replay workflow execution from saved event history file.
|
|
564
|
+
*
|
|
565
|
+
* This is a convenience method that combines loadEventHistory and
|
|
566
|
+
* WorkflowEventReplayer.replay() for one-call restoration of workflow trees.
|
|
567
|
+
*
|
|
568
|
+
* **Use Case**: Time-travel debugging - reconstruct workflow tree from saved events
|
|
569
|
+
* to inspect execution after completion without requiring the live workflow instance.
|
|
570
|
+
*
|
|
571
|
+
* **Workflow**:
|
|
572
|
+
* 1. Load events from file using loadEventHistory()
|
|
573
|
+
* 2. Create WorkflowEventReplayer instance
|
|
574
|
+
* 3. Replay events and return reconstructed tree
|
|
575
|
+
*
|
|
576
|
+
* **Error Handling**:
|
|
577
|
+
* - Throws descriptive errors for file operations (delegated to loadEventHistory)
|
|
578
|
+
* - Wraps replay errors with file path context
|
|
579
|
+
*
|
|
580
|
+
* **Returns**: Read-only WorkflowNode tree (no live workflow attached)
|
|
581
|
+
*
|
|
582
|
+
* @param path - File path to saved event history JSON file
|
|
583
|
+
* @returns Reconstructed workflow tree root node
|
|
584
|
+
* @throws {Error} If file cannot be read or parsed
|
|
585
|
+
* @throws {Error} If events cannot be replayed (empty events, no root established)
|
|
586
|
+
*
|
|
587
|
+
* @example
|
|
588
|
+
* ```typescript
|
|
589
|
+
* // Save event history during execution
|
|
590
|
+
* const debugger = new WorkflowTreeDebugger(workflow, { persistEvents: true });
|
|
591
|
+
* await workflow.run();
|
|
592
|
+
* await debugger.saveEventHistory('./workflow-events.json');
|
|
593
|
+
*
|
|
594
|
+
* // Later, replay the events to reconstruct the tree
|
|
595
|
+
* const tree = await WorkflowTreeDebugger.replay('./workflow-events.json');
|
|
596
|
+
* console.log(`Restored tree with ${tree.children.length} children`);
|
|
597
|
+
*
|
|
598
|
+
* // Use debugger instance to inspect the reconstructed tree
|
|
599
|
+
* const debugInstance = new WorkflowTreeDebugger({ getNode: () => tree });
|
|
600
|
+
* console.log(debugInstance.toTreeString(tree));
|
|
601
|
+
* console.log(debugInstance.getStats());
|
|
602
|
+
* ```
|
|
603
|
+
*/
|
|
604
|
+
static async replay(path) {
|
|
605
|
+
// Load events from file using existing static method
|
|
606
|
+
const events = await WorkflowTreeDebugger.loadEventHistory(path);
|
|
607
|
+
// Create replayer instance
|
|
608
|
+
const replayer = new WorkflowEventReplayer();
|
|
609
|
+
// Replay events with type assertion (loadEventHistory returns unknown[])
|
|
610
|
+
// GOTCHA: Wrap in try-catch to enhance error messages with file path context
|
|
611
|
+
try {
|
|
612
|
+
return replayer.replay(events);
|
|
613
|
+
}
|
|
614
|
+
catch (error) {
|
|
615
|
+
const err = error;
|
|
616
|
+
throw new Error(`Failed to replay events from ${path}: ${err.message}`);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
197
619
|
}
|
|
198
620
|
//# sourceMappingURL=tree-debugger.js.map
|