groundswell 0.0.1

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 (120) hide show
  1. package/.claude/settings.local.json +9 -0
  2. package/.claude/system_prompts/task-breakdown.md +100 -0
  3. package/PRPs/001-hierarchical-workflow-engine.md +2438 -0
  4. package/PRPs/PRDs/001-hierarchical-workflow-engine.md +543 -0
  5. package/PRPs/PRDs/002-agent-prompt.md +390 -0
  6. package/PRPs/PRDs/003-agent-prompt.md +943 -0
  7. package/PRPs/PRDs/004-agent-prompt.md +1136 -0
  8. package/PRPs/PRDs/tasks-001.json +492 -0
  9. package/PRPs/README.md +83 -0
  10. package/PRPs/templates/prp_base.md +222 -0
  11. package/README.md +218 -0
  12. package/docs/agent.md +422 -0
  13. package/docs/prompt.md +419 -0
  14. package/docs/workflow.md +600 -0
  15. package/examples/README.md +244 -0
  16. package/examples/examples/01-basic-workflow.ts +100 -0
  17. package/examples/examples/02-decorator-options.ts +217 -0
  18. package/examples/examples/03-parent-child.ts +241 -0
  19. package/examples/examples/04-observers-debugger.ts +340 -0
  20. package/examples/examples/05-error-handling.ts +387 -0
  21. package/examples/examples/06-concurrent-tasks.ts +352 -0
  22. package/examples/examples/07-agent-loops.ts +432 -0
  23. package/examples/examples/08-sdk-features.ts +667 -0
  24. package/examples/examples/09-reflection.ts +573 -0
  25. package/examples/examples/10-introspection.ts +550 -0
  26. package/examples/index.ts +143 -0
  27. package/examples/utils/helpers.ts +57 -0
  28. package/llms_full.txt +5890 -0
  29. package/package.json +63 -0
  30. package/plan/P1P2/PRP.md +527 -0
  31. package/plan/P1P2/research/LRU_CACHE_BEST_PRACTICES.md +1929 -0
  32. package/plan/P1P2/research/LRU_CACHE_CODE_PATTERNS.md +857 -0
  33. package/plan/P1P2/research/LRU_CACHE_INTEGRATION_GUIDE.md +738 -0
  34. package/plan/P1P2/research/LRU_CACHE_RESEARCH_INDEX.md +424 -0
  35. package/plan/P1P2/research/REFLECTION_INDEX.md +291 -0
  36. package/plan/P1P2/research/REFLECTION_RESEARCH_REPORT.md +1342 -0
  37. package/plan/P1P2/research/RESEARCH_SUMMARY.md +342 -0
  38. package/plan/P1P2/research/anthropic-sdk.md +174 -0
  39. package/plan/P1P2/research/async-local-storage.md +200 -0
  40. package/plan/P1P2/research/reflection-code-patterns.md +1205 -0
  41. package/plan/P1P2/research/reflection-decision-matrix.md +421 -0
  42. package/plan/P1P2/research/reflection-implementation-guide.md +1341 -0
  43. package/plan/P1P2/research/reflection-integration-guide.md +834 -0
  44. package/plan/P1P2/research/reflection-patterns.md +1468 -0
  45. package/plan/P1P2/research/reflection-quick-reference.md +558 -0
  46. package/plan/P1P2/research/zod-schema.md +152 -0
  47. package/plan/P3P4/PRP.md +1388 -0
  48. package/plan/P3P4/research/caching-lru.md +116 -0
  49. package/plan/P3P4/research/introspection-tools.md +177 -0
  50. package/plan/P3P4/research/reflection-patterns.md +117 -0
  51. package/plan/P4P5/PRP.md +1136 -0
  52. package/plan/P4P5/research/RESEARCH_SUMMARY.md +151 -0
  53. package/plan/architecture/external_deps.md +358 -0
  54. package/plan/architecture/system_context.md +242 -0
  55. package/plan/backlog.json +867 -0
  56. package/plan/research/INTROSPECTION_RESEARCH_SUMMARY.md +378 -0
  57. package/plan/research/README-INTROSPECTION.md +352 -0
  58. package/plan/research/agent-introspection-patterns.md +1085 -0
  59. package/plan/research/introspection-security-guide.md +928 -0
  60. package/plan/research/introspection-tool-examples.md +875 -0
  61. package/scripts/generate-llms-full.ts +206 -0
  62. package/src/__tests__/integration/agent-workflow.test.ts +256 -0
  63. package/src/__tests__/integration/tree-mirroring.test.ts +114 -0
  64. package/src/__tests__/unit/agent.test.ts +169 -0
  65. package/src/__tests__/unit/cache-key.test.ts +182 -0
  66. package/src/__tests__/unit/cache.test.ts +172 -0
  67. package/src/__tests__/unit/context.test.ts +138 -0
  68. package/src/__tests__/unit/decorators.test.ts +100 -0
  69. package/src/__tests__/unit/introspection-tools.test.ts +277 -0
  70. package/src/__tests__/unit/prompt.test.ts +135 -0
  71. package/src/__tests__/unit/reflection.test.ts +210 -0
  72. package/src/__tests__/unit/tree-debugger.test.ts +85 -0
  73. package/src/__tests__/unit/workflow.test.ts +81 -0
  74. package/src/cache/cache-key.ts +244 -0
  75. package/src/cache/cache.ts +236 -0
  76. package/src/cache/index.ts +8 -0
  77. package/src/core/agent.ts +573 -0
  78. package/src/core/context.ts +119 -0
  79. package/src/core/event-tree.ts +260 -0
  80. package/src/core/factory.ts +123 -0
  81. package/src/core/index.ts +17 -0
  82. package/src/core/logger.ts +87 -0
  83. package/src/core/mcp-handler.ts +184 -0
  84. package/src/core/prompt.ts +150 -0
  85. package/src/core/workflow-context.ts +349 -0
  86. package/src/core/workflow.ts +302 -0
  87. package/src/debugger/index.ts +1 -0
  88. package/src/debugger/tree-debugger.ts +210 -0
  89. package/src/decorators/index.ts +3 -0
  90. package/src/decorators/observed-state.ts +95 -0
  91. package/src/decorators/step.ts +139 -0
  92. package/src/decorators/task.ts +96 -0
  93. package/src/examples/index.ts +2 -0
  94. package/src/examples/tdd-orchestrator.ts +65 -0
  95. package/src/examples/test-cycle-workflow.ts +64 -0
  96. package/src/index.ts +140 -0
  97. package/src/reflection/index.ts +5 -0
  98. package/src/reflection/reflection.ts +407 -0
  99. package/src/tools/index.ts +36 -0
  100. package/src/tools/introspection.ts +464 -0
  101. package/src/types/agent.ts +90 -0
  102. package/src/types/decorators.ts +25 -0
  103. package/src/types/error-strategy.ts +13 -0
  104. package/src/types/error.ts +20 -0
  105. package/src/types/events.ts +74 -0
  106. package/src/types/index.ts +55 -0
  107. package/src/types/logging.ts +24 -0
  108. package/src/types/observer.ts +18 -0
  109. package/src/types/prompt.ts +40 -0
  110. package/src/types/reflection.ts +117 -0
  111. package/src/types/sdk-primitives.ts +128 -0
  112. package/src/types/snapshot.ts +14 -0
  113. package/src/types/workflow-context.ts +163 -0
  114. package/src/types/workflow.ts +37 -0
  115. package/src/utils/id.ts +11 -0
  116. package/src/utils/index.ts +3 -0
  117. package/src/utils/observable.ts +77 -0
  118. package/tasks.json +0 -0
  119. package/tsconfig.json +22 -0
  120. package/vitest.config.ts +16 -0
@@ -0,0 +1,241 @@
1
+ /**
2
+ * Example 3: Parent-Child Workflows
3
+ *
4
+ * Demonstrates:
5
+ * - Creating hierarchical workflow structures
6
+ * - Automatic parent-child attachment
7
+ * - Using @Task decorator to spawn child workflows
8
+ * - Event propagation from children to root
9
+ * - Tree visualization of nested workflows
10
+ */
11
+
12
+ import {
13
+ Workflow,
14
+ Step,
15
+ Task,
16
+ ObservedState,
17
+ WorkflowTreeDebugger,
18
+ } from 'groundswell';
19
+ import { printHeader, printSection, sleep } from '../utils/helpers.js';
20
+
21
+ /**
22
+ * Leaf workflow - performs actual work
23
+ */
24
+ class ProcessItemWorkflow extends Workflow {
25
+ @ObservedState()
26
+ itemId: string;
27
+
28
+ @ObservedState()
29
+ processed: boolean = false;
30
+
31
+ constructor(itemId: string, parent?: Workflow) {
32
+ super(`ProcessItem-${itemId}`, parent);
33
+ this.itemId = itemId;
34
+ }
35
+
36
+ @Step({ trackTiming: true, snapshotState: true })
37
+ async validate(): Promise<void> {
38
+ this.logger.info(`Validating item ${this.itemId}`);
39
+ await sleep(50);
40
+ }
41
+
42
+ @Step({ trackTiming: true, snapshotState: true })
43
+ async transform(): Promise<void> {
44
+ this.logger.info(`Transforming item ${this.itemId}`);
45
+ await sleep(100);
46
+ }
47
+
48
+ @Step({ trackTiming: true, snapshotState: true })
49
+ async save(): Promise<void> {
50
+ this.logger.info(`Saving item ${this.itemId}`);
51
+ this.processed = true;
52
+ await sleep(50);
53
+ }
54
+
55
+ async run(): Promise<void> {
56
+ this.setStatus('running');
57
+ this.logger.info(`Starting item processing for ${this.itemId}`);
58
+
59
+ await this.validate();
60
+ await this.transform();
61
+ await this.save();
62
+
63
+ this.setStatus('completed');
64
+ this.logger.info(`Completed processing ${this.itemId}`);
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Middle-tier workflow - manages a batch of items
70
+ */
71
+ class BatchProcessorWorkflow extends Workflow {
72
+ @ObservedState()
73
+ batchId: string;
74
+
75
+ @ObservedState()
76
+ itemCount: number = 0;
77
+
78
+ @ObservedState()
79
+ processedCount: number = 0;
80
+
81
+ private items: string[];
82
+
83
+ constructor(batchId: string, items: string[], parent?: Workflow) {
84
+ super(`Batch-${batchId}`, parent);
85
+ this.batchId = batchId;
86
+ this.items = items;
87
+ this.itemCount = items.length;
88
+ }
89
+
90
+ @Step({ logStart: true })
91
+ async prepareBatch(): Promise<void> {
92
+ this.logger.info(`Preparing batch ${this.batchId} with ${this.itemCount} items`);
93
+ await sleep(50);
94
+ }
95
+
96
+ @Task()
97
+ async processItem(itemId: string): Promise<ProcessItemWorkflow> {
98
+ this.logger.info(`Spawning workflow for item ${itemId}`);
99
+ return new ProcessItemWorkflow(itemId, this);
100
+ }
101
+
102
+ @Step({ logFinish: true, snapshotState: true })
103
+ async finalizeBatch(): Promise<void> {
104
+ this.processedCount = this.itemCount;
105
+ this.logger.info(`Batch ${this.batchId} finalized: ${this.processedCount} items processed`);
106
+ await sleep(30);
107
+ }
108
+
109
+ async run(): Promise<void> {
110
+ this.setStatus('running');
111
+ this.logger.info(`Starting batch ${this.batchId}`);
112
+
113
+ await this.prepareBatch();
114
+
115
+ // Process each item sequentially
116
+ for (const itemId of this.items) {
117
+ const itemWorkflow = await this.processItem(itemId);
118
+ await itemWorkflow.run();
119
+ this.processedCount++;
120
+ }
121
+
122
+ await this.finalizeBatch();
123
+
124
+ this.setStatus('completed');
125
+ }
126
+ }
127
+
128
+ /**
129
+ * Top-level orchestrator workflow
130
+ */
131
+ class DataPipelineWorkflow extends Workflow {
132
+ @ObservedState()
133
+ pipelineName: string;
134
+
135
+ @ObservedState()
136
+ totalBatches: number = 0;
137
+
138
+ @ObservedState()
139
+ completedBatches: number = 0;
140
+
141
+ private batches: { id: string; items: string[] }[];
142
+
143
+ constructor(name: string, batches: { id: string; items: string[] }[]) {
144
+ super(name);
145
+ this.pipelineName = name;
146
+ this.batches = batches;
147
+ this.totalBatches = batches.length;
148
+ }
149
+
150
+ @Step({ logStart: true, logFinish: true })
151
+ async initialize(): Promise<void> {
152
+ this.logger.info(`Initializing pipeline: ${this.pipelineName}`);
153
+ this.logger.info(`Total batches to process: ${this.totalBatches}`);
154
+ await sleep(50);
155
+ }
156
+
157
+ @Task()
158
+ async processBatch(batch: { id: string; items: string[] }): Promise<BatchProcessorWorkflow> {
159
+ this.logger.info(`Creating batch processor for ${batch.id}`);
160
+ return new BatchProcessorWorkflow(batch.id, batch.items, this);
161
+ }
162
+
163
+ @Step({ logStart: true, logFinish: true, snapshotState: true })
164
+ async cleanup(): Promise<void> {
165
+ this.logger.info('Running cleanup tasks');
166
+ await sleep(50);
167
+ }
168
+
169
+ async run(): Promise<void> {
170
+ this.setStatus('running');
171
+ this.logger.info('=== Pipeline Started ===');
172
+
173
+ await this.initialize();
174
+
175
+ // Process each batch
176
+ for (const batch of this.batches) {
177
+ const batchWorkflow = await this.processBatch(batch);
178
+ await batchWorkflow.run();
179
+ this.completedBatches++;
180
+ this.logger.info(`Completed ${this.completedBatches}/${this.totalBatches} batches`);
181
+ }
182
+
183
+ await this.cleanup();
184
+
185
+ this.setStatus('completed');
186
+ this.logger.info('=== Pipeline Completed ===');
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Run the parent-child workflow example
192
+ */
193
+ export async function runParentChildExample(): Promise<void> {
194
+ printHeader('Example 3: Parent-Child Workflows');
195
+
196
+ // Create sample data
197
+ const batches = [
198
+ { id: 'batch-A', items: ['A1', 'A2'] },
199
+ { id: 'batch-B', items: ['B1', 'B2', 'B3'] },
200
+ ];
201
+
202
+ // Create the pipeline
203
+ const pipeline = new DataPipelineWorkflow('MyDataPipeline', batches);
204
+ const debugger_ = new WorkflowTreeDebugger(pipeline);
205
+
206
+ printSection('Initial Tree Structure');
207
+ console.log(debugger_.toTreeString());
208
+
209
+ printSection('Executing Pipeline');
210
+ await pipeline.run();
211
+
212
+ printSection('Final Tree Structure');
213
+ console.log(debugger_.toTreeString());
214
+
215
+ printSection('Tree Statistics');
216
+ const stats = debugger_.getStats();
217
+ console.log(`Total nodes: ${stats.totalNodes}`);
218
+ console.log(`By status:`, stats.byStatus);
219
+ console.log(`Total logs: ${stats.totalLogs}`);
220
+ console.log(`Total events: ${stats.totalEvents}`);
221
+
222
+ printSection('Workflow Hierarchy');
223
+ console.log('Pipeline:', pipeline.id);
224
+ console.log(' Children (batches):', pipeline.children.length);
225
+ for (const batch of pipeline.children) {
226
+ console.log(` ${batch.getNode().name} - ${batch.children.length} items`);
227
+ for (const item of batch.children) {
228
+ console.log(` ${item.getNode().name} [${item.getNode().status}]`);
229
+ }
230
+ }
231
+
232
+ printSection('Sample Logs (first 15)');
233
+ const logLines = debugger_.toLogString().split('\n').slice(0, 15);
234
+ console.log(logLines.join('\n'));
235
+ console.log('...');
236
+ }
237
+
238
+ // Run if executed directly
239
+ if (import.meta.url === `file://${process.argv[1]}`) {
240
+ runParentChildExample().catch(console.error);
241
+ }
@@ -0,0 +1,340 @@
1
+ /**
2
+ * Example 4: Observers and Debugger
3
+ *
4
+ * Demonstrates:
5
+ * - Implementing custom WorkflowObserver
6
+ * - Real-time event streaming
7
+ * - Log collection and filtering
8
+ * - Using WorkflowTreeDebugger API
9
+ * - Observable subscription patterns
10
+ */
11
+
12
+ import {
13
+ Workflow,
14
+ Step,
15
+ Task,
16
+ ObservedState,
17
+ WorkflowTreeDebugger,
18
+ WorkflowObserver,
19
+ WorkflowEvent,
20
+ LogEntry,
21
+ WorkflowNode,
22
+ Observable,
23
+ } from 'groundswell';
24
+ import { printHeader, printSection, sleep } from '../utils/helpers.js';
25
+
26
+ /**
27
+ * Custom observer that collects detailed metrics
28
+ */
29
+ class MetricsObserver implements WorkflowObserver {
30
+ public logCount = 0;
31
+ public eventCount = 0;
32
+ public stateUpdates = 0;
33
+ public treeChanges = 0;
34
+
35
+ public logsByLevel: Record<string, number> = {
36
+ debug: 0,
37
+ info: 0,
38
+ warn: 0,
39
+ error: 0,
40
+ };
41
+
42
+ public eventsByType: Record<string, number> = {};
43
+ public stepDurations: { step: string; duration: number }[] = [];
44
+ public errors: WorkflowEvent[] = [];
45
+
46
+ onLog(entry: LogEntry): void {
47
+ this.logCount++;
48
+ this.logsByLevel[entry.level] = (this.logsByLevel[entry.level] || 0) + 1;
49
+ }
50
+
51
+ onEvent(event: WorkflowEvent): void {
52
+ this.eventCount++;
53
+ this.eventsByType[event.type] = (this.eventsByType[event.type] || 0) + 1;
54
+
55
+ if (event.type === 'stepEnd') {
56
+ this.stepDurations.push({
57
+ step: event.step,
58
+ duration: event.duration,
59
+ });
60
+ }
61
+
62
+ if (event.type === 'error') {
63
+ this.errors.push(event);
64
+ }
65
+ }
66
+
67
+ onStateUpdated(_node: WorkflowNode): void {
68
+ this.stateUpdates++;
69
+ }
70
+
71
+ onTreeChanged(_root: WorkflowNode): void {
72
+ this.treeChanges++;
73
+ }
74
+
75
+ getReport(): string {
76
+ const lines = [
77
+ `=== Metrics Report ===`,
78
+ `Logs: ${this.logCount} total`,
79
+ ` - debug: ${this.logsByLevel.debug}`,
80
+ ` - info: ${this.logsByLevel.info}`,
81
+ ` - warn: ${this.logsByLevel.warn}`,
82
+ ` - error: ${this.logsByLevel.error}`,
83
+ ``,
84
+ `Events: ${this.eventCount} total`,
85
+ ...Object.entries(this.eventsByType).map(([type, count]) => ` - ${type}: ${count}`),
86
+ ``,
87
+ `State updates: ${this.stateUpdates}`,
88
+ `Tree changes: ${this.treeChanges}`,
89
+ ``,
90
+ `Step durations:`,
91
+ ...this.stepDurations.map((s) => ` - ${s.step}: ${s.duration}ms`),
92
+ ];
93
+
94
+ if (this.errors.length > 0) {
95
+ lines.push(``, `Errors: ${this.errors.length}`);
96
+ }
97
+
98
+ return lines.join('\n');
99
+ }
100
+ }
101
+
102
+ /**
103
+ * Custom observer that logs in real-time
104
+ */
105
+ class ConsoleObserver implements WorkflowObserver {
106
+ private prefix: string;
107
+
108
+ constructor(prefix: string = 'OBSERVER') {
109
+ this.prefix = prefix;
110
+ }
111
+
112
+ onLog(entry: LogEntry): void {
113
+ const level = entry.level.toUpperCase().padEnd(5);
114
+ console.log(`[${this.prefix}] ${level} | ${entry.message}`);
115
+ }
116
+
117
+ onEvent(event: WorkflowEvent): void {
118
+ if (event.type === 'stepStart') {
119
+ console.log(`[${this.prefix}] >> Step started: ${event.step}`);
120
+ } else if (event.type === 'stepEnd') {
121
+ console.log(`[${this.prefix}] << Step ended: ${event.step} (${event.duration}ms)`);
122
+ } else if (event.type === 'childAttached') {
123
+ console.log(`[${this.prefix}] ++ Child attached: ${event.child.name}`);
124
+ } else if (event.type === 'error') {
125
+ console.log(`[${this.prefix}] !! ERROR: ${event.error.message}`);
126
+ }
127
+ }
128
+
129
+ onStateUpdated(node: WorkflowNode): void {
130
+ console.log(`[${this.prefix}] State updated: ${node.name}`);
131
+ }
132
+
133
+ onTreeChanged(_root: WorkflowNode): void {
134
+ console.log(`[${this.prefix}] Tree structure changed`);
135
+ }
136
+ }
137
+
138
+ /**
139
+ * Sample workflow for observation
140
+ */
141
+ class ObservableWorkflow extends Workflow {
142
+ @ObservedState()
143
+ phase: string = 'init';
144
+
145
+ @ObservedState()
146
+ progress: number = 0;
147
+
148
+ @Step({ trackTiming: true, snapshotState: true, logStart: true })
149
+ async phase1(): Promise<void> {
150
+ this.phase = 'phase1';
151
+ this.progress = 25;
152
+ await sleep(100);
153
+ }
154
+
155
+ @Step({ trackTiming: true, snapshotState: true })
156
+ async phase2(): Promise<void> {
157
+ this.phase = 'phase2';
158
+ this.progress = 50;
159
+ await sleep(150);
160
+ }
161
+
162
+ @Step({ trackTiming: true, snapshotState: true })
163
+ async phase3(): Promise<void> {
164
+ this.phase = 'phase3';
165
+ this.progress = 75;
166
+ await sleep(80);
167
+ }
168
+
169
+ @Step({ trackTiming: true, snapshotState: true, logFinish: true })
170
+ async phase4(): Promise<void> {
171
+ this.phase = 'phase4';
172
+ this.progress = 100;
173
+ await sleep(120);
174
+ }
175
+
176
+ async run(): Promise<void> {
177
+ this.setStatus('running');
178
+ this.logger.info('Observable workflow starting');
179
+
180
+ await this.phase1();
181
+ await this.phase2();
182
+ await this.phase3();
183
+ await this.phase4();
184
+
185
+ this.setStatus('completed');
186
+ this.logger.info('Observable workflow completed');
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Child workflow for tree demonstration
192
+ */
193
+ class ChildWorkflow extends Workflow {
194
+ @Step({ trackTiming: true })
195
+ async doWork(): Promise<void> {
196
+ this.logger.info('Child doing work');
197
+ await sleep(50);
198
+ }
199
+
200
+ async run(): Promise<void> {
201
+ this.setStatus('running');
202
+ await this.doWork();
203
+ this.setStatus('completed');
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Parent workflow that spawns children
209
+ */
210
+ class ParentWithChildrenWorkflow extends Workflow {
211
+ @Task()
212
+ async spawnChild(name: string): Promise<ChildWorkflow> {
213
+ return new ChildWorkflow(name, this);
214
+ }
215
+
216
+ async run(): Promise<void> {
217
+ this.setStatus('running');
218
+ this.logger.info('Parent starting');
219
+
220
+ const child1 = await this.spawnChild('Child-1');
221
+ await child1.run();
222
+
223
+ const child2 = await this.spawnChild('Child-2');
224
+ await child2.run();
225
+
226
+ this.setStatus('completed');
227
+ this.logger.info('Parent completed');
228
+ }
229
+ }
230
+
231
+ /**
232
+ * Run the observers and debugger example
233
+ */
234
+ export async function runObserversDebuggerExample(): Promise<void> {
235
+ printHeader('Example 4: Observers and Debugger');
236
+
237
+ // Part 1: Custom MetricsObserver
238
+ printSection('Part 1: MetricsObserver');
239
+ {
240
+ const workflow = new ObservableWorkflow('MetricsDemo');
241
+ const metricsObserver = new MetricsObserver();
242
+ workflow.addObserver(metricsObserver);
243
+
244
+ await workflow.run();
245
+
246
+ console.log(metricsObserver.getReport());
247
+ }
248
+
249
+ // Part 2: Real-time ConsoleObserver
250
+ printSection('Part 2: Real-time ConsoleObserver');
251
+ {
252
+ const workflow = new ObservableWorkflow('ConsoleDemo');
253
+ const consoleObserver = new ConsoleObserver('LIVE');
254
+ workflow.addObserver(consoleObserver);
255
+
256
+ await workflow.run();
257
+ }
258
+
259
+ // Part 3: Using Observable for event streaming
260
+ printSection('Part 3: Observable Event Stream');
261
+ {
262
+ const workflow = new ParentWithChildrenWorkflow('StreamDemo');
263
+ const debugger_ = new WorkflowTreeDebugger(workflow);
264
+
265
+ const eventLog: string[] = [];
266
+
267
+ // Subscribe to the event stream
268
+ const subscription = debugger_.events.subscribe({
269
+ next: (event) => {
270
+ eventLog.push(`${event.type}: ${'node' in event ? event.node.name : 'N/A'}`);
271
+ },
272
+ });
273
+
274
+ await workflow.run();
275
+
276
+ console.log('Events received via Observable:');
277
+ eventLog.forEach((e) => console.log(` ${e}`));
278
+
279
+ // Cleanup subscription
280
+ subscription.unsubscribe();
281
+ }
282
+
283
+ // Part 4: WorkflowTreeDebugger API
284
+ printSection('Part 4: WorkflowTreeDebugger API');
285
+ {
286
+ const workflow = new ParentWithChildrenWorkflow('DebuggerDemo');
287
+ const debugger_ = new WorkflowTreeDebugger(workflow);
288
+
289
+ await workflow.run();
290
+
291
+ console.log('1. Tree visualization:');
292
+ console.log(debugger_.toTreeString());
293
+
294
+ console.log('2. Get tree root:');
295
+ const root = debugger_.getTree();
296
+ console.log(` Root: ${root.name} (${root.id})`);
297
+ console.log(` Children: ${root.children.length}`);
298
+
299
+ console.log('\n3. Find node by ID:');
300
+ const firstChild = workflow.children[0];
301
+ const foundNode = debugger_.getNode(firstChild.id);
302
+ console.log(` Found: ${foundNode?.name}`);
303
+
304
+ console.log('\n4. Statistics:');
305
+ const stats = debugger_.getStats();
306
+ console.log(` ${JSON.stringify(stats, null, 2)}`);
307
+
308
+ console.log('\n5. Formatted logs:');
309
+ const logs = debugger_.toLogString().split('\n').slice(0, 5);
310
+ logs.forEach((log) => console.log(` ${log}`));
311
+ console.log(' ...');
312
+ }
313
+
314
+ // Part 5: Multiple observers
315
+ printSection('Part 5: Multiple Observers');
316
+ {
317
+ const workflow = new ObservableWorkflow('MultiObserver');
318
+
319
+ const metrics = new MetricsObserver();
320
+ const console1 = new ConsoleObserver('OBS-1');
321
+ const console2 = new ConsoleObserver('OBS-2');
322
+
323
+ workflow.addObserver(metrics);
324
+ workflow.addObserver(console1);
325
+ workflow.addObserver(console2);
326
+
327
+ // Note: both console observers will print
328
+ console.log('Running with 3 observers attached...');
329
+ await workflow.run();
330
+
331
+ console.log('\nMetrics summary:');
332
+ console.log(` Events received: ${metrics.eventCount}`);
333
+ console.log(` Logs received: ${metrics.logCount}`);
334
+ }
335
+ }
336
+
337
+ // Run if executed directly
338
+ if (import.meta.url === `file://${process.argv[1]}`) {
339
+ runObserversDebuggerExample().catch(console.error);
340
+ }