claude-flow 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.
Files changed (83) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +612 -0
  3. package/bin/claude-flow +0 -0
  4. package/bin/claude-flow-simple +0 -0
  5. package/bin/claude-flow-typecheck +0 -0
  6. package/deno.json +84 -0
  7. package/package.json +45 -0
  8. package/scripts/check-links.ts +274 -0
  9. package/scripts/check-performance-regression.ts +168 -0
  10. package/scripts/claude-sparc.sh +562 -0
  11. package/scripts/coverage-report.ts +692 -0
  12. package/scripts/demo-task-system.ts +224 -0
  13. package/scripts/install.js +72 -0
  14. package/scripts/test-batch-tasks.ts +29 -0
  15. package/scripts/test-coordination-features.ts +238 -0
  16. package/scripts/test-mcp.ts +251 -0
  17. package/scripts/test-runner.ts +571 -0
  18. package/scripts/validate-examples.ts +288 -0
  19. package/src/cli/cli-core.ts +273 -0
  20. package/src/cli/commands/agent.ts +83 -0
  21. package/src/cli/commands/config.ts +442 -0
  22. package/src/cli/commands/help.ts +765 -0
  23. package/src/cli/commands/index.ts +963 -0
  24. package/src/cli/commands/mcp.ts +191 -0
  25. package/src/cli/commands/memory.ts +74 -0
  26. package/src/cli/commands/monitor.ts +403 -0
  27. package/src/cli/commands/session.ts +595 -0
  28. package/src/cli/commands/start.ts +156 -0
  29. package/src/cli/commands/status.ts +345 -0
  30. package/src/cli/commands/task.ts +79 -0
  31. package/src/cli/commands/workflow.ts +763 -0
  32. package/src/cli/completion.ts +553 -0
  33. package/src/cli/formatter.ts +310 -0
  34. package/src/cli/index.ts +211 -0
  35. package/src/cli/main.ts +23 -0
  36. package/src/cli/repl.ts +1050 -0
  37. package/src/cli/simple-cli.js +211 -0
  38. package/src/cli/simple-cli.ts +211 -0
  39. package/src/coordination/README.md +400 -0
  40. package/src/coordination/advanced-scheduler.ts +487 -0
  41. package/src/coordination/circuit-breaker.ts +366 -0
  42. package/src/coordination/conflict-resolution.ts +490 -0
  43. package/src/coordination/dependency-graph.ts +475 -0
  44. package/src/coordination/index.ts +63 -0
  45. package/src/coordination/manager.ts +460 -0
  46. package/src/coordination/messaging.ts +290 -0
  47. package/src/coordination/metrics.ts +585 -0
  48. package/src/coordination/resources.ts +322 -0
  49. package/src/coordination/scheduler.ts +390 -0
  50. package/src/coordination/work-stealing.ts +224 -0
  51. package/src/core/config.ts +627 -0
  52. package/src/core/event-bus.ts +186 -0
  53. package/src/core/json-persistence.ts +183 -0
  54. package/src/core/logger.ts +262 -0
  55. package/src/core/orchestrator-fixed.ts +312 -0
  56. package/src/core/orchestrator.ts +1234 -0
  57. package/src/core/persistence.ts +276 -0
  58. package/src/mcp/auth.ts +438 -0
  59. package/src/mcp/claude-flow-tools.ts +1280 -0
  60. package/src/mcp/load-balancer.ts +510 -0
  61. package/src/mcp/router.ts +240 -0
  62. package/src/mcp/server.ts +548 -0
  63. package/src/mcp/session-manager.ts +418 -0
  64. package/src/mcp/tools.ts +180 -0
  65. package/src/mcp/transports/base.ts +21 -0
  66. package/src/mcp/transports/http.ts +457 -0
  67. package/src/mcp/transports/stdio.ts +254 -0
  68. package/src/memory/backends/base.ts +22 -0
  69. package/src/memory/backends/markdown.ts +283 -0
  70. package/src/memory/backends/sqlite.ts +329 -0
  71. package/src/memory/cache.ts +238 -0
  72. package/src/memory/indexer.ts +238 -0
  73. package/src/memory/manager.ts +572 -0
  74. package/src/terminal/adapters/base.ts +29 -0
  75. package/src/terminal/adapters/native.ts +504 -0
  76. package/src/terminal/adapters/vscode.ts +340 -0
  77. package/src/terminal/manager.ts +308 -0
  78. package/src/terminal/pool.ts +271 -0
  79. package/src/terminal/session.ts +250 -0
  80. package/src/terminal/vscode-bridge.ts +242 -0
  81. package/src/utils/errors.ts +231 -0
  82. package/src/utils/helpers.ts +476 -0
  83. package/src/utils/types.ts +493 -0
@@ -0,0 +1,572 @@
1
+ /**
2
+ * Memory manager interface and implementation
3
+ */
4
+
5
+ import { MemoryEntry, MemoryQuery, MemoryConfig } from '../utils/types.ts';
6
+ import { IEventBus } from '../core/event-bus.ts';
7
+ import { ILogger } from '../core/logger.ts';
8
+ import { MemoryError } from '../utils/errors.ts';
9
+ import { IMemoryBackend } from './backends/base.ts';
10
+ import { SQLiteBackend } from './backends/sqlite.ts';
11
+ import { MarkdownBackend } from './backends/markdown.ts';
12
+ import { MemoryCache } from './cache.ts';
13
+ import { MemoryIndexer } from './indexer.ts';
14
+
15
+ export interface IMemoryManager {
16
+ initialize(): Promise<void>;
17
+ shutdown(): Promise<void>;
18
+ createBank(agentId: string): Promise<string>;
19
+ closeBank(bankId: string): Promise<void>;
20
+ store(entry: MemoryEntry): Promise<void>;
21
+ retrieve(id: string): Promise<MemoryEntry | undefined>;
22
+ query(query: MemoryQuery): Promise<MemoryEntry[]>;
23
+ update(id: string, updates: Partial<MemoryEntry>): Promise<void>;
24
+ delete(id: string): Promise<void>;
25
+ getHealthStatus(): Promise<{ healthy: boolean; error?: string; metrics?: Record<string, number> }>;
26
+ performMaintenance(): Promise<void>;
27
+ }
28
+
29
+ /**
30
+ * Memory bank for agent-specific storage
31
+ */
32
+ interface MemoryBank {
33
+ id: string;
34
+ agentId: string;
35
+ createdAt: Date;
36
+ lastAccessed: Date;
37
+ entryCount: number;
38
+ }
39
+
40
+ /**
41
+ * Memory manager implementation
42
+ */
43
+ export class MemoryManager implements IMemoryManager {
44
+ private backend: IMemoryBackend;
45
+ private cache: MemoryCache;
46
+ private indexer: MemoryIndexer;
47
+ private banks = new Map<string, MemoryBank>();
48
+ private initialized = false;
49
+ private syncInterval?: number;
50
+
51
+ constructor(
52
+ private config: MemoryConfig,
53
+ private eventBus: IEventBus,
54
+ private logger: ILogger,
55
+ ) {
56
+ // Initialize backend based on configuration
57
+ this.backend = this.createBackend();
58
+
59
+ // Initialize cache
60
+ this.cache = new MemoryCache(
61
+ this.config.cacheSizeMB * 1024 * 1024, // Convert MB to bytes
62
+ this.logger,
63
+ );
64
+
65
+ // Initialize indexer
66
+ this.indexer = new MemoryIndexer(this.logger);
67
+ }
68
+
69
+ async initialize(): Promise<void> {
70
+ if (this.initialized) {
71
+ return;
72
+ }
73
+
74
+ this.logger.info('Initializing memory manager...');
75
+
76
+ try {
77
+ // Initialize backend
78
+ await this.backend.initialize();
79
+
80
+ // Initialize indexer with existing entries
81
+ const allEntries = await this.backend.getAllEntries();
82
+ await this.indexer.buildIndex(allEntries);
83
+
84
+ // Start sync interval
85
+ this.startSyncInterval();
86
+
87
+ this.initialized = true;
88
+ this.logger.info('Memory manager initialized');
89
+ } catch (error) {
90
+ this.logger.error('Failed to initialize memory manager', error);
91
+ throw new MemoryError('Memory manager initialization failed', { error });
92
+ }
93
+ }
94
+
95
+ async shutdown(): Promise<void> {
96
+ if (!this.initialized) {
97
+ return;
98
+ }
99
+
100
+ this.logger.info('Shutting down memory manager...');
101
+
102
+ try {
103
+ // Stop sync interval
104
+ if (this.syncInterval) {
105
+ clearInterval(this.syncInterval);
106
+ }
107
+
108
+ // Flush cache
109
+ await this.flushCache();
110
+
111
+ // Close all banks
112
+ const bankIds = Array.from(this.banks.keys());
113
+ await Promise.all(bankIds.map(id => this.closeBank(id)));
114
+
115
+ // Shutdown backend
116
+ await this.backend.shutdown();
117
+
118
+ this.initialized = false;
119
+ this.logger.info('Memory manager shutdown complete');
120
+ } catch (error) {
121
+ this.logger.error('Error during memory manager shutdown', error);
122
+ throw error;
123
+ }
124
+ }
125
+
126
+ async createBank(agentId: string): Promise<string> {
127
+ if (!this.initialized) {
128
+ throw new MemoryError('Memory manager not initialized');
129
+ }
130
+
131
+ const bank: MemoryBank = {
132
+ id: `bank_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
133
+ agentId,
134
+ createdAt: new Date(),
135
+ lastAccessed: new Date(),
136
+ entryCount: 0,
137
+ };
138
+
139
+ this.banks.set(bank.id, bank);
140
+
141
+ this.logger.info('Memory bank created', { bankId: bank.id, agentId });
142
+
143
+ return bank.id;
144
+ }
145
+
146
+ async closeBank(bankId: string): Promise<void> {
147
+ const bank = this.banks.get(bankId);
148
+ if (!bank) {
149
+ throw new MemoryError(`Memory bank not found: ${bankId}`);
150
+ }
151
+
152
+ // Flush any cached entries for this bank
153
+ const bankEntries = this.cache.getByPrefix(`${bank.agentId}:`);
154
+ for (const entry of bankEntries) {
155
+ await this.backend.store(entry);
156
+ }
157
+
158
+ this.banks.delete(bankId);
159
+
160
+ this.logger.info('Memory bank closed', { bankId });
161
+ }
162
+
163
+ async store(entry: MemoryEntry): Promise<void> {
164
+ if (!this.initialized) {
165
+ throw new MemoryError('Memory manager not initialized');
166
+ }
167
+
168
+ this.logger.debug('Storing memory entry', {
169
+ id: entry.id,
170
+ type: entry.type,
171
+ agentId: entry.agentId,
172
+ });
173
+
174
+ try {
175
+ // Add to cache
176
+ this.cache.set(entry.id, entry);
177
+
178
+ // Add to index
179
+ this.indexer.addEntry(entry);
180
+
181
+ // Store in backend (async, don't wait)
182
+ this.backend.store(entry).catch(error => {
183
+ this.logger.error('Failed to store entry in backend', {
184
+ id: entry.id,
185
+ error,
186
+ });
187
+ });
188
+
189
+ // Update bank stats
190
+ const bank = Array.from(this.banks.values()).find(b => b.agentId === entry.agentId);
191
+ if (bank) {
192
+ bank.entryCount++;
193
+ bank.lastAccessed = new Date();
194
+ }
195
+
196
+ // Emit event
197
+ this.eventBus.emit('memory:created', { entry });
198
+ } catch (error) {
199
+ this.logger.error('Failed to store memory entry', error);
200
+ throw new MemoryError('Failed to store memory entry', { error });
201
+ }
202
+ }
203
+
204
+ async retrieve(id: string): Promise<MemoryEntry | undefined> {
205
+ if (!this.initialized) {
206
+ throw new MemoryError('Memory manager not initialized');
207
+ }
208
+
209
+ // Check cache first
210
+ const cached = this.cache.get(id);
211
+ if (cached) {
212
+ return cached;
213
+ }
214
+
215
+ // Retrieve from backend
216
+ const entry = await this.backend.retrieve(id);
217
+ if (entry) {
218
+ // Add to cache
219
+ this.cache.set(id, entry);
220
+ }
221
+
222
+ return entry;
223
+ }
224
+
225
+ async query(query: MemoryQuery): Promise<MemoryEntry[]> {
226
+ if (!this.initialized) {
227
+ throw new MemoryError('Memory manager not initialized');
228
+ }
229
+
230
+ this.logger.debug('Querying memory', query);
231
+
232
+ try {
233
+ // Use index for fast querying
234
+ let results = this.indexer.search(query);
235
+
236
+ // Apply additional filters if needed
237
+ if (query.search) {
238
+ results = results.filter(entry =>
239
+ entry.content.toLowerCase().includes(query.search!.toLowerCase()) ||
240
+ entry.tags.some(tag => tag.toLowerCase().includes(query.search!.toLowerCase())),
241
+ );
242
+ }
243
+
244
+ // Apply time range filter
245
+ if (query.startTime || query.endTime) {
246
+ results = results.filter(entry => {
247
+ const timestamp = entry.timestamp.getTime();
248
+ if (query.startTime && timestamp < query.startTime.getTime()) {
249
+ return false;
250
+ }
251
+ if (query.endTime && timestamp > query.endTime.getTime()) {
252
+ return false;
253
+ }
254
+ return true;
255
+ });
256
+ }
257
+
258
+ // Apply pagination
259
+ const start = query.offset || 0;
260
+ const limit = query.limit || 100;
261
+ results = results.slice(start, start + limit);
262
+
263
+ return results;
264
+ } catch (error) {
265
+ this.logger.error('Failed to query memory', error);
266
+ throw new MemoryError('Failed to query memory', { error });
267
+ }
268
+ }
269
+
270
+ async update(id: string, updates: Partial<MemoryEntry>): Promise<void> {
271
+ if (!this.initialized) {
272
+ throw new MemoryError('Memory manager not initialized');
273
+ }
274
+
275
+ const existing = await this.retrieve(id);
276
+ if (!existing) {
277
+ throw new MemoryError(`Memory entry not found: ${id}`);
278
+ }
279
+
280
+ // Create updated entry
281
+ const updated: MemoryEntry = {
282
+ ...existing,
283
+ ...updates,
284
+ id: existing.id, // Ensure ID doesn't change
285
+ version: existing.version + 1,
286
+ timestamp: new Date(),
287
+ };
288
+
289
+ // Update in cache
290
+ this.cache.set(id, updated);
291
+
292
+ // Update in index
293
+ this.indexer.updateEntry(updated);
294
+
295
+ // Update in backend
296
+ await this.backend.update(id, updated);
297
+
298
+ // Emit event
299
+ this.eventBus.emit('memory:updated', {
300
+ entry: updated,
301
+ previousVersion: existing.version,
302
+ });
303
+ }
304
+
305
+ async delete(id: string): Promise<void> {
306
+ if (!this.initialized) {
307
+ throw new MemoryError('Memory manager not initialized');
308
+ }
309
+
310
+ // Remove from cache
311
+ this.cache.delete(id);
312
+
313
+ // Remove from index
314
+ this.indexer.removeEntry(id);
315
+
316
+ // Delete from backend
317
+ await this.backend.delete(id);
318
+
319
+ // Emit event
320
+ this.eventBus.emit('memory:deleted', { entryId: id });
321
+ }
322
+
323
+ async getHealthStatus(): Promise<{
324
+ healthy: boolean;
325
+ error?: string;
326
+ metrics?: Record<string, number>;
327
+ }> {
328
+ try {
329
+ const backendHealth = await this.backend.getHealthStatus();
330
+ const cacheMetrics = this.cache.getMetrics();
331
+ const indexMetrics = this.indexer.getMetrics();
332
+
333
+ const metrics = {
334
+ totalEntries: indexMetrics.totalEntries,
335
+ cacheSize: cacheMetrics.size,
336
+ cacheHitRate: cacheMetrics.hitRate,
337
+ activeBanks: this.banks.size,
338
+ ...backendHealth.metrics,
339
+ };
340
+
341
+ return {
342
+ healthy: backendHealth.healthy,
343
+ metrics,
344
+ ...(backendHealth.error && { error: backendHealth.error }),
345
+ };
346
+ } catch (error) {
347
+ return {
348
+ healthy: false,
349
+ error: error instanceof Error ? error.message : 'Unknown error',
350
+ };
351
+ }
352
+ }
353
+
354
+ async performMaintenance(): Promise<void> {
355
+ if (!this.initialized) {
356
+ return;
357
+ }
358
+
359
+ this.logger.debug('Performing memory manager maintenance');
360
+
361
+ try {
362
+ // Clean up old entries based on retention policy
363
+ if (this.config.retentionDays > 0) {
364
+ const cutoffDate = new Date();
365
+ cutoffDate.setDate(cutoffDate.getDate() - this.config.retentionDays);
366
+
367
+ const oldEntries = await this.query({
368
+ endTime: cutoffDate,
369
+ });
370
+
371
+ for (const entry of oldEntries) {
372
+ await this.delete(entry.id);
373
+ }
374
+
375
+ this.logger.info(`Cleaned up ${oldEntries.length} old memory entries`);
376
+ }
377
+
378
+ // Perform cache maintenance
379
+ this.cache.performMaintenance();
380
+
381
+ // Perform backend maintenance
382
+ if (this.backend.performMaintenance) {
383
+ await this.backend.performMaintenance();
384
+ }
385
+
386
+ // Update bank statistics
387
+ for (const bank of this.banks.values()) {
388
+ const entries = await this.query({ agentId: bank.agentId });
389
+ bank.entryCount = entries.length;
390
+ bank.lastAccessed = new Date();
391
+ }
392
+
393
+ this.logger.debug('Memory manager maintenance completed');
394
+ } catch (error) {
395
+ this.logger.error('Error during memory manager maintenance', error);
396
+ }
397
+ }
398
+
399
+ private createBackend(): IMemoryBackend {
400
+ switch (this.config.backend) {
401
+ case 'sqlite':
402
+ return new SQLiteBackend(
403
+ this.config.sqlitePath || './claude-flow.db',
404
+ this.logger,
405
+ );
406
+ case 'markdown':
407
+ return new MarkdownBackend(
408
+ this.config.markdownDir || './memory',
409
+ this.logger,
410
+ );
411
+ case 'hybrid':
412
+ // Use SQLite for structured data and Markdown for human-readable backup
413
+ return new HybridBackend(
414
+ new SQLiteBackend(
415
+ this.config.sqlitePath || './claude-flow.db',
416
+ this.logger,
417
+ ),
418
+ new MarkdownBackend(
419
+ this.config.markdownDir || './memory',
420
+ this.logger,
421
+ ),
422
+ this.logger,
423
+ );
424
+ default:
425
+ throw new MemoryError(`Unknown memory backend: ${this.config.backend}`);
426
+ }
427
+ }
428
+
429
+ private startSyncInterval(): void {
430
+ this.syncInterval = setInterval(async () => {
431
+ try {
432
+ await this.syncCache();
433
+ } catch (error) {
434
+ this.logger.error('Cache sync error', error);
435
+ }
436
+ }, this.config.syncInterval);
437
+ }
438
+
439
+ private async syncCache(): Promise<void> {
440
+ const dirtyEntries = this.cache.getDirtyEntries();
441
+
442
+ if (dirtyEntries.length === 0) {
443
+ return;
444
+ }
445
+
446
+ this.logger.debug('Syncing cache to backend', { count: dirtyEntries.length });
447
+
448
+ const promises = dirtyEntries.map(entry =>
449
+ this.backend.store(entry).catch(error => {
450
+ this.logger.error('Failed to sync entry', { id: entry.id, error });
451
+ }),
452
+ );
453
+
454
+ await Promise.all(promises);
455
+ this.cache.markClean(dirtyEntries.map(e => e.id));
456
+
457
+ // Emit sync event
458
+ this.eventBus.emit('memory:synced', { entries: dirtyEntries });
459
+ }
460
+
461
+ private async flushCache(): Promise<void> {
462
+ const allEntries = this.cache.getAllEntries();
463
+
464
+ if (allEntries.length === 0) {
465
+ return;
466
+ }
467
+
468
+ this.logger.info('Flushing cache to backend', { count: allEntries.length });
469
+
470
+ const promises = allEntries.map(entry =>
471
+ this.backend.store(entry).catch(error => {
472
+ this.logger.error('Failed to flush entry', { id: entry.id, error });
473
+ }),
474
+ );
475
+
476
+ await Promise.all(promises);
477
+ }
478
+ }
479
+
480
+ /**
481
+ * Hybrid backend that uses both SQLite and Markdown
482
+ */
483
+ class HybridBackend implements IMemoryBackend {
484
+ constructor(
485
+ private primary: IMemoryBackend,
486
+ private secondary: IMemoryBackend,
487
+ private logger: ILogger,
488
+ ) {}
489
+
490
+ async initialize(): Promise<void> {
491
+ await Promise.all([
492
+ this.primary.initialize(),
493
+ this.secondary.initialize(),
494
+ ]);
495
+ }
496
+
497
+ async shutdown(): Promise<void> {
498
+ await Promise.all([
499
+ this.primary.shutdown(),
500
+ this.secondary.shutdown(),
501
+ ]);
502
+ }
503
+
504
+ async store(entry: MemoryEntry): Promise<void> {
505
+ // Store in both backends
506
+ await Promise.all([
507
+ this.primary.store(entry),
508
+ this.secondary.store(entry).catch(error => {
509
+ this.logger.warn('Failed to store in secondary backend', { error });
510
+ }),
511
+ ]);
512
+ }
513
+
514
+ async retrieve(id: string): Promise<MemoryEntry | undefined> {
515
+ // Try primary first
516
+ const entry = await this.primary.retrieve(id);
517
+ if (entry) {
518
+ return entry;
519
+ }
520
+
521
+ // Fall back to secondary
522
+ return await this.secondary.retrieve(id);
523
+ }
524
+
525
+ async update(id: string, entry: MemoryEntry): Promise<void> {
526
+ await Promise.all([
527
+ this.primary.update(id, entry),
528
+ this.secondary.update(id, entry).catch(error => {
529
+ this.logger.warn('Failed to update in secondary backend', { error });
530
+ }),
531
+ ]);
532
+ }
533
+
534
+ async delete(id: string): Promise<void> {
535
+ await Promise.all([
536
+ this.primary.delete(id),
537
+ this.secondary.delete(id).catch(error => {
538
+ this.logger.warn('Failed to delete from secondary backend', { error });
539
+ }),
540
+ ]);
541
+ }
542
+
543
+ async query(query: MemoryQuery): Promise<MemoryEntry[]> {
544
+ // Use primary for querying (faster)
545
+ return await this.primary.query(query);
546
+ }
547
+
548
+ async getAllEntries(): Promise<MemoryEntry[]> {
549
+ return await this.primary.getAllEntries();
550
+ }
551
+
552
+ async getHealthStatus(): Promise<{
553
+ healthy: boolean;
554
+ error?: string;
555
+ metrics?: Record<string, number>;
556
+ }> {
557
+ const [primaryHealth, secondaryHealth] = await Promise.all([
558
+ this.primary.getHealthStatus(),
559
+ this.secondary.getHealthStatus(),
560
+ ]);
561
+
562
+ const error = primaryHealth.error || secondaryHealth.error;
563
+ return {
564
+ healthy: primaryHealth.healthy && secondaryHealth.healthy,
565
+ ...(error && { error }),
566
+ metrics: {
567
+ ...primaryHealth.metrics,
568
+ ...secondaryHealth.metrics,
569
+ },
570
+ };
571
+ }
572
+ }
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Base terminal adapter interface
3
+ */
4
+
5
+ export interface Terminal {
6
+ id: string;
7
+ pid?: number;
8
+ executeCommand(command: string): Promise<string>;
9
+ write(data: string): Promise<void>;
10
+ read(): Promise<string>;
11
+ isAlive(): boolean;
12
+ kill(): Promise<void>;
13
+ addOutputListener?(listener: (data: string) => void): void;
14
+ removeOutputListener?(listener: (data: string) => void): void;
15
+ }
16
+
17
+ export interface ITerminalAdapter {
18
+ initialize(): Promise<void>;
19
+ shutdown(): Promise<void>;
20
+ createTerminal(): Promise<Terminal>;
21
+ destroyTerminal(terminal: Terminal): Promise<void>;
22
+ }
23
+
24
+ export interface TerminalEvents {
25
+ 'terminal:created': { terminalId: string; pid?: number };
26
+ 'terminal:closed': { terminalId: string; code?: number; signal?: string };
27
+ 'terminal:error': { terminalId: string; error: Error };
28
+ 'terminal:output': { terminalId: string; data: string };
29
+ }