@claude-flow/cli 3.0.0-alpha.13 → 3.0.0-alpha.15

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 (106) hide show
  1. package/dist/src/commands/doctor.d.ts.map +1 -1
  2. package/dist/src/commands/doctor.js +75 -2
  3. package/dist/src/commands/doctor.js.map +1 -1
  4. package/dist/tsconfig.tsbuildinfo +1 -1
  5. package/package.json +12 -4
  6. package/.agentic-flow/intelligence.json +0 -17
  7. package/.claude-flow/agents/store.json +0 -16
  8. package/.claude-flow/daemon-state.json +0 -123
  9. package/.claude-flow/daemon-test.log +0 -0
  10. package/.claude-flow/daemon.log +0 -0
  11. package/.claude-flow/daemon2.log +0 -0
  12. package/.claude-flow/daemon3.log +0 -0
  13. package/.claude-flow/hive-mind/state.json +0 -51
  14. package/.claude-flow/metrics/agent-metrics.json +0 -1
  15. package/.claude-flow/metrics/codebase-map.json +0 -11
  16. package/.claude-flow/metrics/consolidation.json +0 -6
  17. package/.claude-flow/metrics/performance.json +0 -87
  18. package/.claude-flow/metrics/security-audit.json +0 -10
  19. package/.claude-flow/metrics/task-metrics.json +0 -10
  20. package/.claude-flow/metrics/test-gaps.json +0 -6
  21. package/__tests__/README.md +0 -140
  22. package/__tests__/TEST_SUMMARY.md +0 -144
  23. package/__tests__/cli.test.ts +0 -558
  24. package/__tests__/commands.test.ts +0 -726
  25. package/__tests__/config-adapter.test.ts +0 -362
  26. package/__tests__/config-loading.test.ts +0 -106
  27. package/__tests__/coverage/.tmp/coverage-0.json +0 -1
  28. package/__tests__/coverage/.tmp/coverage-1.json +0 -1
  29. package/__tests__/coverage/.tmp/coverage-2.json +0 -1
  30. package/__tests__/coverage/.tmp/coverage-3.json +0 -1
  31. package/__tests__/coverage/.tmp/coverage-4.json +0 -1
  32. package/__tests__/coverage/.tmp/coverage-5.json +0 -1
  33. package/__tests__/mcp-client.test.ts +0 -480
  34. package/__tests__/p1-commands.test.ts +0 -1064
  35. package/agents/architect.yaml +0 -11
  36. package/agents/coder.yaml +0 -11
  37. package/agents/reviewer.yaml +0 -10
  38. package/agents/security-architect.yaml +0 -10
  39. package/agents/tester.yaml +0 -10
  40. package/docs/CONFIG_LOADING.md +0 -236
  41. package/docs/IMPLEMENTATION_COMPLETE.md +0 -421
  42. package/docs/MCP_CLIENT_GUIDE.md +0 -620
  43. package/docs/REFACTORING_SUMMARY.md +0 -247
  44. package/scripts/publish.sh +0 -46
  45. package/src/commands/agent.ts +0 -955
  46. package/src/commands/claims.ts +0 -317
  47. package/src/commands/completions.ts +0 -558
  48. package/src/commands/config.ts +0 -452
  49. package/src/commands/daemon.ts +0 -621
  50. package/src/commands/deployment.ts +0 -323
  51. package/src/commands/doctor.ts +0 -382
  52. package/src/commands/embeddings.ts +0 -686
  53. package/src/commands/hive-mind.ts +0 -928
  54. package/src/commands/hooks.ts +0 -2603
  55. package/src/commands/index.ts +0 -154
  56. package/src/commands/init.ts +0 -597
  57. package/src/commands/mcp.ts +0 -753
  58. package/src/commands/memory.ts +0 -1161
  59. package/src/commands/migrate.ts +0 -447
  60. package/src/commands/neural.ts +0 -253
  61. package/src/commands/performance.ts +0 -292
  62. package/src/commands/plugins.ts +0 -316
  63. package/src/commands/process.ts +0 -695
  64. package/src/commands/providers.ts +0 -259
  65. package/src/commands/security.ts +0 -288
  66. package/src/commands/session.ts +0 -891
  67. package/src/commands/start.ts +0 -457
  68. package/src/commands/status.ts +0 -736
  69. package/src/commands/swarm.ts +0 -648
  70. package/src/commands/task.ts +0 -792
  71. package/src/commands/workflow.ts +0 -742
  72. package/src/config-adapter.ts +0 -210
  73. package/src/index.ts +0 -443
  74. package/src/infrastructure/in-memory-repositories.ts +0 -310
  75. package/src/init/claudemd-generator.ts +0 -631
  76. package/src/init/executor.ts +0 -762
  77. package/src/init/helpers-generator.ts +0 -628
  78. package/src/init/index.ts +0 -60
  79. package/src/init/mcp-generator.ts +0 -83
  80. package/src/init/settings-generator.ts +0 -284
  81. package/src/init/statusline-generator.ts +0 -211
  82. package/src/init/types.ts +0 -447
  83. package/src/mcp-client.ts +0 -241
  84. package/src/mcp-server.ts +0 -577
  85. package/src/mcp-tools/agent-tools.ts +0 -466
  86. package/src/mcp-tools/config-tools.ts +0 -370
  87. package/src/mcp-tools/hive-mind-tools.ts +0 -521
  88. package/src/mcp-tools/hooks-tools.ts +0 -1888
  89. package/src/mcp-tools/index.ts +0 -16
  90. package/src/mcp-tools/memory-tools.ts +0 -270
  91. package/src/mcp-tools/session-tools.ts +0 -359
  92. package/src/mcp-tools/swarm-tools.ts +0 -105
  93. package/src/mcp-tools/task-tools.ts +0 -347
  94. package/src/mcp-tools/types.ts +0 -33
  95. package/src/mcp-tools/workflow-tools.ts +0 -573
  96. package/src/output.ts +0 -639
  97. package/src/parser.ts +0 -417
  98. package/src/prompt.ts +0 -619
  99. package/src/services/index.ts +0 -15
  100. package/src/services/worker-daemon.ts +0 -726
  101. package/src/suggest.ts +0 -245
  102. package/src/types.ts +0 -287
  103. package/tmp.json +0 -0
  104. package/tsconfig.json +0 -16
  105. package/tsconfig.tsbuildinfo +0 -1
  106. package/vitest.config.ts +0 -13
@@ -1,891 +0,0 @@
1
- /**
2
- * V3 CLI Session Command
3
- * Session management for Claude Flow
4
- */
5
-
6
- import type { Command, CommandContext, CommandResult } from '../types.js';
7
- import { output } from '../output.js';
8
- import { confirm, input, select } from '../prompt.js';
9
- import { callMCPTool, MCPClientError } from '../mcp-client.js';
10
- import * as fs from 'fs';
11
- import * as path from 'path';
12
-
13
- // Format date for display
14
- function formatDate(dateStr: string): string {
15
- const date = new Date(dateStr);
16
- const now = new Date();
17
- const diff = now.getTime() - date.getTime();
18
-
19
- // Less than 24 hours - show relative time
20
- if (diff < 24 * 60 * 60 * 1000) {
21
- const hours = Math.floor(diff / (60 * 60 * 1000));
22
- const minutes = Math.floor((diff % (60 * 60 * 1000)) / (60 * 1000));
23
-
24
- if (hours > 0) {
25
- return `${hours}h ${minutes}m ago`;
26
- }
27
- return `${minutes}m ago`;
28
- }
29
-
30
- // Otherwise show date
31
- return date.toLocaleDateString() + ' ' + date.toLocaleTimeString();
32
- }
33
-
34
- // Format session status
35
- function formatStatus(status: string): string {
36
- switch (status) {
37
- case 'active':
38
- return output.success(status);
39
- case 'saved':
40
- return output.info(status);
41
- case 'archived':
42
- return output.dim(status);
43
- default:
44
- return status;
45
- }
46
- }
47
-
48
- // List subcommand
49
- const listCommand: Command = {
50
- name: 'list',
51
- aliases: ['ls'],
52
- description: 'List all sessions',
53
- options: [
54
- {
55
- name: 'active',
56
- short: 'a',
57
- description: 'Show only active sessions',
58
- type: 'boolean',
59
- default: false
60
- },
61
- {
62
- name: 'all',
63
- description: 'Include archived sessions',
64
- type: 'boolean',
65
- default: false
66
- },
67
- {
68
- name: 'limit',
69
- short: 'l',
70
- description: 'Maximum sessions to show',
71
- type: 'number',
72
- default: 20
73
- }
74
- ],
75
- action: async (ctx: CommandContext): Promise<CommandResult> => {
76
- const activeOnly = ctx.flags.active as boolean;
77
- const includeArchived = ctx.flags.all as boolean;
78
- const limit = ctx.flags.limit as number;
79
-
80
- try {
81
- const result = await callMCPTool<{
82
- sessions: Array<{
83
- id: string;
84
- name?: string;
85
- description?: string;
86
- status: 'active' | 'saved' | 'archived';
87
- createdAt: string;
88
- updatedAt: string;
89
- agentCount: number;
90
- taskCount: number;
91
- memorySize: number;
92
- }>;
93
- total: number;
94
- }>('session/list', {
95
- status: activeOnly ? 'active' : includeArchived ? 'all' : 'active,saved',
96
- limit
97
- });
98
-
99
- if (ctx.flags.format === 'json') {
100
- output.printJson(result);
101
- return { success: true, data: result };
102
- }
103
-
104
- output.writeln();
105
- output.writeln(output.bold('Sessions'));
106
- output.writeln();
107
-
108
- if (result.sessions.length === 0) {
109
- output.printInfo('No sessions found');
110
- output.printInfo('Run "claude-flow session save" to create a session');
111
- return { success: true, data: result };
112
- }
113
-
114
- output.printTable({
115
- columns: [
116
- { key: 'id', header: 'ID', width: 20 },
117
- { key: 'name', header: 'Name', width: 20 },
118
- { key: 'status', header: 'Status', width: 10 },
119
- { key: 'agents', header: 'Agents', width: 8, align: 'right' },
120
- { key: 'tasks', header: 'Tasks', width: 8, align: 'right' },
121
- { key: 'updated', header: 'Last Updated', width: 18 }
122
- ],
123
- data: result.sessions.map(s => ({
124
- id: s.id,
125
- name: s.name || '-',
126
- status: formatStatus(s.status),
127
- agents: s.agentCount,
128
- tasks: s.taskCount,
129
- updated: formatDate(s.updatedAt)
130
- }))
131
- });
132
-
133
- output.writeln();
134
- output.printInfo(`Showing ${result.sessions.length} of ${result.total} sessions`);
135
-
136
- return { success: true, data: result };
137
- } catch (error) {
138
- if (error instanceof MCPClientError) {
139
- output.printError(`Failed to list sessions: ${error.message}`);
140
- } else {
141
- output.printError(`Unexpected error: ${String(error)}`);
142
- }
143
- return { success: false, exitCode: 1 };
144
- }
145
- }
146
- };
147
-
148
- // Save subcommand
149
- const saveCommand: Command = {
150
- name: 'save',
151
- aliases: ['create', 'checkpoint'],
152
- description: 'Save current session state',
153
- options: [
154
- {
155
- name: 'name',
156
- short: 'n',
157
- description: 'Session name',
158
- type: 'string'
159
- },
160
- {
161
- name: 'description',
162
- short: 'd',
163
- description: 'Session description',
164
- type: 'string'
165
- },
166
- {
167
- name: 'include-memory',
168
- description: 'Include memory state in session',
169
- type: 'boolean',
170
- default: true
171
- },
172
- {
173
- name: 'include-agents',
174
- description: 'Include agent state in session',
175
- type: 'boolean',
176
- default: true
177
- },
178
- {
179
- name: 'include-tasks',
180
- description: 'Include task state in session',
181
- type: 'boolean',
182
- default: true
183
- }
184
- ],
185
- action: async (ctx: CommandContext): Promise<CommandResult> => {
186
- let sessionName = ctx.flags.name as string;
187
- let description = ctx.flags.description as string;
188
-
189
- // Interactive mode
190
- if (!sessionName && ctx.interactive) {
191
- sessionName = await input({
192
- message: 'Session name:',
193
- default: `session-${Date.now().toString(36)}`,
194
- validate: (v) => v.length > 0 || 'Name is required'
195
- });
196
- }
197
-
198
- if (!description && ctx.interactive) {
199
- description = await input({
200
- message: 'Session description (optional):',
201
- default: ''
202
- });
203
- }
204
-
205
- const spinner = output.createSpinner({ text: 'Saving session...' });
206
- spinner.start();
207
-
208
- try {
209
- const result = await callMCPTool<{
210
- sessionId: string;
211
- name: string;
212
- description?: string;
213
- savedAt: string;
214
- includes: {
215
- memory: boolean;
216
- agents: boolean;
217
- tasks: boolean;
218
- };
219
- stats: {
220
- agentCount: number;
221
- taskCount: number;
222
- memoryEntries: number;
223
- totalSize: number;
224
- };
225
- }>('session/save', {
226
- name: sessionName,
227
- description,
228
- includeMemory: ctx.flags['include-memory'] !== false,
229
- includeAgents: ctx.flags['include-agents'] !== false,
230
- includeTasks: ctx.flags['include-tasks'] !== false
231
- });
232
-
233
- spinner.succeed('Session saved');
234
- output.writeln();
235
-
236
- output.printTable({
237
- columns: [
238
- { key: 'property', header: 'Property', width: 18 },
239
- { key: 'value', header: 'Value', width: 35 }
240
- ],
241
- data: [
242
- { property: 'Session ID', value: result.sessionId },
243
- { property: 'Name', value: result.name },
244
- { property: 'Description', value: result.description || '-' },
245
- { property: 'Saved At', value: new Date(result.savedAt).toLocaleString() },
246
- { property: 'Agents', value: result.stats.agentCount },
247
- { property: 'Tasks', value: result.stats.taskCount },
248
- { property: 'Memory Entries', value: result.stats.memoryEntries },
249
- { property: 'Total Size', value: formatSize(result.stats.totalSize) }
250
- ]
251
- });
252
-
253
- output.writeln();
254
- output.printSuccess(`Session saved: ${result.sessionId}`);
255
- output.printInfo(`Restore with: claude-flow session restore ${result.sessionId}`);
256
-
257
- if (ctx.flags.format === 'json') {
258
- output.printJson(result);
259
- }
260
-
261
- return { success: true, data: result };
262
- } catch (error) {
263
- spinner.fail('Failed to save session');
264
- if (error instanceof MCPClientError) {
265
- output.printError(`Error: ${error.message}`);
266
- } else {
267
- output.printError(`Unexpected error: ${String(error)}`);
268
- }
269
- return { success: false, exitCode: 1 };
270
- }
271
- }
272
- };
273
-
274
- // Restore subcommand
275
- const restoreCommand: Command = {
276
- name: 'restore',
277
- aliases: ['load'],
278
- description: 'Restore a saved session',
279
- options: [
280
- {
281
- name: 'force',
282
- short: 'f',
283
- description: 'Overwrite current state without confirmation',
284
- type: 'boolean',
285
- default: false
286
- },
287
- {
288
- name: 'memory-only',
289
- description: 'Only restore memory state',
290
- type: 'boolean',
291
- default: false
292
- },
293
- {
294
- name: 'agents-only',
295
- description: 'Only restore agent state',
296
- type: 'boolean',
297
- default: false
298
- },
299
- {
300
- name: 'tasks-only',
301
- description: 'Only restore task state',
302
- type: 'boolean',
303
- default: false
304
- }
305
- ],
306
- action: async (ctx: CommandContext): Promise<CommandResult> => {
307
- let sessionId = ctx.args[0];
308
- const force = ctx.flags.force as boolean;
309
-
310
- if (!sessionId && ctx.interactive) {
311
- // Show list to select from
312
- try {
313
- const sessions = await callMCPTool<{
314
- sessions: Array<{ id: string; name?: string; status: string; updatedAt: string }>;
315
- }>('session/list', { status: 'saved', limit: 20 });
316
-
317
- if (sessions.sessions.length === 0) {
318
- output.printWarning('No saved sessions found');
319
- return { success: false, exitCode: 1 };
320
- }
321
-
322
- sessionId = await select({
323
- message: 'Select session to restore:',
324
- options: sessions.sessions.map(s => ({
325
- value: s.id,
326
- label: s.name || s.id,
327
- hint: formatDate(s.updatedAt)
328
- }))
329
- });
330
- } catch (error) {
331
- if (error instanceof Error && error.message === 'User cancelled') {
332
- output.printInfo('Operation cancelled');
333
- return { success: true };
334
- }
335
- throw error;
336
- }
337
- }
338
-
339
- if (!sessionId) {
340
- output.printError('Session ID is required');
341
- return { success: false, exitCode: 1 };
342
- }
343
-
344
- // Confirm unless forced
345
- if (!force && ctx.interactive) {
346
- const confirmed = await confirm({
347
- message: 'This will overwrite current state. Continue?',
348
- default: false
349
- });
350
-
351
- if (!confirmed) {
352
- output.printInfo('Operation cancelled');
353
- return { success: true };
354
- }
355
- }
356
-
357
- const spinner = output.createSpinner({ text: 'Restoring session...' });
358
- spinner.start();
359
-
360
- try {
361
- // Determine what to restore
362
- const restoreMemory = !ctx.flags['agents-only'] && !ctx.flags['tasks-only'];
363
- const restoreAgents = !ctx.flags['memory-only'] && !ctx.flags['tasks-only'];
364
- const restoreTasks = !ctx.flags['memory-only'] && !ctx.flags['agents-only'];
365
-
366
- const result = await callMCPTool<{
367
- sessionId: string;
368
- restoredAt: string;
369
- restored: {
370
- memory: boolean;
371
- agents: boolean;
372
- tasks: boolean;
373
- };
374
- stats: {
375
- agentsRestored: number;
376
- tasksRestored: number;
377
- memoryEntriesRestored: number;
378
- };
379
- }>('session/restore', {
380
- sessionId,
381
- restoreMemory,
382
- restoreAgents,
383
- restoreTasks
384
- });
385
-
386
- spinner.succeed('Session restored');
387
- output.writeln();
388
-
389
- output.printTable({
390
- columns: [
391
- { key: 'component', header: 'Component', width: 20 },
392
- { key: 'status', header: 'Status', width: 15 },
393
- { key: 'count', header: 'Items', width: 10, align: 'right' }
394
- ],
395
- data: [
396
- {
397
- component: 'Memory',
398
- status: result.restored.memory ? output.success('Restored') : output.dim('Skipped'),
399
- count: result.stats.memoryEntriesRestored
400
- },
401
- {
402
- component: 'Agents',
403
- status: result.restored.agents ? output.success('Restored') : output.dim('Skipped'),
404
- count: result.stats.agentsRestored
405
- },
406
- {
407
- component: 'Tasks',
408
- status: result.restored.tasks ? output.success('Restored') : output.dim('Skipped'),
409
- count: result.stats.tasksRestored
410
- }
411
- ]
412
- });
413
-
414
- output.writeln();
415
- output.printSuccess(`Session ${sessionId} restored successfully`);
416
-
417
- if (ctx.flags.format === 'json') {
418
- output.printJson(result);
419
- }
420
-
421
- return { success: true, data: result };
422
- } catch (error) {
423
- spinner.fail('Failed to restore session');
424
- if (error instanceof MCPClientError) {
425
- output.printError(`Error: ${error.message}`);
426
- } else {
427
- output.printError(`Unexpected error: ${String(error)}`);
428
- }
429
- return { success: false, exitCode: 1 };
430
- }
431
- }
432
- };
433
-
434
- // Delete subcommand
435
- const deleteCommand: Command = {
436
- name: 'delete',
437
- aliases: ['rm', 'remove'],
438
- description: 'Delete a saved session',
439
- options: [
440
- {
441
- name: 'force',
442
- short: 'f',
443
- description: 'Delete without confirmation',
444
- type: 'boolean',
445
- default: false
446
- }
447
- ],
448
- action: async (ctx: CommandContext): Promise<CommandResult> => {
449
- const sessionId = ctx.args[0];
450
- const force = ctx.flags.force as boolean;
451
-
452
- if (!sessionId) {
453
- output.printError('Session ID is required');
454
- return { success: false, exitCode: 1 };
455
- }
456
-
457
- if (!force && ctx.interactive) {
458
- const confirmed = await confirm({
459
- message: `Delete session ${sessionId}? This cannot be undone.`,
460
- default: false
461
- });
462
-
463
- if (!confirmed) {
464
- output.printInfo('Operation cancelled');
465
- return { success: true };
466
- }
467
- }
468
-
469
- try {
470
- const result = await callMCPTool<{
471
- sessionId: string;
472
- deleted: boolean;
473
- deletedAt: string;
474
- }>('session/delete', { sessionId });
475
-
476
- output.writeln();
477
- output.printSuccess(`Session ${sessionId} deleted`);
478
-
479
- if (ctx.flags.format === 'json') {
480
- output.printJson(result);
481
- }
482
-
483
- return { success: true, data: result };
484
- } catch (error) {
485
- if (error instanceof MCPClientError) {
486
- output.printError(`Failed to delete session: ${error.message}`);
487
- } else {
488
- output.printError(`Unexpected error: ${String(error)}`);
489
- }
490
- return { success: false, exitCode: 1 };
491
- }
492
- }
493
- };
494
-
495
- // Export subcommand
496
- const exportCommand: Command = {
497
- name: 'export',
498
- description: 'Export session to file',
499
- options: [
500
- {
501
- name: 'output',
502
- short: 'o',
503
- description: 'Output file path',
504
- type: 'string'
505
- },
506
- {
507
- name: 'format',
508
- short: 'f',
509
- description: 'Export format (json, yaml)',
510
- type: 'string',
511
- choices: ['json', 'yaml'],
512
- default: 'json'
513
- },
514
- {
515
- name: 'include-memory',
516
- description: 'Include memory data',
517
- type: 'boolean',
518
- default: true
519
- },
520
- {
521
- name: 'compress',
522
- description: 'Compress output',
523
- type: 'boolean',
524
- default: false
525
- }
526
- ],
527
- action: async (ctx: CommandContext): Promise<CommandResult> => {
528
- let sessionId = ctx.args[0];
529
- let outputPath = ctx.flags.output as string;
530
- const exportFormat = ctx.flags.format as string;
531
- const compress = ctx.flags.compress as boolean;
532
-
533
- // Get current session if no ID provided
534
- if (!sessionId) {
535
- try {
536
- const current = await callMCPTool<{ sessionId: string }>('session/current', {});
537
- sessionId = current.sessionId;
538
- } catch {
539
- output.printError('No active session. Provide a session ID to export.');
540
- return { success: false, exitCode: 1 };
541
- }
542
- }
543
-
544
- // Generate output path if not provided
545
- if (!outputPath) {
546
- const ext = compress ? '.gz' : '';
547
- outputPath = `session-${sessionId}.${exportFormat}${ext}`;
548
- }
549
-
550
- const spinner = output.createSpinner({ text: 'Exporting session...' });
551
- spinner.start();
552
-
553
- try {
554
- const result = await callMCPTool<{
555
- sessionId: string;
556
- data: unknown;
557
- stats: {
558
- agentCount: number;
559
- taskCount: number;
560
- memoryEntries: number;
561
- };
562
- }>('session/export', {
563
- sessionId,
564
- includeMemory: ctx.flags['include-memory'] !== false
565
- });
566
-
567
- // Format output
568
- let content: string;
569
- if (exportFormat === 'yaml') {
570
- content = toSimpleYaml(result.data);
571
- } else {
572
- content = JSON.stringify(result.data, null, 2);
573
- }
574
-
575
- // Write to file
576
- const absolutePath = path.isAbsolute(outputPath)
577
- ? outputPath
578
- : path.join(ctx.cwd, outputPath);
579
-
580
- fs.writeFileSync(absolutePath, content, 'utf-8');
581
-
582
- spinner.succeed('Session exported');
583
- output.writeln();
584
-
585
- output.printTable({
586
- columns: [
587
- { key: 'property', header: 'Property', width: 18 },
588
- { key: 'value', header: 'Value', width: 40 }
589
- ],
590
- data: [
591
- { property: 'Session ID', value: sessionId },
592
- { property: 'Output File', value: absolutePath },
593
- { property: 'Format', value: exportFormat.toUpperCase() },
594
- { property: 'Agents', value: result.stats.agentCount },
595
- { property: 'Tasks', value: result.stats.taskCount },
596
- { property: 'Memory Entries', value: result.stats.memoryEntries },
597
- { property: 'File Size', value: formatSize(content.length) }
598
- ]
599
- });
600
-
601
- output.writeln();
602
- output.printSuccess(`Session exported to ${outputPath}`);
603
-
604
- return {
605
- success: true,
606
- data: { sessionId, outputPath, format: exportFormat, size: content.length }
607
- };
608
- } catch (error) {
609
- spinner.fail('Failed to export session');
610
- if (error instanceof MCPClientError) {
611
- output.printError(`Error: ${error.message}`);
612
- } else {
613
- output.printError(`Unexpected error: ${String(error)}`);
614
- }
615
- return { success: false, exitCode: 1 };
616
- }
617
- }
618
- };
619
-
620
- // Import subcommand
621
- const importCommand: Command = {
622
- name: 'import',
623
- description: 'Import session from file',
624
- options: [
625
- {
626
- name: 'name',
627
- short: 'n',
628
- description: 'Session name for imported session',
629
- type: 'string'
630
- },
631
- {
632
- name: 'activate',
633
- description: 'Activate session after import',
634
- type: 'boolean',
635
- default: false
636
- }
637
- ],
638
- action: async (ctx: CommandContext): Promise<CommandResult> => {
639
- const filePath = ctx.args[0];
640
- const sessionName = ctx.flags.name as string;
641
- const activate = ctx.flags.activate as boolean;
642
-
643
- if (!filePath) {
644
- output.printError('File path is required');
645
- return { success: false, exitCode: 1 };
646
- }
647
-
648
- const absolutePath = path.isAbsolute(filePath)
649
- ? filePath
650
- : path.join(ctx.cwd, filePath);
651
-
652
- if (!fs.existsSync(absolutePath)) {
653
- output.printError(`File not found: ${absolutePath}`);
654
- return { success: false, exitCode: 1 };
655
- }
656
-
657
- const spinner = output.createSpinner({ text: 'Importing session...' });
658
- spinner.start();
659
-
660
- try {
661
- const content = fs.readFileSync(absolutePath, 'utf-8');
662
- let data: unknown;
663
-
664
- // Parse based on extension
665
- if (absolutePath.endsWith('.yaml') || absolutePath.endsWith('.yml')) {
666
- // Simple YAML parsing (basic implementation)
667
- data = JSON.parse(content); // Would need proper YAML parser
668
- } else {
669
- data = JSON.parse(content);
670
- }
671
-
672
- const result = await callMCPTool<{
673
- sessionId: string;
674
- name: string;
675
- importedAt: string;
676
- stats: {
677
- agentsImported: number;
678
- tasksImported: number;
679
- memoryEntriesImported: number;
680
- };
681
- activated: boolean;
682
- }>('session/import', {
683
- data,
684
- name: sessionName,
685
- activate
686
- });
687
-
688
- spinner.succeed('Session imported');
689
- output.writeln();
690
-
691
- output.printTable({
692
- columns: [
693
- { key: 'property', header: 'Property', width: 20 },
694
- { key: 'value', header: 'Value', width: 35 }
695
- ],
696
- data: [
697
- { property: 'Session ID', value: result.sessionId },
698
- { property: 'Name', value: result.name },
699
- { property: 'Source File', value: path.basename(absolutePath) },
700
- { property: 'Agents Imported', value: result.stats.agentsImported },
701
- { property: 'Tasks Imported', value: result.stats.tasksImported },
702
- { property: 'Memory Entries', value: result.stats.memoryEntriesImported },
703
- { property: 'Activated', value: result.activated ? 'Yes' : 'No' }
704
- ]
705
- });
706
-
707
- output.writeln();
708
- output.printSuccess(`Session imported: ${result.sessionId}`);
709
-
710
- if (!result.activated) {
711
- output.printInfo(`Restore with: claude-flow session restore ${result.sessionId}`);
712
- }
713
-
714
- if (ctx.flags.format === 'json') {
715
- output.printJson(result);
716
- }
717
-
718
- return { success: true, data: result };
719
- } catch (error) {
720
- spinner.fail('Failed to import session');
721
- if (error instanceof MCPClientError) {
722
- output.printError(`Error: ${error.message}`);
723
- } else if (error instanceof SyntaxError) {
724
- output.printError('Invalid file format. Expected JSON or YAML.');
725
- } else {
726
- output.printError(`Unexpected error: ${String(error)}`);
727
- }
728
- return { success: false, exitCode: 1 };
729
- }
730
- }
731
- };
732
-
733
- // Current subcommand
734
- const currentCommand: Command = {
735
- name: 'current',
736
- description: 'Show current active session',
737
- action: async (ctx: CommandContext): Promise<CommandResult> => {
738
- try {
739
- const result = await callMCPTool<{
740
- sessionId: string;
741
- name?: string;
742
- status: string;
743
- startedAt: string;
744
- stats: {
745
- agentCount: number;
746
- taskCount: number;
747
- memoryEntries: number;
748
- duration: number;
749
- };
750
- }>('session/current', { includeStats: true });
751
-
752
- if (ctx.flags.format === 'json') {
753
- output.printJson(result);
754
- return { success: true, data: result };
755
- }
756
-
757
- output.writeln();
758
- output.writeln(output.bold('Current Session'));
759
- output.writeln();
760
-
761
- output.printTable({
762
- columns: [
763
- { key: 'property', header: 'Property', width: 18 },
764
- { key: 'value', header: 'Value', width: 35 }
765
- ],
766
- data: [
767
- { property: 'Session ID', value: result.sessionId },
768
- { property: 'Name', value: result.name || '-' },
769
- { property: 'Status', value: formatStatus(result.status) },
770
- { property: 'Started', value: new Date(result.startedAt).toLocaleString() },
771
- { property: 'Duration', value: formatDuration(result.stats.duration) },
772
- { property: 'Agents', value: result.stats.agentCount },
773
- { property: 'Tasks', value: result.stats.taskCount },
774
- { property: 'Memory Entries', value: result.stats.memoryEntries }
775
- ]
776
- });
777
-
778
- return { success: true, data: result };
779
- } catch (error) {
780
- if (error instanceof MCPClientError) {
781
- output.printWarning('No active session');
782
- output.printInfo('Start a session with "claude-flow start"');
783
- return { success: true, data: { active: false } };
784
- }
785
- output.printError(`Unexpected error: ${String(error)}`);
786
- return { success: false, exitCode: 1 };
787
- }
788
- }
789
- };
790
-
791
- // Helper functions
792
- function formatSize(bytes: number): string {
793
- if (bytes === 0) return '0 B';
794
- const k = 1024;
795
- const sizes = ['B', 'KB', 'MB', 'GB'];
796
- const i = Math.floor(Math.log(bytes) / Math.log(k));
797
- return `${parseFloat((bytes / Math.pow(k, i)).toFixed(1))} ${sizes[i]}`;
798
- }
799
-
800
- function formatDuration(ms: number): string {
801
- const seconds = Math.floor(ms / 1000);
802
- const minutes = Math.floor(seconds / 60);
803
- const hours = Math.floor(minutes / 60);
804
-
805
- if (hours > 0) {
806
- return `${hours}h ${minutes % 60}m`;
807
- } else if (minutes > 0) {
808
- return `${minutes}m ${seconds % 60}s`;
809
- }
810
- return `${seconds}s`;
811
- }
812
-
813
- function toSimpleYaml(obj: unknown, indent: number = 0): string {
814
- // Simple YAML serializer (for basic types)
815
- if (obj === null) return 'null';
816
- if (typeof obj === 'boolean') return String(obj);
817
- if (typeof obj === 'number') return String(obj);
818
- if (typeof obj === 'string') return obj.includes(':') ? `"${obj}"` : obj;
819
-
820
- const spaces = ' '.repeat(indent);
821
- let result = '';
822
-
823
- if (Array.isArray(obj)) {
824
- for (const item of obj) {
825
- result += `${spaces}- ${toSimpleYaml(item, indent + 1).trim()}\n`;
826
- }
827
- return result;
828
- }
829
-
830
- if (typeof obj === 'object') {
831
- for (const [key, value] of Object.entries(obj)) {
832
- if (typeof value === 'object' && value !== null) {
833
- result += `${spaces}${key}:\n${toSimpleYaml(value, indent + 1)}`;
834
- } else {
835
- result += `${spaces}${key}: ${toSimpleYaml(value, indent)}\n`;
836
- }
837
- }
838
- return result;
839
- }
840
-
841
- return String(obj);
842
- }
843
-
844
- // Main session command
845
- export const sessionCommand: Command = {
846
- name: 'session',
847
- description: 'Session management commands',
848
- subcommands: [
849
- listCommand,
850
- saveCommand,
851
- restoreCommand,
852
- deleteCommand,
853
- exportCommand,
854
- importCommand,
855
- currentCommand
856
- ],
857
- options: [],
858
- examples: [
859
- { command: 'claude-flow session list', description: 'List all sessions' },
860
- { command: 'claude-flow session save -n "checkpoint-1"', description: 'Save current session' },
861
- { command: 'claude-flow session restore session-123', description: 'Restore a session' },
862
- { command: 'claude-flow session delete session-123', description: 'Delete a session' },
863
- { command: 'claude-flow session export -o backup.json', description: 'Export session to file' },
864
- { command: 'claude-flow session import backup.json', description: 'Import session from file' },
865
- { command: 'claude-flow session current', description: 'Show current session' }
866
- ],
867
- action: async (ctx: CommandContext): Promise<CommandResult> => {
868
- // Show help if no subcommand
869
- output.writeln();
870
- output.writeln(output.bold('Session Management Commands'));
871
- output.writeln();
872
- output.writeln('Usage: claude-flow session <subcommand> [options]');
873
- output.writeln();
874
- output.writeln('Subcommands:');
875
- output.printList([
876
- `${output.highlight('list')} - List all sessions`,
877
- `${output.highlight('save')} - Save current session state`,
878
- `${output.highlight('restore')} - Restore a saved session`,
879
- `${output.highlight('delete')} - Delete a saved session`,
880
- `${output.highlight('export')} - Export session to file`,
881
- `${output.highlight('import')} - Import session from file`,
882
- `${output.highlight('current')} - Show current active session`
883
- ]);
884
- output.writeln();
885
- output.writeln('Run "claude-flow session <subcommand> --help" for subcommand help');
886
-
887
- return { success: true };
888
- }
889
- };
890
-
891
- export default sessionCommand;