@wundr.io/cli 1.0.12 → 1.0.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 (233) hide show
  1. package/dist/ai/ai-service.d.ts +152 -0
  2. package/dist/ai/ai-service.d.ts.map +1 -0
  3. package/dist/ai/ai-service.js +430 -0
  4. package/dist/ai/ai-service.js.map +1 -0
  5. package/dist/ai/claude-client.d.ts +130 -0
  6. package/dist/ai/claude-client.d.ts.map +1 -0
  7. package/dist/ai/claude-client.js +340 -0
  8. package/dist/ai/claude-client.js.map +1 -0
  9. package/dist/ai/conversation-manager.d.ts +164 -0
  10. package/dist/ai/conversation-manager.d.ts.map +1 -0
  11. package/dist/ai/conversation-manager.js +614 -0
  12. package/dist/ai/conversation-manager.js.map +1 -0
  13. package/dist/ai/index.d.ts +5 -0
  14. package/dist/ai/index.d.ts.map +1 -0
  15. package/dist/ai/index.js +8 -0
  16. package/dist/ai/index.js.map +1 -0
  17. package/dist/cli.d.ts +36 -0
  18. package/dist/cli.d.ts.map +1 -0
  19. package/dist/cli.js +192 -0
  20. package/dist/cli.js.map +1 -0
  21. package/dist/commands/ai.d.ts +89 -0
  22. package/dist/commands/ai.d.ts.map +1 -0
  23. package/dist/commands/ai.js +954 -0
  24. package/dist/commands/ai.js.map +1 -0
  25. package/dist/commands/alignment.d.ts +78 -0
  26. package/dist/commands/alignment.d.ts.map +1 -0
  27. package/dist/commands/alignment.js +817 -0
  28. package/dist/commands/alignment.js.map +1 -0
  29. package/dist/commands/analyze-optimized.d.ts +14 -0
  30. package/dist/commands/analyze-optimized.d.ts.map +1 -0
  31. package/dist/commands/analyze-optimized.js +609 -0
  32. package/dist/commands/analyze-optimized.js.map +1 -0
  33. package/dist/commands/analyze.d.ts +65 -0
  34. package/dist/commands/analyze.d.ts.map +1 -0
  35. package/dist/commands/analyze.js +435 -0
  36. package/dist/commands/analyze.js.map +1 -0
  37. package/dist/commands/batch.d.ts +93 -0
  38. package/dist/commands/batch.d.ts.map +1 -0
  39. package/dist/commands/batch.js +854 -0
  40. package/dist/commands/batch.js.map +1 -0
  41. package/dist/commands/chat.d.ts +72 -0
  42. package/dist/commands/chat.d.ts.map +1 -0
  43. package/dist/commands/chat.js +678 -0
  44. package/dist/commands/chat.js.map +1 -0
  45. package/dist/commands/claude-init.d.ts +28 -0
  46. package/dist/commands/claude-init.d.ts.map +1 -0
  47. package/dist/commands/claude-init.js +591 -0
  48. package/dist/commands/claude-init.js.map +1 -0
  49. package/dist/commands/claude-setup.d.ts +119 -0
  50. package/dist/commands/claude-setup.d.ts.map +1 -0
  51. package/dist/commands/claude-setup.js +1079 -0
  52. package/dist/commands/claude-setup.js.map +1 -0
  53. package/dist/commands/computer-setup.d.ts +8 -0
  54. package/dist/commands/computer-setup.d.ts.map +1 -0
  55. package/dist/commands/computer-setup.js +877 -0
  56. package/dist/commands/computer-setup.js.map +1 -0
  57. package/dist/commands/create-command.d.ts +7 -0
  58. package/dist/commands/create-command.d.ts.map +1 -0
  59. package/dist/commands/create-command.js +158 -0
  60. package/dist/commands/create-command.js.map +1 -0
  61. package/dist/commands/create.d.ts +74 -0
  62. package/dist/commands/create.d.ts.map +1 -0
  63. package/dist/commands/create.js +556 -0
  64. package/dist/commands/create.js.map +1 -0
  65. package/dist/commands/dashboard.d.ts +91 -0
  66. package/dist/commands/dashboard.d.ts.map +1 -0
  67. package/dist/commands/dashboard.js +538 -0
  68. package/dist/commands/dashboard.js.map +1 -0
  69. package/dist/commands/govern.d.ts +70 -0
  70. package/dist/commands/govern.d.ts.map +1 -0
  71. package/dist/commands/govern.js +481 -0
  72. package/dist/commands/govern.js.map +1 -0
  73. package/dist/commands/governance.d.ts +17 -0
  74. package/dist/commands/governance.d.ts.map +1 -0
  75. package/dist/commands/governance.js +703 -0
  76. package/dist/commands/governance.js.map +1 -0
  77. package/dist/commands/guardian.d.ts +20 -0
  78. package/dist/commands/guardian.d.ts.map +1 -0
  79. package/dist/commands/guardian.js +597 -0
  80. package/dist/commands/guardian.js.map +1 -0
  81. package/dist/commands/init.d.ts +59 -0
  82. package/dist/commands/init.d.ts.map +1 -0
  83. package/dist/commands/init.js +650 -0
  84. package/dist/commands/init.js.map +1 -0
  85. package/dist/commands/orchestrator.d.ts +7 -0
  86. package/dist/commands/orchestrator.d.ts.map +1 -0
  87. package/dist/commands/orchestrator.js +578 -0
  88. package/dist/commands/orchestrator.js.map +1 -0
  89. package/dist/commands/performance-optimizer.d.ts +30 -0
  90. package/dist/commands/performance-optimizer.d.ts.map +1 -0
  91. package/dist/commands/performance-optimizer.js +650 -0
  92. package/dist/commands/performance-optimizer.js.map +1 -0
  93. package/dist/commands/plugins.d.ts +87 -0
  94. package/dist/commands/plugins.d.ts.map +1 -0
  95. package/dist/commands/plugins.js +685 -0
  96. package/dist/commands/plugins.js.map +1 -0
  97. package/dist/commands/rag.d.ts +7 -0
  98. package/dist/commands/rag.d.ts.map +1 -0
  99. package/dist/commands/rag.js +751 -0
  100. package/dist/commands/rag.js.map +1 -0
  101. package/dist/commands/session.d.ts +41 -0
  102. package/dist/commands/session.d.ts.map +1 -0
  103. package/dist/commands/session.js +441 -0
  104. package/dist/commands/session.js.map +1 -0
  105. package/dist/commands/setup.d.ts +24 -0
  106. package/dist/commands/setup.d.ts.map +1 -0
  107. package/dist/commands/setup.js +172 -0
  108. package/dist/commands/setup.js.map +1 -0
  109. package/dist/commands/test-init.d.ts +9 -0
  110. package/dist/commands/test-init.d.ts.map +1 -0
  111. package/dist/commands/test-init.js +222 -0
  112. package/dist/commands/test-init.js.map +1 -0
  113. package/dist/commands/test.d.ts +25 -0
  114. package/dist/commands/test.d.ts.map +1 -0
  115. package/dist/commands/test.js +217 -0
  116. package/dist/commands/test.js.map +1 -0
  117. package/dist/commands/watch.d.ts +76 -0
  118. package/dist/commands/watch.d.ts.map +1 -0
  119. package/dist/commands/watch.js +613 -0
  120. package/dist/commands/watch.js.map +1 -0
  121. package/dist/commands/worktree.d.ts +63 -0
  122. package/dist/commands/worktree.d.ts.map +1 -0
  123. package/dist/commands/worktree.js +774 -0
  124. package/dist/commands/worktree.js.map +1 -0
  125. package/dist/context/context-manager.d.ts +155 -0
  126. package/dist/context/context-manager.d.ts.map +1 -0
  127. package/dist/context/context-manager.js +383 -0
  128. package/dist/context/context-manager.js.map +1 -0
  129. package/dist/context/index.d.ts +3 -0
  130. package/dist/context/index.d.ts.map +1 -0
  131. package/dist/context/index.js +6 -0
  132. package/dist/context/index.js.map +1 -0
  133. package/dist/context/session-manager.d.ts +207 -0
  134. package/dist/context/session-manager.d.ts.map +1 -0
  135. package/dist/context/session-manager.js +686 -0
  136. package/dist/context/session-manager.js.map +1 -0
  137. package/dist/framework/command-interface.d.ts +349 -0
  138. package/dist/framework/command-interface.d.ts.map +1 -0
  139. package/dist/framework/command-interface.js +101 -0
  140. package/dist/framework/command-interface.js.map +1 -0
  141. package/dist/framework/command-registry.d.ts +173 -0
  142. package/dist/framework/command-registry.d.ts.map +1 -0
  143. package/dist/framework/command-registry.js +734 -0
  144. package/dist/framework/command-registry.js.map +1 -0
  145. package/dist/framework/completion-exporter.d.ts +79 -0
  146. package/dist/framework/completion-exporter.d.ts.map +1 -0
  147. package/dist/framework/completion-exporter.js +259 -0
  148. package/dist/framework/completion-exporter.js.map +1 -0
  149. package/dist/framework/debug-logger.d.ts +163 -0
  150. package/dist/framework/debug-logger.d.ts.map +1 -0
  151. package/dist/framework/debug-logger.js +373 -0
  152. package/dist/framework/debug-logger.js.map +1 -0
  153. package/dist/framework/error-handler.d.ts +196 -0
  154. package/dist/framework/error-handler.d.ts.map +1 -0
  155. package/dist/framework/error-handler.js +613 -0
  156. package/dist/framework/error-handler.js.map +1 -0
  157. package/dist/framework/help-generator.d.ts +78 -0
  158. package/dist/framework/help-generator.d.ts.map +1 -0
  159. package/dist/framework/help-generator.js +414 -0
  160. package/dist/framework/help-generator.js.map +1 -0
  161. package/dist/framework/index.d.ts +62 -0
  162. package/dist/framework/index.d.ts.map +1 -0
  163. package/dist/framework/index.js +95 -0
  164. package/dist/framework/index.js.map +1 -0
  165. package/dist/framework/interactive-repl.d.ts +138 -0
  166. package/dist/framework/interactive-repl.d.ts.map +1 -0
  167. package/dist/framework/interactive-repl.js +567 -0
  168. package/dist/framework/interactive-repl.js.map +1 -0
  169. package/dist/framework/output-formatter.d.ts +274 -0
  170. package/dist/framework/output-formatter.d.ts.map +1 -0
  171. package/dist/framework/output-formatter.js +545 -0
  172. package/dist/framework/output-formatter.js.map +1 -0
  173. package/dist/framework/progress-manager.d.ts +192 -0
  174. package/dist/framework/progress-manager.d.ts.map +1 -0
  175. package/dist/framework/progress-manager.js +408 -0
  176. package/dist/framework/progress-manager.js.map +1 -0
  177. package/dist/index.d.ts +8 -0
  178. package/dist/index.d.ts.map +1 -0
  179. package/dist/index.js +51 -0
  180. package/dist/index.js.map +1 -0
  181. package/dist/interactive/interactive-mode.d.ts +76 -0
  182. package/dist/interactive/interactive-mode.d.ts.map +1 -0
  183. package/dist/interactive/interactive-mode.js +732 -0
  184. package/dist/interactive/interactive-mode.js.map +1 -0
  185. package/dist/nlp/command-mapper.d.ts +174 -0
  186. package/dist/nlp/command-mapper.d.ts.map +1 -0
  187. package/dist/nlp/command-mapper.js +624 -0
  188. package/dist/nlp/command-mapper.js.map +1 -0
  189. package/dist/nlp/command-parser.d.ts +106 -0
  190. package/dist/nlp/command-parser.d.ts.map +1 -0
  191. package/dist/nlp/command-parser.js +417 -0
  192. package/dist/nlp/command-parser.js.map +1 -0
  193. package/dist/nlp/index.d.ts +5 -0
  194. package/dist/nlp/index.d.ts.map +1 -0
  195. package/dist/nlp/index.js +8 -0
  196. package/dist/nlp/index.js.map +1 -0
  197. package/dist/nlp/intent-classifier.d.ts +59 -0
  198. package/dist/nlp/intent-classifier.d.ts.map +1 -0
  199. package/dist/nlp/intent-classifier.js +384 -0
  200. package/dist/nlp/intent-classifier.js.map +1 -0
  201. package/dist/nlp/intent-parser.d.ts +152 -0
  202. package/dist/nlp/intent-parser.d.ts.map +1 -0
  203. package/dist/nlp/intent-parser.js +746 -0
  204. package/dist/nlp/intent-parser.js.map +1 -0
  205. package/dist/plugins/plugin-manager.d.ts +121 -0
  206. package/dist/plugins/plugin-manager.d.ts.map +1 -0
  207. package/dist/plugins/plugin-manager.js +606 -0
  208. package/dist/plugins/plugin-manager.js.map +1 -0
  209. package/dist/types/index.d.ts +224 -0
  210. package/dist/types/index.d.ts.map +1 -0
  211. package/dist/types/index.js +3 -0
  212. package/dist/types/index.js.map +1 -0
  213. package/dist/utils/backup-rollback-manager.d.ts +72 -0
  214. package/dist/utils/backup-rollback-manager.d.ts.map +1 -0
  215. package/dist/utils/backup-rollback-manager.js +288 -0
  216. package/dist/utils/backup-rollback-manager.js.map +1 -0
  217. package/dist/utils/claude-config-installer.d.ts +98 -0
  218. package/dist/utils/claude-config-installer.d.ts.map +1 -0
  219. package/dist/utils/claude-config-installer.js +678 -0
  220. package/dist/utils/claude-config-installer.js.map +1 -0
  221. package/dist/utils/config-manager.d.ts +73 -0
  222. package/dist/utils/config-manager.d.ts.map +1 -0
  223. package/dist/utils/config-manager.js +339 -0
  224. package/dist/utils/config-manager.js.map +1 -0
  225. package/dist/utils/error-handler.d.ts +46 -0
  226. package/dist/utils/error-handler.d.ts.map +1 -0
  227. package/dist/utils/error-handler.js +169 -0
  228. package/dist/utils/error-handler.js.map +1 -0
  229. package/dist/utils/logger.d.ts +25 -0
  230. package/dist/utils/logger.d.ts.map +1 -0
  231. package/dist/utils/logger.js +105 -0
  232. package/dist/utils/logger.js.map +1 -0
  233. package/package.json +6 -6
@@ -0,0 +1,686 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SessionManager = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const events_1 = require("events");
6
+ const path_1 = tslib_1.__importDefault(require("path"));
7
+ const fs_extra_1 = tslib_1.__importDefault(require("fs-extra"));
8
+ const logger_1 = require("../utils/logger");
9
+ /**
10
+ * Session manager for persistent context, user preferences, and workspace management
11
+ */
12
+ class SessionManager extends events_1.EventEmitter {
13
+ config;
14
+ conversationManager;
15
+ commandMapper;
16
+ activeSessions;
17
+ workspaces;
18
+ currentSessionId;
19
+ backupTimer;
20
+ cleanupTimer;
21
+ constructor(conversationManager, commandMapper, config = {}) {
22
+ super();
23
+ this.conversationManager = conversationManager;
24
+ this.commandMapper = commandMapper;
25
+ this.config = {
26
+ persistencePath: path_1.default.join(process.cwd(), '.wundr', 'sessions'),
27
+ sessionTimeout: 24 * 60, // 24 hours
28
+ maxSessions: 10,
29
+ autoDetectProjects: true,
30
+ enableContextLearning: true,
31
+ backupInterval: 15, // 15 minutes
32
+ ...config,
33
+ };
34
+ this.activeSessions = new Map();
35
+ this.workspaces = new Map();
36
+ this.initialize();
37
+ }
38
+ /**
39
+ * Create or resume a session
40
+ */
41
+ async createSession(userId, workspacePath, sessionId) {
42
+ const id = sessionId ||
43
+ `session_${userId}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
44
+ // Check if session already exists
45
+ if (this.activeSessions.has(id)) {
46
+ await this.resumeSession(id);
47
+ return id;
48
+ }
49
+ const workspace = workspacePath || process.cwd();
50
+ const projectContext = await this.detectProjectContext(workspace);
51
+ const session = {
52
+ id,
53
+ userId,
54
+ currentWorkspace: workspace,
55
+ recentCommands: [],
56
+ contextStack: [],
57
+ userPreferences: await this.loadUserPreferences(userId),
58
+ projectContext,
59
+ temporaryData: {},
60
+ created: new Date(),
61
+ lastAccessed: new Date(),
62
+ };
63
+ // Load workspace if it exists
64
+ const workspaceConfig = await this.loadWorkspace(workspace);
65
+ if (workspaceConfig) {
66
+ workspaceConfig.lastAccessed = new Date();
67
+ this.workspaces.set(workspace, workspaceConfig);
68
+ }
69
+ this.activeSessions.set(id, session);
70
+ this.currentSessionId = id;
71
+ await this.persistSession(session);
72
+ this.emit('session_created', { sessionId: id, userId, workspace });
73
+ logger_1.logger.debug(`Created session: ${id} for user: ${userId}`);
74
+ return id;
75
+ }
76
+ /**
77
+ * Resume an existing session
78
+ */
79
+ async resumeSession(sessionId) {
80
+ let session = this.activeSessions.get(sessionId);
81
+ if (!session) {
82
+ // Try to load from persistence
83
+ session = (await this.loadSession(sessionId)) || undefined;
84
+ if (!session) {
85
+ throw new Error(`Session not found: ${sessionId}`);
86
+ }
87
+ }
88
+ session.lastAccessed = new Date();
89
+ this.currentSessionId = sessionId;
90
+ this.activeSessions.set(sessionId, session);
91
+ // Refresh project context
92
+ if (session.projectContext) {
93
+ session.projectContext = await this.detectProjectContext(session.currentWorkspace);
94
+ }
95
+ await this.persistSession(session);
96
+ this.emit('session_resumed', { sessionId, session });
97
+ logger_1.logger.debug(`Resumed session: ${sessionId}`);
98
+ return session;
99
+ }
100
+ /**
101
+ * Get current session
102
+ */
103
+ getCurrentSession() {
104
+ if (!this.currentSessionId) {
105
+ return null;
106
+ }
107
+ return this.activeSessions.get(this.currentSessionId) || null;
108
+ }
109
+ /**
110
+ * Get session by ID
111
+ */
112
+ getSession(sessionId) {
113
+ return this.activeSessions.get(sessionId) || null;
114
+ }
115
+ /**
116
+ * Update session context
117
+ */
118
+ async updateSessionContext(sessionId, contextType, contextData) {
119
+ const session = this.activeSessions.get(sessionId);
120
+ if (!session) {
121
+ throw new Error(`Session not found: ${sessionId}`);
122
+ }
123
+ // Add to context stack
124
+ session.contextStack.push({
125
+ type: contextType,
126
+ context: contextData,
127
+ timestamp: new Date(),
128
+ });
129
+ // Limit context stack size
130
+ if (session.contextStack.length > 50) {
131
+ session.contextStack = session.contextStack.slice(-25);
132
+ }
133
+ // Update specific context based on type
134
+ switch (contextType) {
135
+ case 'project':
136
+ session.projectContext = { ...session.projectContext, ...contextData };
137
+ break;
138
+ case 'conversation':
139
+ session.activeConversation = contextData.conversationId;
140
+ break;
141
+ }
142
+ session.lastAccessed = new Date();
143
+ await this.persistSession(session);
144
+ this.emit('context_updated', { sessionId, contextType, contextData });
145
+ }
146
+ /**
147
+ * Add command to session history
148
+ */
149
+ async addCommandToHistory(sessionId, command, success, duration) {
150
+ const session = this.activeSessions.get(sessionId);
151
+ if (!session) {
152
+ throw new Error(`Session not found: ${sessionId}`);
153
+ }
154
+ session.recentCommands.push({
155
+ command,
156
+ timestamp: new Date(),
157
+ success,
158
+ duration,
159
+ });
160
+ // Limit history size
161
+ const maxHistory = session.userPreferences.maxHistoryLength || 100;
162
+ if (session.recentCommands.length > maxHistory) {
163
+ session.recentCommands = session.recentCommands.slice(-maxHistory / 2);
164
+ }
165
+ session.lastAccessed = new Date();
166
+ await this.persistSession(session);
167
+ // Learn from command patterns if enabled
168
+ if (this.config.enableContextLearning) {
169
+ await this.analyzeCommandPatterns(session);
170
+ }
171
+ this.emit('command_recorded', { sessionId, command, success, duration });
172
+ }
173
+ /**
174
+ * Update user preferences
175
+ */
176
+ async updateUserPreferences(userId, preferences) {
177
+ const defaultPreferences = this.getDefaultPreferences();
178
+ const currentPreferences = await this.loadUserPreferences(userId);
179
+ const updatedPreferences = { ...currentPreferences, ...preferences };
180
+ await this.saveUserPreferences(userId, updatedPreferences);
181
+ // Update all active sessions for this user
182
+ for (const [sessionId, session] of this.activeSessions) {
183
+ if (session.userId === userId) {
184
+ session.userPreferences = updatedPreferences;
185
+ await this.persistSession(session);
186
+ }
187
+ }
188
+ this.emit('preferences_updated', {
189
+ userId,
190
+ preferences: updatedPreferences,
191
+ });
192
+ logger_1.logger.debug(`Updated preferences for user: ${userId}`);
193
+ }
194
+ /**
195
+ * Register a workspace
196
+ */
197
+ async registerWorkspace(workspacePath, config) {
198
+ const workspace = {
199
+ name: config.name || path_1.default.basename(workspacePath),
200
+ path: workspacePath,
201
+ type: config.type || 'unknown',
202
+ settings: config.settings || {},
203
+ lastAccessed: new Date(),
204
+ bookmarked: config.bookmarked || false,
205
+ };
206
+ this.workspaces.set(workspacePath, workspace);
207
+ await this.saveWorkspace(workspace);
208
+ this.emit('workspace_registered', { workspace });
209
+ logger_1.logger.debug(`Registered workspace: ${workspacePath}`);
210
+ }
211
+ /**
212
+ * Get workspace suggestions based on recent activity
213
+ */
214
+ getWorkspaceSuggestions(limit = 5) {
215
+ const workspaces = Array.from(this.workspaces.values()).sort((a, b) => b.lastAccessed.getTime() - a.lastAccessed.getTime());
216
+ return workspaces.slice(0, limit);
217
+ }
218
+ /**
219
+ * Search session history
220
+ */
221
+ searchHistory(sessionId, query) {
222
+ const session = this.activeSessions.get(sessionId);
223
+ if (!session) {
224
+ return [];
225
+ }
226
+ let history = session.recentCommands;
227
+ if (query.command) {
228
+ const searchTerm = query.command.toLowerCase();
229
+ history = history.filter(cmd => cmd.command.toLowerCase().includes(searchTerm));
230
+ }
231
+ if (query.timeRange) {
232
+ history = history.filter(cmd => cmd.timestamp >= query.timeRange.from &&
233
+ cmd.timestamp <= query.timeRange.to);
234
+ }
235
+ if (query.successOnly) {
236
+ history = history.filter(cmd => cmd.success);
237
+ }
238
+ if (query.limit) {
239
+ history = history.slice(-query.limit);
240
+ }
241
+ return history;
242
+ }
243
+ /**
244
+ * Get contextual suggestions based on current session
245
+ */
246
+ async getContextualSuggestions(sessionId, limit = 5) {
247
+ const session = this.activeSessions.get(sessionId);
248
+ if (!session) {
249
+ return [];
250
+ }
251
+ const suggestions = [];
252
+ // Command suggestions based on recent history
253
+ const recentCommands = session.recentCommands
254
+ .filter(cmd => cmd.success)
255
+ .slice(-10);
256
+ const commandFrequency = new Map();
257
+ for (const cmd of recentCommands) {
258
+ const baseCommand = cmd.command.split(' ')[0];
259
+ if (baseCommand) {
260
+ commandFrequency.set(baseCommand, (commandFrequency.get(baseCommand) || 0) + 1);
261
+ }
262
+ }
263
+ for (const [command, frequency] of commandFrequency) {
264
+ suggestions.push({
265
+ type: 'command',
266
+ suggestion: command,
267
+ description: `Recently used command (${frequency} times)`,
268
+ confidence: Math.min(0.9, frequency * 0.2),
269
+ });
270
+ }
271
+ // Workspace suggestions
272
+ const workspaceSuggestions = this.getWorkspaceSuggestions(3);
273
+ for (const workspace of workspaceSuggestions) {
274
+ if (workspace.path !== session.currentWorkspace) {
275
+ suggestions.push({
276
+ type: 'workspace',
277
+ suggestion: workspace.path,
278
+ description: `Switch to ${workspace.name}`,
279
+ confidence: 0.6,
280
+ });
281
+ }
282
+ }
283
+ // Sort by confidence and limit
284
+ suggestions.sort((a, b) => b.confidence - a.confidence);
285
+ return suggestions.slice(0, limit);
286
+ }
287
+ /**
288
+ * Export session data
289
+ */
290
+ async exportSession(sessionId, format) {
291
+ const session = this.activeSessions.get(sessionId);
292
+ if (!session) {
293
+ throw new Error(`Session not found: ${sessionId}`);
294
+ }
295
+ switch (format) {
296
+ case 'json':
297
+ return JSON.stringify(session, null, 2);
298
+ case 'csv':
299
+ return this.sessionToCsv(session);
300
+ default:
301
+ throw new Error(`Unsupported export format: ${format}`);
302
+ }
303
+ }
304
+ /**
305
+ * Clean up expired sessions
306
+ */
307
+ async cleanupSessions() {
308
+ const now = new Date();
309
+ const timeoutMs = this.config.sessionTimeout * 60 * 1000;
310
+ const expiredSessions = [];
311
+ for (const [sessionId, session] of this.activeSessions) {
312
+ const timeSinceAccess = now.getTime() - session.lastAccessed.getTime();
313
+ if (timeSinceAccess > timeoutMs) {
314
+ expiredSessions.push(sessionId);
315
+ }
316
+ }
317
+ for (const sessionId of expiredSessions) {
318
+ const session = this.activeSessions.get(sessionId);
319
+ // Final persist before cleanup
320
+ await this.persistSession(session);
321
+ this.activeSessions.delete(sessionId);
322
+ this.emit('session_expired', { sessionId });
323
+ }
324
+ // Limit active sessions
325
+ if (this.activeSessions.size > this.config.maxSessions) {
326
+ const sessionsByAccess = Array.from(this.activeSessions.entries()).sort(([, a], [, b]) => a.lastAccessed.getTime() - b.lastAccessed.getTime());
327
+ const excessCount = this.activeSessions.size - this.config.maxSessions;
328
+ const toRemove = sessionsByAccess.slice(0, excessCount);
329
+ for (const [sessionId, session] of toRemove) {
330
+ await this.persistSession(session);
331
+ this.activeSessions.delete(sessionId);
332
+ this.emit('session_archived', { sessionId });
333
+ }
334
+ }
335
+ if (expiredSessions.length > 0) {
336
+ logger_1.logger.debug(`Cleaned up ${expiredSessions.length} expired sessions`);
337
+ }
338
+ }
339
+ /**
340
+ * Get session statistics
341
+ */
342
+ getSessionStats() {
343
+ const activeSessions = this.activeSessions.size;
344
+ const totalCommands = Array.from(this.activeSessions.values()).reduce((sum, session) => sum + session.recentCommands.length, 0);
345
+ const sessionDurations = Array.from(this.activeSessions.values()).map(session => session.lastAccessed.getTime() - session.created.getTime());
346
+ const averageSessionDuration = sessionDurations.length > 0
347
+ ? sessionDurations.reduce((sum, duration) => sum + duration, 0) /
348
+ sessionDurations.length
349
+ : 0;
350
+ // Command frequency analysis
351
+ const commandCounts = new Map();
352
+ for (const session of this.activeSessions.values()) {
353
+ for (const cmd of session.recentCommands) {
354
+ const baseCommand = cmd.command.split(' ')[0];
355
+ if (baseCommand) {
356
+ commandCounts.set(baseCommand, (commandCounts.get(baseCommand) || 0) + 1);
357
+ }
358
+ }
359
+ }
360
+ const mostUsedCommands = Array.from(commandCounts.entries())
361
+ .map(([command, count]) => ({ command, count }))
362
+ .sort((a, b) => b.count - a.count)
363
+ .slice(0, 10);
364
+ return {
365
+ activeSessions,
366
+ totalCommands,
367
+ averageSessionDuration,
368
+ mostUsedCommands,
369
+ workspaceCount: this.workspaces.size,
370
+ };
371
+ }
372
+ // Private methods
373
+ async initialize() {
374
+ // Ensure directories exist
375
+ await fs_extra_1.default.ensureDir(this.config.persistencePath);
376
+ await fs_extra_1.default.ensureDir(path_1.default.join(this.config.persistencePath, 'users'));
377
+ await fs_extra_1.default.ensureDir(path_1.default.join(this.config.persistencePath, 'workspaces'));
378
+ // Load existing workspaces
379
+ await this.loadAllWorkspaces();
380
+ // Start background tasks
381
+ this.startBackgroundTasks();
382
+ logger_1.logger.debug('Session manager initialized');
383
+ }
384
+ startBackgroundTasks() {
385
+ // Periodic backup
386
+ this.backupTimer = setInterval(async () => {
387
+ try {
388
+ await this.backupActiveSessions();
389
+ }
390
+ catch (error) {
391
+ logger_1.logger.error('Session backup failed:', error);
392
+ }
393
+ }, this.config.backupInterval * 60 * 1000);
394
+ // Periodic cleanup
395
+ this.cleanupTimer = setInterval(async () => {
396
+ try {
397
+ await this.cleanupSessions();
398
+ }
399
+ catch (error) {
400
+ logger_1.logger.error('Session cleanup failed:', error);
401
+ }
402
+ }, 30 * 60 * 1000); // Every 30 minutes
403
+ }
404
+ async detectProjectContext(workspacePath) {
405
+ if (!this.config.autoDetectProjects) {
406
+ return undefined;
407
+ }
408
+ try {
409
+ const context = {
410
+ rootPath: workspacePath,
411
+ projectType: 'unknown',
412
+ packageManager: 'unknown',
413
+ dependencies: [],
414
+ devDependencies: [],
415
+ scripts: {},
416
+ };
417
+ // Detect project type and package manager
418
+ const packageJsonPath = path_1.default.join(workspacePath, 'package.json');
419
+ if (await fs_extra_1.default.pathExists(packageJsonPath)) {
420
+ const packageJson = await fs_extra_1.default.readJson(packageJsonPath);
421
+ context.dependencies = Object.keys(packageJson.dependencies || {});
422
+ context.devDependencies = Object.keys(packageJson.devDependencies || {});
423
+ context.scripts = packageJson.scripts || {};
424
+ // Detect project type from dependencies
425
+ if (context.dependencies.includes('react')) {
426
+ context.projectType = 'react';
427
+ }
428
+ else if (context.dependencies.includes('vue')) {
429
+ context.projectType = 'vue';
430
+ }
431
+ else if (context.dependencies.includes('@angular/core')) {
432
+ context.projectType = 'angular';
433
+ }
434
+ else {
435
+ context.projectType = 'nodejs';
436
+ }
437
+ // Detect package manager
438
+ if (await fs_extra_1.default.pathExists(path_1.default.join(workspacePath, 'pnpm-lock.yaml'))) {
439
+ context.packageManager = 'pnpm';
440
+ }
441
+ else if (await fs_extra_1.default.pathExists(path_1.default.join(workspacePath, 'yarn.lock'))) {
442
+ context.packageManager = 'yarn';
443
+ }
444
+ else if (await fs_extra_1.default.pathExists(path_1.default.join(workspacePath, 'package-lock.json'))) {
445
+ context.packageManager = 'npm';
446
+ }
447
+ }
448
+ // Detect other project types
449
+ if (await fs_extra_1.default.pathExists(path_1.default.join(workspacePath, 'requirements.txt'))) {
450
+ context.projectType = 'python';
451
+ context.packageManager = 'pip';
452
+ }
453
+ else if (await fs_extra_1.default.pathExists(path_1.default.join(workspacePath, 'pom.xml'))) {
454
+ context.projectType = 'java';
455
+ context.packageManager = 'maven';
456
+ }
457
+ else if (await fs_extra_1.default.pathExists(path_1.default.join(workspacePath, 'build.gradle'))) {
458
+ context.projectType = 'java';
459
+ context.packageManager = 'gradle';
460
+ }
461
+ // Git information
462
+ const gitPath = path_1.default.join(workspacePath, '.git');
463
+ if (await fs_extra_1.default.pathExists(gitPath)) {
464
+ context.gitRepository = await this.getGitInfo(workspacePath);
465
+ }
466
+ return context;
467
+ }
468
+ catch (error) {
469
+ logger_1.logger.debug('Failed to detect project context:', error);
470
+ return undefined;
471
+ }
472
+ }
473
+ async getGitInfo(workspacePath) {
474
+ // Simplified git info extraction
475
+ return {
476
+ remote: 'origin',
477
+ branch: 'main',
478
+ status: 'clean',
479
+ hasUncommittedChanges: false,
480
+ };
481
+ }
482
+ getDefaultPreferences() {
483
+ return {
484
+ defaultModel: 'claude-3-5-sonnet-20241022',
485
+ preferredOutputFormat: 'table',
486
+ confirmDestructiveCommands: true,
487
+ enableStreamingResponses: true,
488
+ maxHistoryLength: 100,
489
+ autoSave: true,
490
+ theme: 'auto',
491
+ verbosity: 'normal',
492
+ aliases: {},
493
+ favorites: [],
494
+ workspacePreferences: {},
495
+ };
496
+ }
497
+ async loadUserPreferences(userId) {
498
+ const prefsPath = path_1.default.join(this.config.persistencePath, 'users', `${userId}.json`);
499
+ if (await fs_extra_1.default.pathExists(prefsPath)) {
500
+ try {
501
+ const saved = await fs_extra_1.default.readJson(prefsPath);
502
+ return { ...this.getDefaultPreferences(), ...saved };
503
+ }
504
+ catch (error) {
505
+ logger_1.logger.warn(`Failed to load preferences for ${userId}:`, error);
506
+ }
507
+ }
508
+ return this.getDefaultPreferences();
509
+ }
510
+ async saveUserPreferences(userId, preferences) {
511
+ const prefsPath = path_1.default.join(this.config.persistencePath, 'users', `${userId}.json`);
512
+ await fs_extra_1.default.ensureDir(path_1.default.dirname(prefsPath));
513
+ await fs_extra_1.default.writeJson(prefsPath, preferences, { spaces: 2 });
514
+ }
515
+ async persistSession(session) {
516
+ const sessionPath = path_1.default.join(this.config.persistencePath, `${session.id}.json`);
517
+ const serialized = this.serializeSession(session);
518
+ await fs_extra_1.default.writeJson(sessionPath, serialized, { spaces: 2 });
519
+ }
520
+ async loadSession(sessionId) {
521
+ const sessionPath = path_1.default.join(this.config.persistencePath, `${sessionId}.json`);
522
+ if (await fs_extra_1.default.pathExists(sessionPath)) {
523
+ try {
524
+ const data = await fs_extra_1.default.readJson(sessionPath);
525
+ return this.deserializeSession(data);
526
+ }
527
+ catch (error) {
528
+ logger_1.logger.warn(`Failed to load session ${sessionId}:`, error);
529
+ }
530
+ }
531
+ return null;
532
+ }
533
+ serializeSession(session) {
534
+ return {
535
+ ...session,
536
+ created: session.created.toISOString(),
537
+ lastAccessed: session.lastAccessed.toISOString(),
538
+ recentCommands: session.recentCommands.map(cmd => ({
539
+ ...cmd,
540
+ timestamp: cmd.timestamp.toISOString(),
541
+ })),
542
+ contextStack: session.contextStack.map(ctx => ({
543
+ ...ctx,
544
+ timestamp: ctx.timestamp.toISOString(),
545
+ })),
546
+ projectContext: session.projectContext
547
+ ? {
548
+ ...session.projectContext,
549
+ lastAnalysis: session.projectContext.lastAnalysis
550
+ ? {
551
+ ...session.projectContext.lastAnalysis,
552
+ timestamp: session.projectContext.lastAnalysis.timestamp.toISOString(),
553
+ }
554
+ : undefined,
555
+ }
556
+ : undefined,
557
+ };
558
+ }
559
+ deserializeSession(data) {
560
+ return {
561
+ ...data,
562
+ created: new Date(data.created),
563
+ lastAccessed: new Date(data.lastAccessed),
564
+ recentCommands: data.recentCommands.map((cmd) => ({
565
+ ...cmd,
566
+ timestamp: new Date(cmd.timestamp),
567
+ })),
568
+ contextStack: data.contextStack.map((ctx) => ({
569
+ ...ctx,
570
+ timestamp: new Date(ctx.timestamp),
571
+ })),
572
+ projectContext: data.projectContext
573
+ ? {
574
+ ...data.projectContext,
575
+ lastAnalysis: data.projectContext.lastAnalysis
576
+ ? {
577
+ ...data.projectContext.lastAnalysis,
578
+ timestamp: new Date(data.projectContext.lastAnalysis.timestamp),
579
+ }
580
+ : undefined,
581
+ }
582
+ : undefined,
583
+ };
584
+ }
585
+ async loadWorkspace(workspacePath) {
586
+ const workspacesDir = path_1.default.join(this.config.persistencePath, 'workspaces');
587
+ const workspaceFile = path_1.default.join(workspacesDir, `${Buffer.from(workspacePath).toString('base64')}.json`);
588
+ if (await fs_extra_1.default.pathExists(workspaceFile)) {
589
+ try {
590
+ const data = await fs_extra_1.default.readJson(workspaceFile);
591
+ data.lastAccessed = new Date(data.lastAccessed);
592
+ return data;
593
+ }
594
+ catch (error) {
595
+ logger_1.logger.warn(`Failed to load workspace ${workspacePath}:`, error);
596
+ }
597
+ }
598
+ return null;
599
+ }
600
+ async saveWorkspace(workspace) {
601
+ const workspacesDir = path_1.default.join(this.config.persistencePath, 'workspaces');
602
+ const workspaceFile = path_1.default.join(workspacesDir, `${Buffer.from(workspace.path).toString('base64')}.json`);
603
+ await fs_extra_1.default.ensureDir(workspacesDir);
604
+ await fs_extra_1.default.writeJson(workspaceFile, {
605
+ ...workspace,
606
+ lastAccessed: workspace.lastAccessed.toISOString(),
607
+ }, { spaces: 2 });
608
+ }
609
+ async loadAllWorkspaces() {
610
+ const workspacesDir = path_1.default.join(this.config.persistencePath, 'workspaces');
611
+ if (await fs_extra_1.default.pathExists(workspacesDir)) {
612
+ const files = await fs_extra_1.default.readdir(workspacesDir);
613
+ for (const file of files) {
614
+ if (file.endsWith('.json')) {
615
+ try {
616
+ const data = await fs_extra_1.default.readJson(path_1.default.join(workspacesDir, file));
617
+ data.lastAccessed = new Date(data.lastAccessed);
618
+ this.workspaces.set(data.path, data);
619
+ }
620
+ catch (error) {
621
+ logger_1.logger.debug(`Failed to load workspace file ${file}:`, error);
622
+ }
623
+ }
624
+ }
625
+ }
626
+ }
627
+ async backupActiveSessions() {
628
+ for (const session of this.activeSessions.values()) {
629
+ await this.persistSession(session);
630
+ }
631
+ logger_1.logger.debug(`Backed up ${this.activeSessions.size} active sessions`);
632
+ }
633
+ async analyzeCommandPatterns(session) {
634
+ // Simple pattern analysis for learning user behavior
635
+ const recentCommands = session.recentCommands.slice(-10);
636
+ if (recentCommands.length >= 3) {
637
+ // Look for command sequences
638
+ const sequences = [];
639
+ for (let i = 0; i < recentCommands.length - 1; i++) {
640
+ const current = recentCommands[i];
641
+ const next = recentCommands[i + 1];
642
+ if (current?.command && next?.command) {
643
+ sequences.push(`${current.command} -> ${next.command}`);
644
+ }
645
+ }
646
+ // Store patterns in temporary data for future suggestions
647
+ if (!session.temporaryData['commandPatterns']) {
648
+ session.temporaryData['commandPatterns'] = [];
649
+ }
650
+ session.temporaryData['commandPatterns'].push(...sequences);
651
+ // Keep only recent patterns
652
+ session.temporaryData['commandPatterns'] =
653
+ session.temporaryData['commandPatterns'].slice(-20);
654
+ }
655
+ }
656
+ sessionToCsv(session) {
657
+ const headers = ['Timestamp', 'Command', 'Success', 'Duration'];
658
+ const rows = [headers];
659
+ session.recentCommands.forEach(cmd => {
660
+ rows.push([
661
+ cmd.timestamp.toISOString(),
662
+ `"${cmd.command.replace(/"/g, '""')}"`,
663
+ cmd.success.toString(),
664
+ cmd.duration.toString(),
665
+ ]);
666
+ });
667
+ return rows.map(row => row.join(',')).join('\n');
668
+ }
669
+ /**
670
+ * Cleanup resources
671
+ */
672
+ destroy() {
673
+ if (this.backupTimer) {
674
+ clearInterval(this.backupTimer);
675
+ }
676
+ if (this.cleanupTimer) {
677
+ clearInterval(this.cleanupTimer);
678
+ }
679
+ this.activeSessions.clear();
680
+ this.workspaces.clear();
681
+ this.removeAllListeners();
682
+ }
683
+ }
684
+ exports.SessionManager = SessionManager;
685
+ exports.default = SessionManager;
686
+ //# sourceMappingURL=session-manager.js.map