centaurus-cli 2.4.0 → 2.5.0

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 (153) hide show
  1. package/README.md +151 -1
  2. package/dist/cli-adapter.d.ts +41 -2
  3. package/dist/cli-adapter.d.ts.map +1 -1
  4. package/dist/cli-adapter.js +407 -79
  5. package/dist/cli-adapter.js.map +1 -1
  6. package/dist/config/types.d.ts +23 -0
  7. package/dist/config/types.d.ts.map +1 -1
  8. package/dist/config/types.js +20 -0
  9. package/dist/config/types.js.map +1 -1
  10. package/dist/context/__tests__/command-detector.test.d.ts +14 -0
  11. package/dist/context/__tests__/command-detector.test.d.ts.map +1 -0
  12. package/dist/context/__tests__/command-detector.test.js +318 -0
  13. package/dist/context/__tests__/command-detector.test.js.map +1 -0
  14. package/dist/context/__tests__/context-manager.test.d.ts +16 -0
  15. package/dist/context/__tests__/context-manager.test.d.ts.map +1 -0
  16. package/dist/context/__tests__/context-manager.test.js +375 -0
  17. package/dist/context/__tests__/context-manager.test.js.map +1 -0
  18. package/dist/context/__tests__/error-handling.test.d.ts +15 -0
  19. package/dist/context/__tests__/error-handling.test.d.ts.map +1 -0
  20. package/dist/context/__tests__/error-handling.test.js +447 -0
  21. package/dist/context/__tests__/error-handling.test.js.map +1 -0
  22. package/dist/context/command-detector.d.ts +50 -0
  23. package/dist/context/command-detector.d.ts.map +1 -0
  24. package/dist/context/command-detector.js +72 -0
  25. package/dist/context/command-detector.js.map +1 -0
  26. package/dist/context/context-manager.d.ts +144 -0
  27. package/dist/context/context-manager.d.ts.map +1 -0
  28. package/dist/context/context-manager.js +487 -0
  29. package/dist/context/context-manager.js.map +1 -0
  30. package/dist/context/handlers/__tests__/docker-handler.test.d.ts +13 -0
  31. package/dist/context/handlers/__tests__/docker-handler.test.d.ts.map +1 -0
  32. package/dist/context/handlers/__tests__/docker-handler.test.js +285 -0
  33. package/dist/context/handlers/__tests__/docker-handler.test.js.map +1 -0
  34. package/dist/context/handlers/__tests__/ssh-handler.test.d.ts +13 -0
  35. package/dist/context/handlers/__tests__/ssh-handler.test.d.ts.map +1 -0
  36. package/dist/context/handlers/__tests__/ssh-handler.test.js +251 -0
  37. package/dist/context/handlers/__tests__/ssh-handler.test.js.map +1 -0
  38. package/dist/context/handlers/__tests__/wsl-handler.test.d.ts +7 -0
  39. package/dist/context/handlers/__tests__/wsl-handler.test.d.ts.map +1 -0
  40. package/dist/context/handlers/__tests__/wsl-handler.test.js +331 -0
  41. package/dist/context/handlers/__tests__/wsl-handler.test.js.map +1 -0
  42. package/dist/context/handlers/docker-handler.d.ts +111 -0
  43. package/dist/context/handlers/docker-handler.d.ts.map +1 -0
  44. package/dist/context/handlers/docker-handler.js +439 -0
  45. package/dist/context/handlers/docker-handler.js.map +1 -0
  46. package/dist/context/handlers/ssh-handler.d.ts +120 -0
  47. package/dist/context/handlers/ssh-handler.d.ts.map +1 -0
  48. package/dist/context/handlers/ssh-handler.js +523 -0
  49. package/dist/context/handlers/ssh-handler.js.map +1 -0
  50. package/dist/context/handlers/wsl-handler.d.ts +128 -0
  51. package/dist/context/handlers/wsl-handler.d.ts.map +1 -0
  52. package/dist/context/handlers/wsl-handler.js +590 -0
  53. package/dist/context/handlers/wsl-handler.js.map +1 -0
  54. package/dist/context/index.d.ts +8 -0
  55. package/dist/context/index.d.ts.map +1 -0
  56. package/dist/context/index.js +7 -0
  57. package/dist/context/index.js.map +1 -0
  58. package/dist/context/subshell-handler.d.ts +130 -0
  59. package/dist/context/subshell-handler.d.ts.map +1 -0
  60. package/dist/context/subshell-handler.js +5 -0
  61. package/dist/context/subshell-handler.js.map +1 -0
  62. package/dist/context/types.d.ts +70 -0
  63. package/dist/context/types.d.ts.map +1 -0
  64. package/dist/context/types.js +34 -0
  65. package/dist/context/types.js.map +1 -0
  66. package/dist/index.js +6 -0
  67. package/dist/index.js.map +1 -1
  68. package/dist/services/__tests__/ai-context-injector.test.d.ts +15 -0
  69. package/dist/services/__tests__/ai-context-injector.test.d.ts.map +1 -0
  70. package/dist/services/__tests__/ai-context-injector.test.js +326 -0
  71. package/dist/services/__tests__/ai-context-injector.test.js.map +1 -0
  72. package/dist/services/ai-context-injector.d.ts +41 -0
  73. package/dist/services/ai-context-injector.d.ts.map +1 -0
  74. package/dist/services/ai-context-injector.js +97 -0
  75. package/dist/services/ai-context-injector.js.map +1 -0
  76. package/dist/services/ai-service-client.d.ts +4 -1
  77. package/dist/services/ai-service-client.d.ts.map +1 -1
  78. package/dist/services/ai-service-client.js +5 -1
  79. package/dist/services/ai-service-client.js.map +1 -1
  80. package/dist/src/context/types.js +27 -0
  81. package/dist/src/services/ai-context-injector.js +96 -0
  82. package/dist/src/services/ai-service-client.js +270 -0
  83. package/dist/src/services/api-client.js +349 -0
  84. package/dist/src/tools/types.js +1 -0
  85. package/dist/src/types/index.js +1 -0
  86. package/dist/test/context/types.js +27 -0
  87. package/dist/test/services/__tests__/ai-context-injector.test.js +325 -0
  88. package/dist/test/services/ai-context-injector.js +96 -0
  89. package/dist/test/services/ai-service-client.js +270 -0
  90. package/dist/test/services/api-client.js +349 -0
  91. package/dist/test/tools/types.js +1 -0
  92. package/dist/test/types/index.js +1 -0
  93. package/dist/test-ai-context-injector.js +97 -0
  94. package/dist/test-ssh-handler.d.ts +8 -0
  95. package/dist/test-ssh-handler.d.ts.map +1 -0
  96. package/dist/test-ssh-handler.js +198 -0
  97. package/dist/test-ssh-handler.js.map +1 -0
  98. package/dist/tools/command.d.ts.map +1 -1
  99. package/dist/tools/command.js +123 -46
  100. package/dist/tools/command.js.map +1 -1
  101. package/dist/tools/file-ops.d.ts.map +1 -1
  102. package/dist/tools/file-ops.js +115 -48
  103. package/dist/tools/file-ops.js.map +1 -1
  104. package/dist/tools/types.d.ts +1 -0
  105. package/dist/tools/types.d.ts.map +1 -1
  106. package/dist/types/index.d.ts +41 -0
  107. package/dist/types/index.d.ts.map +1 -1
  108. package/dist/ui/components/App.d.ts +3 -0
  109. package/dist/ui/components/App.d.ts.map +1 -1
  110. package/dist/ui/components/App.js +213 -46
  111. package/dist/ui/components/App.js.map +1 -1
  112. package/dist/ui/components/Breadcrumbs.d.ts +12 -0
  113. package/dist/ui/components/Breadcrumbs.d.ts.map +1 -0
  114. package/dist/ui/components/Breadcrumbs.js +62 -0
  115. package/dist/ui/components/Breadcrumbs.js.map +1 -0
  116. package/dist/ui/components/CodeBlock.js +1 -1
  117. package/dist/ui/components/CodeBlock.js.map +1 -1
  118. package/dist/ui/components/DiffViewer.js +1 -1
  119. package/dist/ui/components/DiffViewer.js.map +1 -1
  120. package/dist/ui/components/FileViewerScreen.d.ts +14 -0
  121. package/dist/ui/components/FileViewerScreen.d.ts.map +1 -0
  122. package/dist/ui/components/FileViewerScreen.js +74 -0
  123. package/dist/ui/components/FileViewerScreen.js.map +1 -0
  124. package/dist/ui/components/InputBox.d.ts +2 -0
  125. package/dist/ui/components/InputBox.d.ts.map +1 -1
  126. package/dist/ui/components/InputBox.js +85 -41
  127. package/dist/ui/components/InputBox.js.map +1 -1
  128. package/dist/ui/components/MessageDisplay.d.ts.map +1 -1
  129. package/dist/ui/components/MessageDisplay.js +3 -28
  130. package/dist/ui/components/MessageDisplay.js.map +1 -1
  131. package/dist/ui/components/PasswordPrompt.d.ts +9 -0
  132. package/dist/ui/components/PasswordPrompt.d.ts.map +1 -0
  133. package/dist/ui/components/PasswordPrompt.js +20 -0
  134. package/dist/ui/components/PasswordPrompt.js.map +1 -0
  135. package/dist/ui/components/StatusBar.d.ts +2 -0
  136. package/dist/ui/components/StatusBar.d.ts.map +1 -1
  137. package/dist/ui/components/StatusBar.js +36 -1
  138. package/dist/ui/components/StatusBar.js.map +1 -1
  139. package/dist/ui/components/ToolExecutionMessage.d.ts.map +1 -1
  140. package/dist/ui/components/ToolExecutionMessage.js +13 -24
  141. package/dist/ui/components/ToolExecutionMessage.js.map +1 -1
  142. package/dist/ui/components/VersionUpdatePrompt.d.ts +10 -0
  143. package/dist/ui/components/VersionUpdatePrompt.d.ts.map +1 -0
  144. package/dist/ui/components/VersionUpdatePrompt.js +41 -0
  145. package/dist/ui/components/VersionUpdatePrompt.js.map +1 -0
  146. package/dist/utils/shell.d.ts.map +1 -1
  147. package/dist/utils/shell.js +38 -10
  148. package/dist/utils/shell.js.map +1 -1
  149. package/dist/utils/version-checker.d.ts +14 -0
  150. package/dist/utils/version-checker.d.ts.map +1 -0
  151. package/dist/utils/version-checker.js +63 -0
  152. package/dist/utils/version-checker.js.map +1 -0
  153. package/package.json +71 -69
@@ -0,0 +1,349 @@
1
+ /**
2
+ * API Client Service for Centaurus CLI
3
+ *
4
+ * Handles all communication with the backend REST API including:
5
+ * - Authentication and session management
6
+ * - Conversation and message operations
7
+ * - User settings management
8
+ * - API key storage and retrieval
9
+ */
10
+ import axios from 'axios';
11
+ import { readFileSync, writeFileSync, mkdirSync, existsSync, unlinkSync } from 'fs';
12
+ import { join } from 'path';
13
+ import { homedir } from 'os';
14
+ /**
15
+ * API Client class for communicating with the backend service
16
+ */
17
+ class ApiClient {
18
+ constructor() {
19
+ this.client = null;
20
+ this.sessionToken = null;
21
+ // Set up session storage path: ~/.centaurus/session.json
22
+ this.configDir = join(homedir(), '.centaurus');
23
+ this.configPath = join(this.configDir, 'session.json');
24
+ // Load existing session if available
25
+ this.loadSession();
26
+ // Don't create axios client yet - wait until first use
27
+ // This allows environment variables to be loaded first
28
+ }
29
+ /**
30
+ * Get or create the axios client instance
31
+ * This is lazy-loaded to ensure environment variables are loaded first
32
+ */
33
+ getClient() {
34
+ if (!this.client) {
35
+ // Create axios instance with base configuration
36
+ // Use production URL by default, only use localhost in development mode
37
+ const baseURL = process.env.DEV_MODE === 'true'
38
+ ? 'http://localhost:3002/api'
39
+ : (process.env.BACKEND_URL || 'https://centaurus-backend-354715948975.asia-south1.run.app/api');
40
+ this.client = axios.create({
41
+ baseURL,
42
+ timeout: 30000,
43
+ headers: {
44
+ 'Content-Type': 'application/json',
45
+ },
46
+ });
47
+ // Request interceptor: Add Authorization header if session token exists
48
+ this.getClient().interceptors.request.use((config) => {
49
+ if (this.sessionToken) {
50
+ config.headers.Authorization = `Bearer ${this.sessionToken}`;
51
+ }
52
+ return config;
53
+ }, (error) => {
54
+ return Promise.reject(error);
55
+ });
56
+ // Response interceptor: Handle 401 errors (expired/invalid session)
57
+ this.getClient().interceptors.response.use((response) => response, async (error) => {
58
+ if (error.response?.status === 401) {
59
+ // Clear invalid session
60
+ this.clearSession();
61
+ // Create a more user-friendly error
62
+ const authError = new Error('Session expired. Please sign in again.');
63
+ authError.name = 'AuthenticationError';
64
+ throw authError;
65
+ }
66
+ // For other errors, extract message from API response if available
67
+ if (error.response?.data) {
68
+ const apiError = error.response.data;
69
+ if (apiError.error) {
70
+ const customError = new Error(apiError.error.message);
71
+ customError.name = apiError.error.code;
72
+ throw customError;
73
+ }
74
+ }
75
+ throw error;
76
+ });
77
+ }
78
+ return this.client;
79
+ }
80
+ /**
81
+ * Load session token from local config file
82
+ */
83
+ loadSession() {
84
+ try {
85
+ if (existsSync(this.configPath)) {
86
+ const data = readFileSync(this.configPath, 'utf-8');
87
+ const session = JSON.parse(data);
88
+ this.sessionToken = session.sessionToken || null;
89
+ }
90
+ }
91
+ catch (error) {
92
+ // If there's any error reading the session, just start fresh
93
+ this.sessionToken = null;
94
+ }
95
+ }
96
+ /**
97
+ * Save session token to local config file
98
+ */
99
+ saveSession(token, expiresAt) {
100
+ try {
101
+ // Ensure config directory exists
102
+ if (!existsSync(this.configDir)) {
103
+ mkdirSync(this.configDir, { recursive: true });
104
+ }
105
+ // Save session data
106
+ const sessionData = {
107
+ sessionToken: token,
108
+ expiresAt: expiresAt || null,
109
+ savedAt: new Date().toISOString(),
110
+ };
111
+ writeFileSync(this.configPath, JSON.stringify(sessionData, null, 2), 'utf-8');
112
+ this.sessionToken = token;
113
+ }
114
+ catch (error) {
115
+ console.error('Failed to save session:', error);
116
+ throw new Error('Failed to save session locally');
117
+ }
118
+ }
119
+ /**
120
+ * Clear session token from memory and local storage
121
+ */
122
+ clearSession() {
123
+ this.sessionToken = null;
124
+ try {
125
+ if (existsSync(this.configPath)) {
126
+ unlinkSync(this.configPath);
127
+ }
128
+ }
129
+ catch (error) {
130
+ // Ignore errors when clearing session
131
+ }
132
+ }
133
+ /**
134
+ * Check if user is authenticated
135
+ */
136
+ isAuthenticated() {
137
+ return this.sessionToken !== null;
138
+ }
139
+ // ==================== Authentication Methods ====================
140
+ /**
141
+ * Initialize Google OAuth flow
142
+ * @param redirectUri - The URI to redirect to after OAuth
143
+ * @returns OAuth URL and state parameter
144
+ */
145
+ async initGoogleAuth(redirectUri) {
146
+ const response = await this.getClient().post('/auth/google/init', { redirectUri });
147
+ return response.data.data;
148
+ }
149
+ /**
150
+ * Complete Google OAuth authentication
151
+ * @param code - Authorization code from Google
152
+ * @param state - State parameter for CSRF protection
153
+ * @returns Session token and user information
154
+ */
155
+ async authenticate(code, state) {
156
+ const response = await this.getClient().post('/auth/google/callback', { code, state });
157
+ const authData = response.data.data;
158
+ this.saveSession(authData.sessionToken, authData.expiresAt);
159
+ return authData;
160
+ }
161
+ /**
162
+ * Set session token directly (used when receiving token from web app)
163
+ * @param sessionToken - The session token to save
164
+ * @param user - User information
165
+ */
166
+ setSessionToken(sessionToken, user) {
167
+ // Calculate expiration (30 days from now)
168
+ const expiresAt = new Date();
169
+ expiresAt.setDate(expiresAt.getDate() + 30);
170
+ this.saveSession(sessionToken, expiresAt.toISOString());
171
+ }
172
+ /**
173
+ * Refresh the current session token
174
+ * @returns New session token and expiration
175
+ */
176
+ async refreshSession() {
177
+ const response = await this.getClient().post('/auth/refresh');
178
+ const refreshData = response.data.data;
179
+ this.saveSession(refreshData.sessionToken, refreshData.expiresAt);
180
+ return refreshData;
181
+ }
182
+ /**
183
+ * Logout and invalidate current session
184
+ */
185
+ async logout() {
186
+ try {
187
+ await this.getClient().post('/auth/logout');
188
+ }
189
+ finally {
190
+ // Always clear local session, even if API call fails
191
+ this.clearSession();
192
+ }
193
+ }
194
+ /**
195
+ * Get current authenticated user profile
196
+ * @returns User profile information
197
+ */
198
+ async getCurrentUser() {
199
+ const response = await this.getClient().get('/auth/me');
200
+ return response.data.data;
201
+ }
202
+ // ==================== Conversation Methods ====================
203
+ /**
204
+ * Create a new conversation
205
+ * @param data - Conversation creation parameters
206
+ * @returns Created conversation
207
+ */
208
+ async createConversation(data) {
209
+ const response = await this.getClient().post('/conversations', data);
210
+ return response.data.data;
211
+ }
212
+ /**
213
+ * Get all conversations for the authenticated user
214
+ * @param params - Pagination and filter parameters
215
+ * @returns List of conversations with pagination metadata
216
+ */
217
+ async getConversations(params) {
218
+ const queryParams = {
219
+ page: params?.page || 1,
220
+ limit: params?.limit || 20,
221
+ };
222
+ if (params?.includeArchived !== undefined) {
223
+ queryParams.includeArchived = params.includeArchived;
224
+ }
225
+ if (params?.tags && params.tags.length > 0) {
226
+ queryParams.tags = params.tags.join(',');
227
+ }
228
+ const response = await this.getClient().get('/conversations', { params: queryParams });
229
+ return response.data;
230
+ }
231
+ /**
232
+ * Get a specific conversation by ID
233
+ * @param conversationId - The conversation ID
234
+ * @returns Conversation details
235
+ */
236
+ async getConversation(conversationId) {
237
+ const response = await this.getClient().get(`/conversations/${conversationId}`);
238
+ return response.data.data;
239
+ }
240
+ /**
241
+ * Update a conversation
242
+ * @param conversationId - The conversation ID
243
+ * @param data - Fields to update
244
+ * @returns Updated conversation
245
+ */
246
+ async updateConversation(conversationId, data) {
247
+ const response = await this.getClient().put(`/conversations/${conversationId}`, data);
248
+ return response.data.data;
249
+ }
250
+ /**
251
+ * Delete (archive) a conversation
252
+ * @param conversationId - The conversation ID
253
+ */
254
+ async deleteConversation(conversationId) {
255
+ await this.getClient().delete(`/conversations/${conversationId}`);
256
+ }
257
+ // ==================== Message Methods ====================
258
+ /**
259
+ * Add a message to a conversation
260
+ * @param conversationId - The conversation ID
261
+ * @param message - Message data
262
+ * @returns Created message
263
+ */
264
+ async addMessage(conversationId, message) {
265
+ const response = await this.getClient().post(`/conversations/${conversationId}/messages`, message);
266
+ return response.data.data;
267
+ }
268
+ /**
269
+ * Get all messages for a conversation
270
+ * @param conversationId - The conversation ID
271
+ * @param params - Pagination parameters
272
+ * @returns List of messages with pagination metadata
273
+ */
274
+ async getMessages(conversationId, params) {
275
+ const queryParams = {
276
+ page: params?.page || 1,
277
+ limit: params?.limit || 50,
278
+ };
279
+ const response = await this.getClient().get(`/conversations/${conversationId}/messages`, { params: queryParams });
280
+ return response.data;
281
+ }
282
+ // ==================== Settings Methods ====================
283
+ /**
284
+ * Get user settings
285
+ * @returns User settings object
286
+ */
287
+ async getSettings() {
288
+ const response = await this.getClient().get('/settings');
289
+ return response.data.data;
290
+ }
291
+ /**
292
+ * Update user settings
293
+ * @param settings - Settings to update (partial update supported)
294
+ * @returns Updated settings
295
+ */
296
+ async updateSettings(settings) {
297
+ const response = await this.getClient().put('/settings', settings);
298
+ return response.data.data;
299
+ }
300
+ // ==================== API Key Methods ====================
301
+ /**
302
+ * Store an encrypted API key
303
+ * @param data - API key data including provider, name, and key value
304
+ * @returns API key metadata (without the actual key)
305
+ */
306
+ async storeApiKey(data) {
307
+ const response = await this.getClient().post('/api-keys', data);
308
+ return response.data.data;
309
+ }
310
+ /**
311
+ * Get all API keys (metadata only, not actual keys)
312
+ * @returns List of API key metadata
313
+ */
314
+ async getApiKeys() {
315
+ const response = await this.getClient().get('/api-keys');
316
+ return response.data.data;
317
+ }
318
+ /**
319
+ * Decrypt and retrieve an API key for a specific provider
320
+ * @param provider - The provider name
321
+ * @returns Decrypted API key
322
+ */
323
+ async decryptApiKey(provider) {
324
+ const response = await this.getClient().get(`/api-keys/${provider}/decrypt`);
325
+ return response.data.data;
326
+ }
327
+ /**
328
+ * Delete an API key
329
+ * @param keyId - The API key ID
330
+ */
331
+ async deleteApiKey(keyId) {
332
+ await this.getClient().delete(`/api-keys/${keyId}`);
333
+ }
334
+ // ==================== Health Check ====================
335
+ /**
336
+ * Check backend service health
337
+ * @returns Health status information
338
+ */
339
+ async healthCheck() {
340
+ // Health endpoint is at root level, not under /api
341
+ // So we need to construct the full URL manually
342
+ const baseURL = process.env.BACKEND_API_URL || 'http://localhost:3000/api';
343
+ const healthURL = baseURL.replace('/api', '/health');
344
+ const response = await axios.get(healthURL);
345
+ return response.data.data;
346
+ }
347
+ }
348
+ // Export singleton instance
349
+ export const apiClient = new ApiClient();
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Simple test script for AI Context Injector
3
+ */
4
+ import { AIContextInjector } from './src/services/ai-context-injector.js';
5
+ console.log('Testing AI Context Injector...\n');
6
+ const injector = new AIContextInjector();
7
+ // Test 1: Local context (no injection)
8
+ console.log('Test 1: Local context (no injection)');
9
+ const localMessages = [
10
+ { role: 'user', content: 'Hello' },
11
+ { role: 'assistant', content: 'Hi!' },
12
+ ];
13
+ const localContext = {
14
+ type: 'local',
15
+ metadata: {
16
+ workingDirectory: '/home/user',
17
+ shell: 'bash',
18
+ os: 'linux',
19
+ },
20
+ connectionState: 'connected',
21
+ sessionId: 'local',
22
+ };
23
+ const localResult = injector.injectSubshellContext(localMessages, localContext);
24
+ console.log(` Original messages: ${localMessages.length}`);
25
+ console.log(` Result messages: ${localResult.length}`);
26
+ console.log(` ✓ No injection for local context\n`);
27
+ // Test 2: SSH context injection
28
+ console.log('Test 2: SSH context injection');
29
+ const sshMessages = [
30
+ { role: 'user', content: 'List files' },
31
+ ];
32
+ const sshContext = {
33
+ type: 'ssh',
34
+ metadata: {
35
+ hostname: 'example.com',
36
+ username: 'testuser',
37
+ workingDirectory: '/home/testuser',
38
+ shell: 'bash',
39
+ os: 'linux',
40
+ port: 22,
41
+ },
42
+ connectionState: 'connected',
43
+ sessionId: 'ssh-123',
44
+ };
45
+ const sshResult = injector.injectSubshellContext(sshMessages, sshContext);
46
+ console.log(` Original messages: ${sshMessages.length}`);
47
+ console.log(` Result messages: ${sshResult.length}`);
48
+ console.log(` Context message role: ${sshResult[0].role}`);
49
+ console.log(` Context includes SSH: ${sshResult[0].content.includes('SSH')}`);
50
+ console.log(` Context includes hostname: ${sshResult[0].content.includes('example.com')}`);
51
+ console.log(` Context includes username: ${sshResult[0].content.includes('testuser')}`);
52
+ console.log(` ✓ SSH context injected correctly\n`);
53
+ // Test 3: WSL context injection
54
+ console.log('Test 3: WSL context injection');
55
+ const wslMessages = [
56
+ { role: 'user', content: 'Check files' },
57
+ ];
58
+ const wslContext = {
59
+ type: 'wsl',
60
+ metadata: {
61
+ distroName: 'Ubuntu-20.04',
62
+ workingDirectory: '/home/user',
63
+ shell: 'bash',
64
+ os: 'linux',
65
+ },
66
+ connectionState: 'connected',
67
+ sessionId: 'wsl-456',
68
+ };
69
+ const wslResult = injector.injectSubshellContext(wslMessages, wslContext);
70
+ console.log(` Original messages: ${wslMessages.length}`);
71
+ console.log(` Result messages: ${wslResult.length}`);
72
+ console.log(` Context includes WSL: ${wslResult[0].content.includes('WSL')}`);
73
+ console.log(` Context includes distro: ${wslResult[0].content.includes('Ubuntu-20.04')}`);
74
+ console.log(` ✓ WSL context injected correctly\n`);
75
+ // Test 4: Docker context injection
76
+ console.log('Test 4: Docker context injection');
77
+ const dockerMessages = [
78
+ { role: 'user', content: 'Run command' },
79
+ ];
80
+ const dockerContext = {
81
+ type: 'docker',
82
+ metadata: {
83
+ containerId: 'abc123',
84
+ workingDirectory: '/app',
85
+ shell: 'sh',
86
+ os: 'linux',
87
+ },
88
+ connectionState: 'connected',
89
+ sessionId: 'docker-789',
90
+ };
91
+ const dockerResult = injector.injectSubshellContext(dockerMessages, dockerContext);
92
+ console.log(` Original messages: ${dockerMessages.length}`);
93
+ console.log(` Result messages: ${dockerResult.length}`);
94
+ console.log(` Context includes DOCKER: ${dockerResult[0].content.includes('DOCKER')}`);
95
+ console.log(` Context includes container: ${dockerResult[0].content.includes('abc123')}`);
96
+ console.log(` ✓ Docker context injected correctly\n`);
97
+ console.log('All tests passed! ✓');
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Manual test script for SSH Handler
3
+ *
4
+ * This script provides basic verification of the SSH Handler implementation.
5
+ * Run with: npx ts-node test-ssh-handler.ts
6
+ */
7
+ export {};
8
+ //# sourceMappingURL=test-ssh-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-ssh-handler.d.ts","sourceRoot":"","sources":["../src/test-ssh-handler.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
@@ -0,0 +1,198 @@
1
+ /**
2
+ * Manual test script for SSH Handler
3
+ *
4
+ * This script provides basic verification of the SSH Handler implementation.
5
+ * Run with: npx ts-node test-ssh-handler.ts
6
+ */
7
+ import { SSHHandler } from './context/handlers/ssh-handler.js';
8
+ async function runTests() {
9
+ console.log('🧪 SSH Handler Test Suite\n');
10
+ const handler = new SSHHandler();
11
+ let passedTests = 0;
12
+ let failedTests = 0;
13
+ // Test 1: Detection patterns
14
+ console.log('Test 1: Command detection');
15
+ try {
16
+ const test1 = handler.detect('ssh user@host');
17
+ const test2 = handler.detect('ssh -p 2222 user@host');
18
+ const test3 = !handler.detect('ls -la');
19
+ if (test1 && test2 && test3) {
20
+ console.log('✅ PASS: Command detection works correctly');
21
+ passedTests++;
22
+ }
23
+ else {
24
+ console.log('❌ FAIL: Command detection failed');
25
+ failedTests++;
26
+ }
27
+ }
28
+ catch (error) {
29
+ console.log('❌ FAIL: Command detection threw error:', error);
30
+ failedTests++;
31
+ }
32
+ // Test 2: SSH command parsing
33
+ console.log('\nTest 2: SSH command parsing');
34
+ try {
35
+ const config1 = handler.parseSSHCommand('ssh user@example.com');
36
+ const config2 = handler.parseSSHCommand('ssh -p 2222 user@example.com');
37
+ if (config1.host === 'example.com' &&
38
+ config1.username === 'user' &&
39
+ config1.port === 22 &&
40
+ config2.port === 2222) {
41
+ console.log('✅ PASS: SSH command parsing works correctly');
42
+ passedTests++;
43
+ }
44
+ else {
45
+ console.log('❌ FAIL: SSH command parsing failed');
46
+ console.log(' Config1:', config1);
47
+ console.log(' Config2:', config2);
48
+ failedTests++;
49
+ }
50
+ }
51
+ catch (error) {
52
+ console.log('❌ FAIL: SSH command parsing threw error:', error);
53
+ failedTests++;
54
+ }
55
+ // Test 3: Breadcrumbs
56
+ console.log('\nTest 3: Breadcrumb generation');
57
+ try {
58
+ const emptyBreadcrumbs = handler.getBreadcrumbs();
59
+ // Simulate config being set
60
+ handler.config = {
61
+ host: 'example.com',
62
+ username: 'testuser',
63
+ port: 22,
64
+ };
65
+ const breadcrumbs = handler.getBreadcrumbs();
66
+ if (emptyBreadcrumbs.length === 0 &&
67
+ breadcrumbs.length === 2 &&
68
+ breadcrumbs[0].label === 'ssh' &&
69
+ breadcrumbs[1].label === 'testuser@example.com') {
70
+ console.log('✅ PASS: Breadcrumb generation works correctly');
71
+ passedTests++;
72
+ }
73
+ else {
74
+ console.log('❌ FAIL: Breadcrumb generation failed');
75
+ console.log(' Empty breadcrumbs:', emptyBreadcrumbs);
76
+ console.log(' Breadcrumbs:', breadcrumbs);
77
+ failedTests++;
78
+ }
79
+ }
80
+ catch (error) {
81
+ console.log('❌ FAIL: Breadcrumb generation threw error:', error);
82
+ failedTests++;
83
+ }
84
+ // Test 4: Path resolution
85
+ console.log('\nTest 4: Path resolution');
86
+ try {
87
+ handler.currentWorkingDirectory = '/home/user';
88
+ const absolutePath = handler.resolveAbsolutePath('/etc/hosts');
89
+ const homePath = handler.resolveAbsolutePath('~/documents');
90
+ const relativePath = handler.resolveAbsolutePath('documents/file.txt');
91
+ if (absolutePath === '/etc/hosts' &&
92
+ homePath === '~/documents' &&
93
+ relativePath === '/home/user/documents/file.txt') {
94
+ console.log('✅ PASS: Path resolution works correctly');
95
+ passedTests++;
96
+ }
97
+ else {
98
+ console.log('❌ FAIL: Path resolution failed');
99
+ console.log(' Absolute:', absolutePath);
100
+ console.log(' Home:', homePath);
101
+ console.log(' Relative:', relativePath);
102
+ failedTests++;
103
+ }
104
+ }
105
+ catch (error) {
106
+ console.log('❌ FAIL: Path resolution threw error:', error);
107
+ failedTests++;
108
+ }
109
+ // Test 5: Shell integration scripts
110
+ console.log('\nTest 5: Shell integration scripts');
111
+ try {
112
+ handler.sessionId = 'test-session-id';
113
+ handler.shellType = 'bash';
114
+ const bashScript = handler.getShellIntegrationScript();
115
+ handler.shellType = 'zsh';
116
+ const zshScript = handler.getShellIntegrationScript();
117
+ handler.shellType = 'fish';
118
+ const fishScript = handler.getShellIntegrationScript();
119
+ if (bashScript.includes('CENTAURUS_SUBSHELL=1') &&
120
+ bashScript.includes('PROMPT_COMMAND') &&
121
+ zshScript.includes('precmd_functions') &&
122
+ fishScript.includes('fish_prompt')) {
123
+ console.log('✅ PASS: Shell integration scripts generated correctly');
124
+ passedTests++;
125
+ }
126
+ else {
127
+ console.log('❌ FAIL: Shell integration scripts failed');
128
+ failedTests++;
129
+ }
130
+ }
131
+ catch (error) {
132
+ console.log('❌ FAIL: Shell integration scripts threw error:', error);
133
+ failedTests++;
134
+ }
135
+ // Test 6: Error handling for invalid commands
136
+ console.log('\nTest 6: Error handling');
137
+ try {
138
+ let errorThrown = false;
139
+ try {
140
+ handler.parseSSHCommand('ssh');
141
+ }
142
+ catch (e) {
143
+ errorThrown = true;
144
+ }
145
+ if (errorThrown) {
146
+ console.log('✅ PASS: Error handling works correctly');
147
+ passedTests++;
148
+ }
149
+ else {
150
+ console.log('❌ FAIL: Error handling failed - no error thrown for invalid command');
151
+ failedTests++;
152
+ }
153
+ }
154
+ catch (error) {
155
+ console.log('❌ FAIL: Error handling test threw unexpected error:', error);
156
+ failedTests++;
157
+ }
158
+ // Test 7: Handler type and patterns
159
+ console.log('\nTest 7: Handler metadata');
160
+ try {
161
+ if (handler.type === 'ssh' &&
162
+ handler.detectionPatterns.length > 0 &&
163
+ handler.detectionPatterns[0] instanceof RegExp) {
164
+ console.log('✅ PASS: Handler metadata is correct');
165
+ passedTests++;
166
+ }
167
+ else {
168
+ console.log('❌ FAIL: Handler metadata is incorrect');
169
+ failedTests++;
170
+ }
171
+ }
172
+ catch (error) {
173
+ console.log('❌ FAIL: Handler metadata test threw error:', error);
174
+ failedTests++;
175
+ }
176
+ // Summary
177
+ console.log('\n' + '='.repeat(50));
178
+ console.log(`Test Results: ${passedTests} passed, ${failedTests} failed`);
179
+ console.log('='.repeat(50));
180
+ if (failedTests === 0) {
181
+ console.log('\n✅ All tests passed!');
182
+ console.log('\nNote: These are unit tests for the SSH Handler logic.');
183
+ console.log('Integration tests with an actual SSH server would require:');
184
+ console.log(' - A test SSH server running');
185
+ console.log(' - Environment variables: TEST_SSH_HOST, TEST_SSH_USER, TEST_SSH_PASSWORD');
186
+ console.log(' - Running the skipped integration tests in the test file');
187
+ }
188
+ else {
189
+ console.log('\n❌ Some tests failed. Please review the implementation.');
190
+ process.exit(1);
191
+ }
192
+ }
193
+ // Run tests
194
+ runTests().catch(error => {
195
+ console.error('Test suite failed with error:', error);
196
+ process.exit(1);
197
+ });
198
+ //# sourceMappingURL=test-ssh-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-ssh-handler.js","sourceRoot":"","sources":["../src/test-ssh-handler.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/tools/command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAKlC,eAAO,MAAM,kBAAkB,EAAE,IA8EhC,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,IA4E5B,CAAC"}
1
+ {"version":3,"file":"command.d.ts","sourceRoot":"","sources":["../../src/tools/command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAMlC,eAAO,MAAM,kBAAkB,EAAE,IA+IhC,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,IA+F5B,CAAC"}