@wundr.io/cli 1.0.10 → 1.0.12

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 (269) hide show
  1. package/bin/wundr.js +8 -4
  2. package/package.json +23 -23
  3. package/src/ai/ai-service.ts +16 -17
  4. package/src/ai/claude-client.ts +16 -16
  5. package/src/ai/conversation-manager.ts +29 -29
  6. package/src/cli.ts +4 -4
  7. package/src/commands/ai.ts +246 -78
  8. package/src/commands/alignment.ts +74 -74
  9. package/src/commands/analyze-optimized.ts +111 -78
  10. package/src/commands/analyze.ts +14 -14
  11. package/src/commands/batch.ts +179 -42
  12. package/src/commands/chat.ts +37 -30
  13. package/src/commands/claude-init.ts +41 -45
  14. package/src/commands/claude-setup.ts +204 -119
  15. package/src/commands/computer-setup.ts +85 -43
  16. package/src/commands/create-command.ts +4 -4
  17. package/src/commands/create.ts +27 -27
  18. package/src/commands/dashboard.ts +24 -24
  19. package/src/commands/govern.ts +25 -25
  20. package/src/commands/governance.ts +34 -34
  21. package/src/commands/guardian.ts +56 -56
  22. package/src/commands/init.ts +25 -22
  23. package/src/commands/orchestrator.ts +68 -41
  24. package/src/commands/performance-optimizer.ts +34 -35
  25. package/src/commands/plugins.ts +27 -27
  26. package/src/commands/project-update.ts +175 -72
  27. package/src/commands/rag.ts +185 -78
  28. package/src/commands/session.ts +35 -35
  29. package/src/commands/setup.ts +40 -344
  30. package/src/commands/test-init.ts +3 -3
  31. package/src/commands/test.ts +4 -4
  32. package/src/commands/watch.ts +28 -29
  33. package/src/commands/worktree.ts +49 -49
  34. package/src/context/context-manager.ts +10 -10
  35. package/src/context/session-manager.ts +41 -41
  36. package/src/framework/command-interface.ts +520 -0
  37. package/src/framework/command-registry.ts +942 -0
  38. package/src/framework/completion-exporter.ts +383 -0
  39. package/src/framework/debug-logger.ts +519 -0
  40. package/src/framework/error-handler.ts +867 -0
  41. package/src/framework/help-generator.ts +540 -0
  42. package/src/framework/index.ts +169 -0
  43. package/src/framework/interactive-repl.ts +703 -0
  44. package/src/framework/output-formatter.ts +834 -0
  45. package/src/framework/progress-manager.ts +539 -0
  46. package/src/index.ts +4 -4
  47. package/src/interactive/interactive-mode.ts +16 -16
  48. package/src/lib/conflict-resolution.ts +799 -9
  49. package/src/lib/merge-strategy.ts +529 -7
  50. package/src/lib/safety-mechanisms.ts +422 -18
  51. package/src/lib/state-detection.ts +1015 -13
  52. package/src/nlp/command-mapper.ts +29 -29
  53. package/src/nlp/command-parser.ts +17 -17
  54. package/src/nlp/intent-classifier.ts +7 -7
  55. package/src/nlp/intent-parser.ts +54 -52
  56. package/src/plugins/plugin-manager.ts +61 -39
  57. package/src/tests/computer-setup-integration.test.ts +46 -15
  58. package/src/types/modules.d.ts +424 -1
  59. package/src/utils/backup-rollback-manager.ts +11 -8
  60. package/src/utils/config-manager.ts +3 -3
  61. package/src/utils/error-handler.ts +2 -2
  62. package/src/utils/logger.ts +22 -22
  63. package/templates/batch/ci-cd.yaml +7 -7
  64. package/test-suites/api/health.spec.ts +20 -23
  65. package/test-suites/helpers/test-config.ts +14 -13
  66. package/test-suites/ui/accessibility.spec.ts +27 -22
  67. package/test-suites/ui/smoke.spec.ts +26 -21
  68. package/LICENSE +0 -21
  69. package/dist/ai/ai-service.d.ts +0 -152
  70. package/dist/ai/ai-service.d.ts.map +0 -1
  71. package/dist/ai/ai-service.js +0 -430
  72. package/dist/ai/ai-service.js.map +0 -1
  73. package/dist/ai/claude-client.d.ts +0 -130
  74. package/dist/ai/claude-client.d.ts.map +0 -1
  75. package/dist/ai/claude-client.js +0 -340
  76. package/dist/ai/claude-client.js.map +0 -1
  77. package/dist/ai/conversation-manager.d.ts +0 -164
  78. package/dist/ai/conversation-manager.d.ts.map +0 -1
  79. package/dist/ai/conversation-manager.js +0 -614
  80. package/dist/ai/conversation-manager.js.map +0 -1
  81. package/dist/ai/index.d.ts +0 -5
  82. package/dist/ai/index.d.ts.map +0 -1
  83. package/dist/ai/index.js +0 -8
  84. package/dist/ai/index.js.map +0 -1
  85. package/dist/cli.d.ts +0 -36
  86. package/dist/cli.d.ts.map +0 -1
  87. package/dist/cli.js +0 -192
  88. package/dist/cli.js.map +0 -1
  89. package/dist/commands/ai.d.ts +0 -89
  90. package/dist/commands/ai.d.ts.map +0 -1
  91. package/dist/commands/ai.js +0 -799
  92. package/dist/commands/ai.js.map +0 -1
  93. package/dist/commands/alignment.d.ts +0 -78
  94. package/dist/commands/alignment.d.ts.map +0 -1
  95. package/dist/commands/alignment.js +0 -817
  96. package/dist/commands/alignment.js.map +0 -1
  97. package/dist/commands/analyze-optimized.d.ts +0 -14
  98. package/dist/commands/analyze-optimized.d.ts.map +0 -1
  99. package/dist/commands/analyze-optimized.js +0 -600
  100. package/dist/commands/analyze-optimized.js.map +0 -1
  101. package/dist/commands/analyze.d.ts +0 -65
  102. package/dist/commands/analyze.d.ts.map +0 -1
  103. package/dist/commands/analyze.js +0 -435
  104. package/dist/commands/analyze.js.map +0 -1
  105. package/dist/commands/batch.d.ts +0 -71
  106. package/dist/commands/batch.d.ts.map +0 -1
  107. package/dist/commands/batch.js +0 -738
  108. package/dist/commands/batch.js.map +0 -1
  109. package/dist/commands/chat.d.ts +0 -71
  110. package/dist/commands/chat.d.ts.map +0 -1
  111. package/dist/commands/chat.js +0 -674
  112. package/dist/commands/chat.js.map +0 -1
  113. package/dist/commands/claude-init.d.ts +0 -28
  114. package/dist/commands/claude-init.d.ts.map +0 -1
  115. package/dist/commands/claude-init.js +0 -591
  116. package/dist/commands/claude-init.js.map +0 -1
  117. package/dist/commands/claude-setup.d.ts +0 -119
  118. package/dist/commands/claude-setup.d.ts.map +0 -1
  119. package/dist/commands/claude-setup.js +0 -1073
  120. package/dist/commands/claude-setup.js.map +0 -1
  121. package/dist/commands/computer-setup-commands.d.ts +0 -53
  122. package/dist/commands/computer-setup-commands.d.ts.map +0 -1
  123. package/dist/commands/computer-setup-commands.js +0 -705
  124. package/dist/commands/computer-setup-commands.js.map +0 -1
  125. package/dist/commands/computer-setup.d.ts +0 -7
  126. package/dist/commands/computer-setup.d.ts.map +0 -1
  127. package/dist/commands/computer-setup.js +0 -849
  128. package/dist/commands/computer-setup.js.map +0 -1
  129. package/dist/commands/create-command.d.ts +0 -7
  130. package/dist/commands/create-command.d.ts.map +0 -1
  131. package/dist/commands/create-command.js +0 -158
  132. package/dist/commands/create-command.js.map +0 -1
  133. package/dist/commands/create.d.ts +0 -74
  134. package/dist/commands/create.d.ts.map +0 -1
  135. package/dist/commands/create.js +0 -556
  136. package/dist/commands/create.js.map +0 -1
  137. package/dist/commands/dashboard.d.ts +0 -91
  138. package/dist/commands/dashboard.d.ts.map +0 -1
  139. package/dist/commands/dashboard.js +0 -538
  140. package/dist/commands/dashboard.js.map +0 -1
  141. package/dist/commands/govern.d.ts +0 -70
  142. package/dist/commands/govern.d.ts.map +0 -1
  143. package/dist/commands/govern.js +0 -481
  144. package/dist/commands/govern.js.map +0 -1
  145. package/dist/commands/governance.d.ts +0 -17
  146. package/dist/commands/governance.d.ts.map +0 -1
  147. package/dist/commands/governance.js +0 -703
  148. package/dist/commands/governance.js.map +0 -1
  149. package/dist/commands/guardian.d.ts +0 -20
  150. package/dist/commands/guardian.d.ts.map +0 -1
  151. package/dist/commands/guardian.js +0 -597
  152. package/dist/commands/guardian.js.map +0 -1
  153. package/dist/commands/init.d.ts +0 -59
  154. package/dist/commands/init.d.ts.map +0 -1
  155. package/dist/commands/init.js +0 -650
  156. package/dist/commands/init.js.map +0 -1
  157. package/dist/commands/orchestrator.d.ts +0 -7
  158. package/dist/commands/orchestrator.d.ts.map +0 -1
  159. package/dist/commands/orchestrator.js +0 -571
  160. package/dist/commands/orchestrator.js.map +0 -1
  161. package/dist/commands/performance-optimizer.d.ts +0 -30
  162. package/dist/commands/performance-optimizer.d.ts.map +0 -1
  163. package/dist/commands/performance-optimizer.js +0 -650
  164. package/dist/commands/performance-optimizer.js.map +0 -1
  165. package/dist/commands/plugins.d.ts +0 -87
  166. package/dist/commands/plugins.d.ts.map +0 -1
  167. package/dist/commands/plugins.js +0 -685
  168. package/dist/commands/plugins.js.map +0 -1
  169. package/dist/commands/rag.d.ts +0 -7
  170. package/dist/commands/rag.d.ts.map +0 -1
  171. package/dist/commands/rag.js +0 -748
  172. package/dist/commands/rag.js.map +0 -1
  173. package/dist/commands/session.d.ts +0 -41
  174. package/dist/commands/session.d.ts.map +0 -1
  175. package/dist/commands/session.js +0 -441
  176. package/dist/commands/session.js.map +0 -1
  177. package/dist/commands/setup.d.ts +0 -29
  178. package/dist/commands/setup.d.ts.map +0 -1
  179. package/dist/commands/setup.js +0 -397
  180. package/dist/commands/setup.js.map +0 -1
  181. package/dist/commands/test-init.d.ts +0 -9
  182. package/dist/commands/test-init.d.ts.map +0 -1
  183. package/dist/commands/test-init.js +0 -222
  184. package/dist/commands/test-init.js.map +0 -1
  185. package/dist/commands/test.d.ts +0 -25
  186. package/dist/commands/test.d.ts.map +0 -1
  187. package/dist/commands/test.js +0 -217
  188. package/dist/commands/test.js.map +0 -1
  189. package/dist/commands/vp.d.ts +0 -7
  190. package/dist/commands/vp.d.ts.map +0 -1
  191. package/dist/commands/vp.js +0 -571
  192. package/dist/commands/vp.js.map +0 -1
  193. package/dist/commands/watch.d.ts +0 -76
  194. package/dist/commands/watch.d.ts.map +0 -1
  195. package/dist/commands/watch.js +0 -613
  196. package/dist/commands/watch.js.map +0 -1
  197. package/dist/commands/worktree.d.ts +0 -63
  198. package/dist/commands/worktree.d.ts.map +0 -1
  199. package/dist/commands/worktree.js +0 -774
  200. package/dist/commands/worktree.js.map +0 -1
  201. package/dist/context/context-manager.d.ts +0 -155
  202. package/dist/context/context-manager.d.ts.map +0 -1
  203. package/dist/context/context-manager.js +0 -383
  204. package/dist/context/context-manager.js.map +0 -1
  205. package/dist/context/index.d.ts +0 -3
  206. package/dist/context/index.d.ts.map +0 -1
  207. package/dist/context/index.js +0 -6
  208. package/dist/context/index.js.map +0 -1
  209. package/dist/context/session-manager.d.ts +0 -207
  210. package/dist/context/session-manager.d.ts.map +0 -1
  211. package/dist/context/session-manager.js +0 -686
  212. package/dist/context/session-manager.js.map +0 -1
  213. package/dist/index.d.ts +0 -8
  214. package/dist/index.d.ts.map +0 -1
  215. package/dist/index.js +0 -51
  216. package/dist/index.js.map +0 -1
  217. package/dist/interactive/interactive-mode.d.ts +0 -76
  218. package/dist/interactive/interactive-mode.d.ts.map +0 -1
  219. package/dist/interactive/interactive-mode.js +0 -732
  220. package/dist/interactive/interactive-mode.js.map +0 -1
  221. package/dist/nlp/command-mapper.d.ts +0 -174
  222. package/dist/nlp/command-mapper.d.ts.map +0 -1
  223. package/dist/nlp/command-mapper.js +0 -624
  224. package/dist/nlp/command-mapper.js.map +0 -1
  225. package/dist/nlp/command-parser.d.ts +0 -106
  226. package/dist/nlp/command-parser.d.ts.map +0 -1
  227. package/dist/nlp/command-parser.js +0 -417
  228. package/dist/nlp/command-parser.js.map +0 -1
  229. package/dist/nlp/index.d.ts +0 -5
  230. package/dist/nlp/index.d.ts.map +0 -1
  231. package/dist/nlp/index.js +0 -8
  232. package/dist/nlp/index.js.map +0 -1
  233. package/dist/nlp/intent-classifier.d.ts +0 -59
  234. package/dist/nlp/intent-classifier.d.ts.map +0 -1
  235. package/dist/nlp/intent-classifier.js +0 -384
  236. package/dist/nlp/intent-classifier.js.map +0 -1
  237. package/dist/nlp/intent-parser.d.ts +0 -152
  238. package/dist/nlp/intent-parser.d.ts.map +0 -1
  239. package/dist/nlp/intent-parser.js +0 -744
  240. package/dist/nlp/intent-parser.js.map +0 -1
  241. package/dist/plugins/plugin-manager.d.ts +0 -120
  242. package/dist/plugins/plugin-manager.d.ts.map +0 -1
  243. package/dist/plugins/plugin-manager.js +0 -595
  244. package/dist/plugins/plugin-manager.js.map +0 -1
  245. package/dist/types/index.d.ts +0 -224
  246. package/dist/types/index.d.ts.map +0 -1
  247. package/dist/types/index.js +0 -3
  248. package/dist/types/index.js.map +0 -1
  249. package/dist/utils/backup-rollback-manager.d.ts +0 -72
  250. package/dist/utils/backup-rollback-manager.d.ts.map +0 -1
  251. package/dist/utils/backup-rollback-manager.js +0 -289
  252. package/dist/utils/backup-rollback-manager.js.map +0 -1
  253. package/dist/utils/claude-config-installer.d.ts +0 -98
  254. package/dist/utils/claude-config-installer.d.ts.map +0 -1
  255. package/dist/utils/claude-config-installer.js +0 -678
  256. package/dist/utils/claude-config-installer.js.map +0 -1
  257. package/dist/utils/config-manager.d.ts +0 -73
  258. package/dist/utils/config-manager.d.ts.map +0 -1
  259. package/dist/utils/config-manager.js +0 -339
  260. package/dist/utils/config-manager.js.map +0 -1
  261. package/dist/utils/error-handler.d.ts +0 -46
  262. package/dist/utils/error-handler.d.ts.map +0 -1
  263. package/dist/utils/error-handler.js +0 -169
  264. package/dist/utils/error-handler.js.map +0 -1
  265. package/dist/utils/logger.d.ts +0 -25
  266. package/dist/utils/logger.d.ts.map +0 -1
  267. package/dist/utils/logger.js +0 -105
  268. package/dist/utils/logger.js.map +0 -1
  269. package/src/commands/computer-setup-commands.ts +0 -872
@@ -1,686 +0,0 @@
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