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,595 @@
1
+ /**
2
+ * Session management commands for Claude-Flow
3
+ */
4
+
5
+ import { Command } from '@cliffy/command';
6
+ import { colors } from '@cliffy/ansi/colors';
7
+ import { Table } from '@cliffy/table';
8
+ import { Confirm, Input } from '@cliffy/prompt';
9
+ import { formatDuration, formatStatusIndicator } from '../formatter.ts';
10
+ import { generateId } from '../../utils/helpers.ts';
11
+
12
+ export const sessionCommand = new Command()
13
+ .description('Manage Claude-Flow sessions')
14
+ .action(() => {
15
+ sessionCommand.showHelp();
16
+ })
17
+ .command('list', new Command()
18
+ .description('List all saved sessions')
19
+ .option('-a, --active', 'Show only active sessions')
20
+ .option('--format <format:string>', 'Output format (table, json)', { default: 'table' })
21
+ .action(async (options: any) => {
22
+ await listSessions(options);
23
+ }),
24
+ )
25
+ .command('save', new Command()
26
+ .description('Save current session state')
27
+ .arguments('[name:string]')
28
+ .option('-d, --description <desc:string>', 'Session description')
29
+ .option('-t, --tags <tags:string>', 'Comma-separated tags')
30
+ .option('--auto', 'Auto-generate session name')
31
+ .action(async (options: any, name: string | undefined) => {
32
+ await saveSession(name, options);
33
+ }),
34
+ )
35
+ .command('restore', new Command()
36
+ .description('Restore a saved session')
37
+ .arguments('<session-id:string>')
38
+ .option('-f, --force', 'Force restore without confirmation')
39
+ .option('--merge', 'Merge with current session instead of replacing')
40
+ .action(async (options: any, sessionId: string) => {
41
+ await restoreSession(sessionId, options);
42
+ }),
43
+ )
44
+ .command('delete', new Command()
45
+ .description('Delete a saved session')
46
+ .arguments('<session-id:string>')
47
+ .option('-f, --force', 'Skip confirmation prompt')
48
+ .action(async (options: any, sessionId: string) => {
49
+ await deleteSession(sessionId, options);
50
+ }),
51
+ )
52
+ .command('export', new Command()
53
+ .description('Export session to file')
54
+ .arguments('<session-id:string> <output-file:string>')
55
+ .option('--format <format:string>', 'Export format (json, yaml)', { default: 'json' })
56
+ .option('--include-memory', 'Include agent memory in export')
57
+ .action(async (options: any, sessionId: string, outputFile: string) => {
58
+ await exportSession(sessionId, outputFile, options);
59
+ }),
60
+ )
61
+ .command('import', new Command()
62
+ .description('Import session from file')
63
+ .arguments('<input-file:string>')
64
+ .option('-n, --name <name:string>', 'Custom session name')
65
+ .option('--overwrite', 'Overwrite existing session with same ID')
66
+ .action(async (options: any, inputFile: string) => {
67
+ await importSession(inputFile, options);
68
+ }),
69
+ )
70
+ .command('info', new Command()
71
+ .description('Show detailed session information')
72
+ .arguments('<session-id:string>')
73
+ .action(async (options: any, sessionId: string) => {
74
+ await showSessionInfo(sessionId);
75
+ }),
76
+ )
77
+ .command('clean', new Command()
78
+ .description('Clean up old or orphaned sessions')
79
+ .option('--older-than <days:number>', 'Delete sessions older than N days', { default: 30 })
80
+ .option('--dry-run', 'Show what would be deleted without deleting')
81
+ .option('--orphaned', 'Only clean orphaned sessions')
82
+ .action(async (options: any) => {
83
+ await cleanSessions(options);
84
+ }),
85
+ );
86
+
87
+ interface SessionData {
88
+ id: string;
89
+ name: string;
90
+ description?: string;
91
+ tags: string[];
92
+ createdAt: Date;
93
+ updatedAt: Date;
94
+ state: {
95
+ agents: any[];
96
+ tasks: any[];
97
+ memory: any[];
98
+ configuration: any;
99
+ };
100
+ metadata: {
101
+ version: string;
102
+ platform: string;
103
+ checksum: string;
104
+ };
105
+ }
106
+
107
+ const SESSION_DIR = '.claude-flow/sessions';
108
+
109
+ async function ensureSessionDir(): Promise<void> {
110
+ try {
111
+ await Deno.mkdir(SESSION_DIR, { recursive: true });
112
+ } catch (error) {
113
+ if (!(error instanceof Deno.errors.AlreadyExists)) {
114
+ throw error;
115
+ }
116
+ }
117
+ }
118
+
119
+ async function listSessions(options: any): Promise<void> {
120
+ try {
121
+ await ensureSessionDir();
122
+ const sessions = await loadAllSessions();
123
+
124
+ let filteredSessions = sessions;
125
+ if (options.active) {
126
+ // In production, this would check if the session is currently active
127
+ filteredSessions = sessions.filter(s => (s.metadata as any).active);
128
+ }
129
+
130
+ if (options.format === 'json') {
131
+ console.log(JSON.stringify(filteredSessions, null, 2));
132
+ return;
133
+ }
134
+
135
+ if (filteredSessions.length === 0) {
136
+ console.log(colors.gray('No sessions found'));
137
+ return;
138
+ }
139
+
140
+ console.log(colors.cyan.bold(`Sessions (${filteredSessions.length})`));
141
+ console.log('─'.repeat(60));
142
+
143
+ const table = new Table()
144
+ .header(['ID', 'Name', 'Description', 'Agents', 'Tasks', 'Created'])
145
+ .border(true);
146
+
147
+ for (const session of filteredSessions) {
148
+ table.push([
149
+ colors.gray(session.id.substring(0, 8) + '...'),
150
+ colors.white(session.name),
151
+ session.description ? session.description.substring(0, 30) + (session.description.length > 30 ? '...' : '') : '-',
152
+ session.state.agents.length.toString(),
153
+ session.state.tasks.length.toString(),
154
+ session.createdAt.toLocaleDateString()
155
+ ]);
156
+ }
157
+
158
+ table.render();
159
+ } catch (error) {
160
+ console.error(colors.red('Failed to list sessions:'), (error as Error).message);
161
+ }
162
+ }
163
+
164
+ async function saveSession(name: string | undefined, options: any): Promise<void> {
165
+ try {
166
+ // Get current session state (mock for now)
167
+ const currentState = await getCurrentSessionState();
168
+
169
+ if (!name) {
170
+ if (options.auto) {
171
+ name = `session-${new Date().toISOString().split('T')[0]}-${Date.now().toString().slice(-4)}`;
172
+ } else {
173
+ name = await Input.prompt({
174
+ message: 'Enter session name:',
175
+ default: `session-${new Date().toISOString().split('T')[0]}`,
176
+ });
177
+ }
178
+ }
179
+
180
+ const session: SessionData = {
181
+ id: generateId('session'),
182
+ name,
183
+ description: options.description,
184
+ tags: options.tags ? options.tags.split(',').map((t: string) => t.trim()) : [],
185
+ createdAt: new Date(),
186
+ updatedAt: new Date(),
187
+ state: currentState,
188
+ metadata: {
189
+ version: '1.0.0',
190
+ platform: Deno.build.os,
191
+ checksum: await calculateChecksum(currentState)
192
+ }
193
+ };
194
+
195
+ await ensureSessionDir();
196
+ const filePath = `${SESSION_DIR}/${session.id}.json`;
197
+ await Deno.writeTextFile(filePath, JSON.stringify(session, null, 2));
198
+
199
+ console.log(colors.green('✓ Session saved successfully'));
200
+ console.log(`${colors.white('ID:')} ${session.id}`);
201
+ console.log(`${colors.white('Name:')} ${session.name}`);
202
+ console.log(`${colors.white('File:')} ${filePath}`);
203
+
204
+ if (session.description) {
205
+ console.log(`${colors.white('Description:')} ${session.description}`);
206
+ }
207
+
208
+ console.log(`${colors.white('Agents:')} ${session.state.agents.length}`);
209
+ console.log(`${colors.white('Tasks:')} ${session.state.tasks.length}`);
210
+ } catch (error) {
211
+ console.error(colors.red('Failed to save session:'), (error as Error).message);
212
+ }
213
+ }
214
+
215
+ async function restoreSession(sessionId: string, options: any): Promise<void> {
216
+ try {
217
+ const session = await loadSession(sessionId);
218
+
219
+ if (!session) {
220
+ console.error(colors.red(`Session '${sessionId}' not found`));
221
+ return;
222
+ }
223
+
224
+ // Show session info
225
+ console.log(colors.cyan.bold('Session to restore:'));
226
+ console.log(`${colors.white('Name:')} ${session.name}`);
227
+ console.log(`${colors.white('Description:')} ${session.description || 'None'}`);
228
+ console.log(`${colors.white('Agents:')} ${session.state.agents.length}`);
229
+ console.log(`${colors.white('Tasks:')} ${session.state.tasks.length}`);
230
+ console.log(`${colors.white('Created:')} ${session.createdAt.toLocaleString()}`);
231
+
232
+ // Confirmation
233
+ if (!options.force) {
234
+ const action = options.merge ? 'merge with current session' : 'replace current session';
235
+ const confirmed = await Confirm.prompt({
236
+ message: `Are you sure you want to ${action}?`,
237
+ default: false,
238
+ });
239
+
240
+ if (!confirmed) {
241
+ console.log(colors.gray('Restore cancelled'));
242
+ return;
243
+ }
244
+ }
245
+
246
+ // Validate session integrity
247
+ const expectedChecksum = await calculateChecksum(session.state);
248
+ if (session.metadata.checksum !== expectedChecksum) {
249
+ console.log(colors.yellow('⚠ Warning: Session checksum mismatch. Data may be corrupted.'));
250
+
251
+ if (!options.force) {
252
+ const proceed = await Confirm.prompt({
253
+ message: 'Continue anyway?',
254
+ default: false,
255
+ });
256
+
257
+ if (!proceed) {
258
+ console.log(colors.gray('Restore cancelled'));
259
+ return;
260
+ }
261
+ }
262
+ }
263
+
264
+ // Restore session (mock for now)
265
+ console.log(colors.yellow('Restoring session...'));
266
+
267
+ if (options.merge) {
268
+ console.log(colors.blue('• Merging agents...'));
269
+ console.log(colors.blue('• Merging tasks...'));
270
+ console.log(colors.blue('• Merging memory...'));
271
+ } else {
272
+ console.log(colors.blue('• Stopping current agents...'));
273
+ console.log(colors.blue('• Clearing current tasks...'));
274
+ console.log(colors.blue('• Restoring agents...'));
275
+ console.log(colors.blue('• Restoring tasks...'));
276
+ console.log(colors.blue('• Restoring memory...'));
277
+ }
278
+
279
+ // Update session metadata
280
+ session.updatedAt = new Date();
281
+ const filePath = `${SESSION_DIR}/${session.id}.json`;
282
+ await Deno.writeTextFile(filePath, JSON.stringify(session, null, 2));
283
+
284
+ console.log(colors.green('✓ Session restored successfully'));
285
+ console.log(colors.yellow('Note: This is a mock implementation. In production, this would connect to the orchestrator.'));
286
+ } catch (error) {
287
+ console.error(colors.red('Failed to restore session:'), (error as Error).message);
288
+ }
289
+ }
290
+
291
+ async function deleteSession(sessionId: string, options: any): Promise<void> {
292
+ try {
293
+ const session = await loadSession(sessionId);
294
+
295
+ if (!session) {
296
+ console.error(colors.red(`Session '${sessionId}' not found`));
297
+ return;
298
+ }
299
+
300
+ // Confirmation
301
+ if (!options.force) {
302
+ console.log(`${colors.white('Session:')} ${session.name}`);
303
+ console.log(`${colors.white('Created:')} ${session.createdAt.toLocaleString()}`);
304
+
305
+ const confirmed = await Confirm.prompt({
306
+ message: 'Are you sure you want to delete this session?',
307
+ default: false,
308
+ });
309
+
310
+ if (!confirmed) {
311
+ console.log(colors.gray('Delete cancelled'));
312
+ return;
313
+ }
314
+ }
315
+
316
+ const filePath = `${SESSION_DIR}/${session.id}.json`;
317
+ await Deno.remove(filePath);
318
+
319
+ console.log(colors.green('✓ Session deleted successfully'));
320
+ } catch (error) {
321
+ console.error(colors.red('Failed to delete session:'), (error as Error).message);
322
+ }
323
+ }
324
+
325
+ async function exportSession(sessionId: string, outputFile: string, options: any): Promise<void> {
326
+ try {
327
+ const session = await loadSession(sessionId);
328
+
329
+ if (!session) {
330
+ console.error(colors.red(`Session '${sessionId}' not found`));
331
+ return;
332
+ }
333
+
334
+ let exportData = session;
335
+
336
+ if (!options.includeMemory) {
337
+ exportData = {
338
+ ...session,
339
+ state: {
340
+ ...session.state,
341
+ memory: [] // Exclude memory data
342
+ }
343
+ };
344
+ }
345
+
346
+ let content: string;
347
+ if (options.format === 'yaml') {
348
+ // In production, you'd use a YAML library
349
+ console.log(colors.yellow('YAML export not implemented yet, using JSON'));
350
+ content = JSON.stringify(exportData, null, 2);
351
+ } else {
352
+ content = JSON.stringify(exportData, null, 2);
353
+ }
354
+
355
+ await Deno.writeTextFile(outputFile, content);
356
+
357
+ console.log(colors.green('✓ Session exported successfully'));
358
+ console.log(`${colors.white('File:')} ${outputFile}`);
359
+ console.log(`${colors.white('Format:')} ${options.format}`);
360
+ console.log(`${colors.white('Size:')} ${new Blob([content]).size} bytes`);
361
+ } catch (error) {
362
+ console.error(colors.red('Failed to export session:'), (error as Error).message);
363
+ }
364
+ }
365
+
366
+ async function importSession(inputFile: string, options: any): Promise<void> {
367
+ try {
368
+ const content = await Deno.readTextFile(inputFile);
369
+ const sessionData = JSON.parse(content) as SessionData;
370
+
371
+ // Validate session data structure
372
+ if (!sessionData.id || !sessionData.name || !sessionData.state) {
373
+ throw new Error('Invalid session file format');
374
+ }
375
+
376
+ // Generate new ID if not overwriting
377
+ if (!options.overwrite) {
378
+ sessionData.id = generateId('session');
379
+ }
380
+
381
+ // Update name if specified
382
+ if (options.name) {
383
+ sessionData.name = options.name;
384
+ }
385
+
386
+ // Check if session already exists
387
+ const existingSession = await loadSession(sessionData.id);
388
+ if (existingSession && !options.overwrite) {
389
+ console.error(colors.red('Session with this ID already exists'));
390
+ console.log(colors.gray('Use --overwrite to replace it'));
391
+ return;
392
+ }
393
+
394
+ // Update timestamps
395
+ if (options.overwrite && existingSession) {
396
+ sessionData.updatedAt = new Date();
397
+ } else {
398
+ sessionData.createdAt = new Date();
399
+ sessionData.updatedAt = new Date();
400
+ }
401
+
402
+ await ensureSessionDir();
403
+ const filePath = `${SESSION_DIR}/${sessionData.id}.json`;
404
+ await Deno.writeTextFile(filePath, JSON.stringify(sessionData, null, 2));
405
+
406
+ console.log(colors.green('✓ Session imported successfully'));
407
+ console.log(`${colors.white('ID:')} ${sessionData.id}`);
408
+ console.log(`${colors.white('Name:')} ${sessionData.name}`);
409
+ console.log(`${colors.white('Action:')} ${options.overwrite ? 'Overwritten' : 'Created'}`);
410
+ } catch (error) {
411
+ console.error(colors.red('Failed to import session:'), (error as Error).message);
412
+ }
413
+ }
414
+
415
+ async function showSessionInfo(sessionId: string): Promise<void> {
416
+ try {
417
+ const session = await loadSession(sessionId);
418
+
419
+ if (!session) {
420
+ console.error(colors.red(`Session '${sessionId}' not found`));
421
+ return;
422
+ }
423
+
424
+ console.log(colors.cyan.bold('Session Information'));
425
+ console.log('─'.repeat(40));
426
+ console.log(`${colors.white('ID:')} ${session.id}`);
427
+ console.log(`${colors.white('Name:')} ${session.name}`);
428
+ console.log(`${colors.white('Description:')} ${session.description || 'None'}`);
429
+ console.log(`${colors.white('Tags:')} ${session.tags.join(', ') || 'None'}`);
430
+ console.log(`${colors.white('Created:')} ${session.createdAt.toLocaleString()}`);
431
+ console.log(`${colors.white('Updated:')} ${session.updatedAt.toLocaleString()}`);
432
+ console.log();
433
+
434
+ console.log(colors.cyan.bold('State Summary'));
435
+ console.log('─'.repeat(40));
436
+ console.log(`${colors.white('Agents:')} ${session.state.agents.length}`);
437
+ console.log(`${colors.white('Tasks:')} ${session.state.tasks.length}`);
438
+ console.log(`${colors.white('Memory Entries:')} ${session.state.memory.length}`);
439
+ console.log();
440
+
441
+ console.log(colors.cyan.bold('Metadata'));
442
+ console.log('─'.repeat(40));
443
+ console.log(`${colors.white('Version:')} ${session.metadata.version}`);
444
+ console.log(`${colors.white('Platform:')} ${session.metadata.platform}`);
445
+ console.log(`${colors.white('Checksum:')} ${session.metadata.checksum}`);
446
+
447
+ // Verify integrity
448
+ const currentChecksum = await calculateChecksum(session.state);
449
+ const integrity = currentChecksum === session.metadata.checksum;
450
+ const integrityIcon = formatStatusIndicator(integrity ? 'success' : 'error');
451
+ console.log(`${colors.white('Integrity:')} ${integrityIcon} ${integrity ? 'Valid' : 'Corrupted'}`);
452
+
453
+ // File info
454
+ const filePath = `${SESSION_DIR}/${session.id}.json`;
455
+ try {
456
+ const fileInfo = await Deno.stat(filePath);
457
+ console.log();
458
+ console.log(colors.cyan.bold('File Information'));
459
+ console.log('─'.repeat(40));
460
+ console.log(`${colors.white('Path:')} ${filePath}`);
461
+ console.log(`${colors.white('Size:')} ${fileInfo.size} bytes`);
462
+ console.log(`${colors.white('Modified:')} ${fileInfo.mtime?.toLocaleString() || 'Unknown'}`);
463
+ } catch {
464
+ console.log(colors.red('Warning: Session file not found'));
465
+ }
466
+ } catch (error) {
467
+ console.error(colors.red('Failed to show session info:'), (error as Error).message);
468
+ }
469
+ }
470
+
471
+ async function cleanSessions(options: any): Promise<void> {
472
+ try {
473
+ await ensureSessionDir();
474
+ const sessions = await loadAllSessions();
475
+
476
+ const cutoffDate = new Date();
477
+ cutoffDate.setDate(cutoffDate.getDate() - options.olderThan);
478
+
479
+ let toDelete = sessions.filter(session => session.createdAt < cutoffDate);
480
+
481
+ if (options.orphaned) {
482
+ // In production, check if sessions have valid references
483
+ toDelete = toDelete.filter(session => (session.metadata as any).orphaned);
484
+ }
485
+
486
+ if (toDelete.length === 0) {
487
+ console.log(colors.gray('No sessions to clean'));
488
+ return;
489
+ }
490
+
491
+ console.log(colors.cyan.bold(`Sessions to clean (${toDelete.length})`));
492
+ console.log('─'.repeat(50));
493
+
494
+ for (const session of toDelete) {
495
+ const age = Math.floor((Date.now() - session.createdAt.getTime()) / (1000 * 60 * 60 * 24));
496
+ console.log(`• ${session.name} (${colors.gray(session.id.substring(0, 8) + '...')}) - ${age} days old`);
497
+ }
498
+
499
+ if (options.dryRun) {
500
+ console.log('\n' + colors.yellow('Dry run mode - no files were deleted'));
501
+ return;
502
+ }
503
+
504
+ console.log();
505
+ const confirmed = await Confirm.prompt({
506
+ message: `Delete ${toDelete.length} sessions?`,
507
+ default: false,
508
+ });
509
+
510
+ if (!confirmed) {
511
+ console.log(colors.gray('Clean cancelled'));
512
+ return;
513
+ }
514
+
515
+ let deleted = 0;
516
+ for (const session of toDelete) {
517
+ try {
518
+ const filePath = `${SESSION_DIR}/${session.id}.json`;
519
+ await Deno.remove(filePath);
520
+ deleted++;
521
+ } catch (error) {
522
+ console.error(colors.red(`Failed to delete ${session.name}:`), (error as Error).message);
523
+ }
524
+ }
525
+
526
+ console.log(colors.green(`✓ Cleaned ${deleted} sessions`));
527
+ } catch (error) {
528
+ console.error(colors.red('Failed to clean sessions:'), (error as Error).message);
529
+ }
530
+ }
531
+
532
+ async function loadAllSessions(): Promise<SessionData[]> {
533
+ const sessions: SessionData[] = [];
534
+
535
+ try {
536
+ for await (const entry of Deno.readDir(SESSION_DIR)) {
537
+ if (entry.isFile && entry.name.endsWith('.json')) {
538
+ try {
539
+ const content = await Deno.readTextFile(`${SESSION_DIR}/${entry.name}`);
540
+ const session = JSON.parse(content) as SessionData;
541
+
542
+ // Convert date strings back to Date objects
543
+ session.createdAt = new Date(session.createdAt);
544
+ session.updatedAt = new Date(session.updatedAt);
545
+
546
+ sessions.push(session);
547
+ } catch (error) {
548
+ console.warn(colors.yellow(`Warning: Failed to load session file ${entry.name}:`), (error as Error).message);
549
+ }
550
+ }
551
+ }
552
+ } catch (error) {
553
+ if (!(error instanceof Deno.errors.NotFound)) {
554
+ throw error;
555
+ }
556
+ }
557
+
558
+ return sessions.sort((a, b) => b.updatedAt.getTime() - a.updatedAt.getTime());
559
+ }
560
+
561
+ async function loadSession(sessionId: string): Promise<SessionData | null> {
562
+ const sessions = await loadAllSessions();
563
+ return sessions.find(s => s.id === sessionId || s.id.startsWith(sessionId)) || null;
564
+ }
565
+
566
+ async function getCurrentSessionState(): Promise<any> {
567
+ // Mock current session state - in production, this would connect to the orchestrator
568
+ return {
569
+ agents: [
570
+ { id: 'agent-001', type: 'coordinator', status: 'active' },
571
+ { id: 'agent-002', type: 'researcher', status: 'active' }
572
+ ],
573
+ tasks: [
574
+ { id: 'task-001', type: 'research', status: 'running' },
575
+ { id: 'task-002', type: 'analysis', status: 'pending' }
576
+ ],
577
+ memory: [
578
+ { id: 'memory-001', type: 'conversation', agentId: 'agent-001' },
579
+ { id: 'memory-002', type: 'result', agentId: 'agent-002' }
580
+ ],
581
+ configuration: {
582
+ orchestrator: { maxAgents: 10 },
583
+ memory: { backend: 'hybrid' }
584
+ }
585
+ };
586
+ }
587
+
588
+ async function calculateChecksum(data: any): Promise<string> {
589
+ const content = JSON.stringify(data, null, 0);
590
+ const encoder = new TextEncoder();
591
+ const dataBuffer = encoder.encode(content);
592
+ const hashBuffer = await crypto.subtle.digest('SHA-256', dataBuffer);
593
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
594
+ return hashArray.map(b => b.toString(16).padStart(2, '0')).join('').substring(0, 16);
595
+ }