@claude-flow/cli 3.0.0-alpha.1

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