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

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 (102) hide show
  1. package/package.json +12 -4
  2. package/.agentic-flow/intelligence.json +0 -17
  3. package/.claude-flow/agents/store.json +0 -16
  4. package/.claude-flow/daemon-state.json +0 -123
  5. package/.claude-flow/daemon-test.log +0 -0
  6. package/.claude-flow/daemon.log +0 -0
  7. package/.claude-flow/daemon2.log +0 -0
  8. package/.claude-flow/daemon3.log +0 -0
  9. package/.claude-flow/hive-mind/state.json +0 -51
  10. package/.claude-flow/metrics/agent-metrics.json +0 -1
  11. package/.claude-flow/metrics/codebase-map.json +0 -11
  12. package/.claude-flow/metrics/consolidation.json +0 -6
  13. package/.claude-flow/metrics/performance.json +0 -87
  14. package/.claude-flow/metrics/security-audit.json +0 -10
  15. package/.claude-flow/metrics/task-metrics.json +0 -10
  16. package/.claude-flow/metrics/test-gaps.json +0 -6
  17. package/__tests__/README.md +0 -140
  18. package/__tests__/TEST_SUMMARY.md +0 -144
  19. package/__tests__/cli.test.ts +0 -558
  20. package/__tests__/commands.test.ts +0 -726
  21. package/__tests__/config-adapter.test.ts +0 -362
  22. package/__tests__/config-loading.test.ts +0 -106
  23. package/__tests__/coverage/.tmp/coverage-0.json +0 -1
  24. package/__tests__/coverage/.tmp/coverage-1.json +0 -1
  25. package/__tests__/coverage/.tmp/coverage-2.json +0 -1
  26. package/__tests__/coverage/.tmp/coverage-3.json +0 -1
  27. package/__tests__/coverage/.tmp/coverage-4.json +0 -1
  28. package/__tests__/coverage/.tmp/coverage-5.json +0 -1
  29. package/__tests__/mcp-client.test.ts +0 -480
  30. package/__tests__/p1-commands.test.ts +0 -1064
  31. package/agents/architect.yaml +0 -11
  32. package/agents/coder.yaml +0 -11
  33. package/agents/reviewer.yaml +0 -10
  34. package/agents/security-architect.yaml +0 -10
  35. package/agents/tester.yaml +0 -10
  36. package/docs/CONFIG_LOADING.md +0 -236
  37. package/docs/IMPLEMENTATION_COMPLETE.md +0 -421
  38. package/docs/MCP_CLIENT_GUIDE.md +0 -620
  39. package/docs/REFACTORING_SUMMARY.md +0 -247
  40. package/scripts/publish.sh +0 -46
  41. package/src/commands/agent.ts +0 -955
  42. package/src/commands/claims.ts +0 -317
  43. package/src/commands/completions.ts +0 -558
  44. package/src/commands/config.ts +0 -452
  45. package/src/commands/daemon.ts +0 -621
  46. package/src/commands/deployment.ts +0 -323
  47. package/src/commands/doctor.ts +0 -382
  48. package/src/commands/embeddings.ts +0 -686
  49. package/src/commands/hive-mind.ts +0 -928
  50. package/src/commands/hooks.ts +0 -2603
  51. package/src/commands/index.ts +0 -154
  52. package/src/commands/init.ts +0 -597
  53. package/src/commands/mcp.ts +0 -753
  54. package/src/commands/memory.ts +0 -1161
  55. package/src/commands/migrate.ts +0 -447
  56. package/src/commands/neural.ts +0 -253
  57. package/src/commands/performance.ts +0 -292
  58. package/src/commands/plugins.ts +0 -316
  59. package/src/commands/process.ts +0 -695
  60. package/src/commands/providers.ts +0 -259
  61. package/src/commands/security.ts +0 -288
  62. package/src/commands/session.ts +0 -891
  63. package/src/commands/start.ts +0 -457
  64. package/src/commands/status.ts +0 -736
  65. package/src/commands/swarm.ts +0 -648
  66. package/src/commands/task.ts +0 -792
  67. package/src/commands/workflow.ts +0 -742
  68. package/src/config-adapter.ts +0 -210
  69. package/src/index.ts +0 -443
  70. package/src/infrastructure/in-memory-repositories.ts +0 -310
  71. package/src/init/claudemd-generator.ts +0 -631
  72. package/src/init/executor.ts +0 -762
  73. package/src/init/helpers-generator.ts +0 -628
  74. package/src/init/index.ts +0 -60
  75. package/src/init/mcp-generator.ts +0 -83
  76. package/src/init/settings-generator.ts +0 -284
  77. package/src/init/statusline-generator.ts +0 -211
  78. package/src/init/types.ts +0 -447
  79. package/src/mcp-client.ts +0 -241
  80. package/src/mcp-server.ts +0 -577
  81. package/src/mcp-tools/agent-tools.ts +0 -466
  82. package/src/mcp-tools/config-tools.ts +0 -370
  83. package/src/mcp-tools/hive-mind-tools.ts +0 -521
  84. package/src/mcp-tools/hooks-tools.ts +0 -1888
  85. package/src/mcp-tools/index.ts +0 -16
  86. package/src/mcp-tools/memory-tools.ts +0 -270
  87. package/src/mcp-tools/session-tools.ts +0 -359
  88. package/src/mcp-tools/swarm-tools.ts +0 -105
  89. package/src/mcp-tools/task-tools.ts +0 -347
  90. package/src/mcp-tools/types.ts +0 -33
  91. package/src/mcp-tools/workflow-tools.ts +0 -573
  92. package/src/output.ts +0 -639
  93. package/src/parser.ts +0 -417
  94. package/src/prompt.ts +0 -619
  95. package/src/services/index.ts +0 -15
  96. package/src/services/worker-daemon.ts +0 -726
  97. package/src/suggest.ts +0 -245
  98. package/src/types.ts +0 -287
  99. package/tmp.json +0 -0
  100. package/tsconfig.json +0 -16
  101. package/tsconfig.tsbuildinfo +0 -1
  102. 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;