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,447 @@
1
+ /**
2
+ * Unit tests for Context Manager Error Handling
3
+ *
4
+ * These tests verify:
5
+ * - Connection error handling
6
+ * - Reconnection logic with exponential backoff
7
+ * - Timeout handling for commands and state queries
8
+ * - Latency warnings
9
+ */
10
+ import { ContextManager } from '../context-manager.js';
11
+ import { SubshellConnectionError } from '../types.js';
12
+ /**
13
+ * Mock handler that can simulate connection failures
14
+ */
15
+ class FailingMockHandler {
16
+ type = 'ssh';
17
+ detectionPatterns = [/^ssh\s+/];
18
+ shouldFail = false;
19
+ failCount = 0;
20
+ maxFailures = 0;
21
+ connected = false;
22
+ detect(command) {
23
+ return this.detectionPatterns.some(pattern => pattern.test(command));
24
+ }
25
+ setShouldFail(shouldFail, maxFailures = 0) {
26
+ this.shouldFail = shouldFail;
27
+ this.maxFailures = maxFailures;
28
+ this.failCount = 0;
29
+ }
30
+ async connect(command, cwd) {
31
+ if (this.shouldFail) {
32
+ if (this.maxFailures === 0 || this.failCount < this.maxFailures) {
33
+ this.failCount++;
34
+ throw new SubshellConnectionError('ssh', 'Connection refused', this.maxFailures > 0 // recoverable if maxFailures is set
35
+ );
36
+ }
37
+ }
38
+ this.connected = true;
39
+ return {
40
+ type: 'ssh',
41
+ handler: this,
42
+ metadata: {
43
+ hostname: 'example.com',
44
+ username: 'testuser',
45
+ workingDirectory: cwd,
46
+ shell: 'bash',
47
+ os: 'linux',
48
+ },
49
+ connectionState: 'connected',
50
+ sessionId: 'test-session-id',
51
+ };
52
+ }
53
+ async disconnect() {
54
+ this.connected = false;
55
+ }
56
+ async executeCommand(command) {
57
+ if (!this.connected) {
58
+ throw new Error('Not connected');
59
+ }
60
+ return {
61
+ stdout: 'mock output',
62
+ stderr: '',
63
+ exitCode: 0,
64
+ };
65
+ }
66
+ async readFile(path) {
67
+ return 'mock file content';
68
+ }
69
+ async writeFile(path, content) {
70
+ // Mock implementation
71
+ }
72
+ async listDirectory(path) {
73
+ return [{ name: 'file1.txt', type: 'file' }];
74
+ }
75
+ async searchFiles(pattern, directory) {
76
+ return [{ file: 'test.txt', line: 1, content: 'test content' }];
77
+ }
78
+ async getCurrentWorkingDirectory() {
79
+ return '/home/user';
80
+ }
81
+ async getShellType() {
82
+ return 'bash';
83
+ }
84
+ async getOSType() {
85
+ return 'linux';
86
+ }
87
+ getBreadcrumbs() {
88
+ return [
89
+ { label: 'ssh', color: 'cyan' },
90
+ { label: 'testuser@example.com', color: 'cyan' },
91
+ ];
92
+ }
93
+ }
94
+ /**
95
+ * Mock handler that simulates slow operations
96
+ */
97
+ class SlowMockHandler {
98
+ type = 'ssh';
99
+ detectionPatterns = [/^ssh\s+/];
100
+ commandDelay = 0;
101
+ connected = false;
102
+ detect(command) {
103
+ return this.detectionPatterns.some(pattern => pattern.test(command));
104
+ }
105
+ setCommandDelay(ms) {
106
+ this.commandDelay = ms;
107
+ }
108
+ async connect(command, cwd) {
109
+ this.connected = true;
110
+ return {
111
+ type: 'ssh',
112
+ handler: this,
113
+ metadata: {
114
+ hostname: 'example.com',
115
+ username: 'testuser',
116
+ workingDirectory: cwd,
117
+ shell: 'bash',
118
+ os: 'linux',
119
+ },
120
+ connectionState: 'connected',
121
+ sessionId: 'test-session-id',
122
+ };
123
+ }
124
+ async disconnect() {
125
+ this.connected = false;
126
+ }
127
+ async executeCommand(command) {
128
+ if (!this.connected) {
129
+ throw new Error('Not connected');
130
+ }
131
+ // Simulate delay
132
+ await new Promise(resolve => setTimeout(resolve, this.commandDelay));
133
+ return {
134
+ stdout: 'mock output',
135
+ stderr: '',
136
+ exitCode: 0,
137
+ };
138
+ }
139
+ async readFile(path) {
140
+ await new Promise(resolve => setTimeout(resolve, this.commandDelay));
141
+ return 'mock file content';
142
+ }
143
+ async writeFile(path, content) {
144
+ await new Promise(resolve => setTimeout(resolve, this.commandDelay));
145
+ }
146
+ async listDirectory(path) {
147
+ await new Promise(resolve => setTimeout(resolve, this.commandDelay));
148
+ return [{ name: 'file1.txt', type: 'file' }];
149
+ }
150
+ async searchFiles(pattern, directory) {
151
+ await new Promise(resolve => setTimeout(resolve, this.commandDelay));
152
+ return [{ file: 'test.txt', line: 1, content: 'test content' }];
153
+ }
154
+ async getCurrentWorkingDirectory() {
155
+ return '/home/user';
156
+ }
157
+ async getShellType() {
158
+ return 'bash';
159
+ }
160
+ async getOSType() {
161
+ return 'linux';
162
+ }
163
+ getBreadcrumbs() {
164
+ return [
165
+ { label: 'ssh', color: 'cyan' },
166
+ { label: 'testuser@example.com', color: 'cyan' },
167
+ ];
168
+ }
169
+ }
170
+ /**
171
+ * Test: Connection failure handling
172
+ */
173
+ async function testConnectionFailure() {
174
+ console.log('Test: Connection failure handling');
175
+ const manager = new ContextManager('/home/local', 'linux');
176
+ const handler = new FailingMockHandler();
177
+ // Track notifications
178
+ const notifications = [];
179
+ manager.onUserNotification((message, type) => {
180
+ notifications.push({ message, type });
181
+ });
182
+ // Set handler to fail
183
+ handler.setShouldFail(true);
184
+ try {
185
+ await manager.connectToSubshell(handler, 'ssh user@host');
186
+ throw new Error('Expected connection to fail');
187
+ }
188
+ catch (error) {
189
+ if (!(error instanceof SubshellConnectionError)) {
190
+ throw new Error('Expected SubshellConnectionError');
191
+ }
192
+ }
193
+ // Verify we're still in local context
194
+ const context = manager.getCurrentContext();
195
+ if (context.type !== 'local') {
196
+ throw new Error('Expected to remain in local context after connection failure');
197
+ }
198
+ // Verify error notification was sent
199
+ const errorNotifications = notifications.filter(n => n.type === 'error');
200
+ if (errorNotifications.length === 0) {
201
+ throw new Error('Expected error notification');
202
+ }
203
+ console.log('✓ Connection failure is handled correctly');
204
+ }
205
+ /**
206
+ * Test: Reconnection logic with exponential backoff
207
+ */
208
+ async function testReconnectionLogic() {
209
+ console.log('\nTest: Reconnection logic with exponential backoff');
210
+ const manager = new ContextManager('/home/local', 'linux');
211
+ const handler = new FailingMockHandler();
212
+ // Track notifications
213
+ const notifications = [];
214
+ manager.onUserNotification((message, type) => {
215
+ notifications.push({ message, type });
216
+ });
217
+ // Set handler to fail 2 times, then succeed
218
+ handler.setShouldFail(true, 2);
219
+ const startTime = Date.now();
220
+ try {
221
+ await manager.connectToSubshell(handler, 'ssh user@host');
222
+ }
223
+ catch (error) {
224
+ // Connection should succeed after retries
225
+ throw new Error('Expected connection to succeed after retries');
226
+ }
227
+ const elapsed = Date.now() - startTime;
228
+ // Verify reconnection attempts were made
229
+ const reconnectNotifications = notifications.filter(n => n.message.includes('Reconnection attempt'));
230
+ if (reconnectNotifications.length === 0) {
231
+ throw new Error('Expected reconnection attempt notifications');
232
+ }
233
+ // Verify exponential backoff (should take at least 1s + 2s = 3s)
234
+ if (elapsed < 3000) {
235
+ console.log(`⚠ Reconnection completed in ${elapsed}ms, expected at least 3000ms`);
236
+ }
237
+ // Verify we're in SSH context
238
+ const context = manager.getCurrentContext();
239
+ if (context.type !== 'ssh') {
240
+ throw new Error('Expected to be in SSH context after successful reconnection');
241
+ }
242
+ console.log('✓ Reconnection logic works with exponential backoff');
243
+ }
244
+ /**
245
+ * Test: Reconnection failure after max attempts
246
+ */
247
+ async function testReconnectionMaxAttempts() {
248
+ console.log('\nTest: Reconnection failure after max attempts');
249
+ const manager = new ContextManager('/home/local', 'linux');
250
+ const handler = new FailingMockHandler();
251
+ // Track notifications
252
+ const notifications = [];
253
+ manager.onUserNotification((message, type) => {
254
+ notifications.push({ message, type });
255
+ });
256
+ // Set handler to always fail (recoverable)
257
+ handler.setShouldFail(true, 999);
258
+ try {
259
+ await manager.connectToSubshell(handler, 'ssh user@host');
260
+ throw new Error('Expected connection to fail after max attempts');
261
+ }
262
+ catch (error) {
263
+ if (!(error instanceof SubshellConnectionError)) {
264
+ throw new Error('Expected SubshellConnectionError');
265
+ }
266
+ }
267
+ // Verify we're back in local context
268
+ const context = manager.getCurrentContext();
269
+ if (context.type !== 'local') {
270
+ throw new Error('Expected to be in local context after max reconnection attempts');
271
+ }
272
+ // Verify reconnection attempts were made (should be 3)
273
+ const reconnectNotifications = notifications.filter(n => n.message.includes('Reconnection attempt'));
274
+ if (reconnectNotifications.length !== 3) {
275
+ throw new Error(`Expected 3 reconnection attempts, got ${reconnectNotifications.length}`);
276
+ }
277
+ console.log('✓ Reconnection stops after max attempts');
278
+ }
279
+ /**
280
+ * Test: Command execution timeout
281
+ */
282
+ async function testCommandTimeout() {
283
+ console.log('\nTest: Command execution timeout');
284
+ const manager = new ContextManager('/home/local', 'linux');
285
+ const handler = new SlowMockHandler();
286
+ // Track notifications
287
+ const notifications = [];
288
+ manager.onUserNotification((message, type) => {
289
+ notifications.push({ message, type });
290
+ });
291
+ // Connect to handler
292
+ const context = await handler.connect('ssh user@host', '/home/local');
293
+ manager.pushContext(context);
294
+ // Set command to take longer than timeout
295
+ handler.setCommandDelay(2000);
296
+ try {
297
+ // Use a short timeout for testing (1 second)
298
+ await manager.executeCommand('sleep 10', 1000);
299
+ throw new Error('Expected command to timeout');
300
+ }
301
+ catch (error) {
302
+ if (!(error instanceof Error) || !error.message.includes('timed out')) {
303
+ throw new Error('Expected timeout error');
304
+ }
305
+ }
306
+ // Verify timeout notification was sent
307
+ const timeoutNotifications = notifications.filter(n => n.message.includes('timed out'));
308
+ if (timeoutNotifications.length === 0) {
309
+ throw new Error('Expected timeout notification');
310
+ }
311
+ console.log('✓ Command execution timeout works correctly');
312
+ }
313
+ /**
314
+ * Test: File operation timeout
315
+ */
316
+ async function testFileOperationTimeout() {
317
+ console.log('\nTest: File operation timeout');
318
+ const manager = new ContextManager('/home/local', 'linux');
319
+ const handler = new SlowMockHandler();
320
+ // Track notifications
321
+ const notifications = [];
322
+ manager.onUserNotification((message, type) => {
323
+ notifications.push({ message, type });
324
+ });
325
+ // Connect to handler
326
+ const context = await handler.connect('ssh user@host', '/home/local');
327
+ manager.pushContext(context);
328
+ // Set operations to take longer than timeout
329
+ handler.setCommandDelay(2000);
330
+ // Test readFile timeout
331
+ try {
332
+ await manager.readFile('/test/file.txt', 1000);
333
+ throw new Error('Expected readFile to timeout');
334
+ }
335
+ catch (error) {
336
+ if (!(error instanceof Error) || !error.message.includes('timed out')) {
337
+ throw new Error('Expected timeout error for readFile');
338
+ }
339
+ }
340
+ // Test writeFile timeout
341
+ try {
342
+ await manager.writeFile('/test/file.txt', 'content', 1000);
343
+ throw new Error('Expected writeFile to timeout');
344
+ }
345
+ catch (error) {
346
+ if (!(error instanceof Error) || !error.message.includes('timed out')) {
347
+ throw new Error('Expected timeout error for writeFile');
348
+ }
349
+ }
350
+ // Test listDirectory timeout
351
+ try {
352
+ await manager.listDirectory('/test', 1000);
353
+ throw new Error('Expected listDirectory to timeout');
354
+ }
355
+ catch (error) {
356
+ if (!(error instanceof Error) || !error.message.includes('timed out')) {
357
+ throw new Error('Expected timeout error for listDirectory');
358
+ }
359
+ }
360
+ console.log('✓ File operation timeouts work correctly');
361
+ }
362
+ /**
363
+ * Test: Latency warning
364
+ */
365
+ async function testLatencyWarning() {
366
+ console.log('\nTest: Latency warning');
367
+ const manager = new ContextManager('/home/local', 'linux');
368
+ const handler = new SlowMockHandler();
369
+ // Track notifications
370
+ const notifications = [];
371
+ manager.onUserNotification((message, type) => {
372
+ notifications.push({ message, type });
373
+ });
374
+ // Connect to handler
375
+ const context = await handler.connect('ssh user@host', '/home/local');
376
+ manager.pushContext(context);
377
+ // Set command to take longer than latency threshold (2 seconds)
378
+ handler.setCommandDelay(2500);
379
+ // Execute command (should complete but trigger warning)
380
+ await manager.executeCommand('ls', 10000); // 10 second timeout
381
+ // Verify latency warning was sent
382
+ const latencyWarnings = notifications.filter(n => n.type === 'warning' && n.message.includes('high latency'));
383
+ if (latencyWarnings.length === 0) {
384
+ throw new Error('Expected latency warning');
385
+ }
386
+ console.log('✓ Latency warning is displayed correctly');
387
+ }
388
+ /**
389
+ * Test: Connection loss handling
390
+ */
391
+ async function testConnectionLoss() {
392
+ console.log('\nTest: Connection loss handling');
393
+ const manager = new ContextManager('/home/local', 'linux');
394
+ const handler = new FailingMockHandler();
395
+ // Track notifications
396
+ const notifications = [];
397
+ manager.onUserNotification((message, type) => {
398
+ notifications.push({ message, type });
399
+ });
400
+ // Connect successfully
401
+ handler.setShouldFail(false);
402
+ const context = await handler.connect('ssh user@host', '/home/local');
403
+ manager.pushContext(context);
404
+ // Verify we're in SSH context
405
+ if (manager.getCurrentContext().type !== 'ssh') {
406
+ throw new Error('Expected to be in SSH context');
407
+ }
408
+ // Simulate connection loss
409
+ await manager.handleConnectionLoss(new Error('Connection reset by peer'));
410
+ // Verify we're back in local context
411
+ const currentContext = manager.getCurrentContext();
412
+ if (currentContext.type !== 'local') {
413
+ throw new Error('Expected to be in local context after connection loss');
414
+ }
415
+ // Verify error notification was sent
416
+ const errorNotifications = notifications.filter(n => n.type === 'error' && n.message.includes('Connection lost'));
417
+ if (errorNotifications.length === 0) {
418
+ throw new Error('Expected connection loss notification');
419
+ }
420
+ console.log('✓ Connection loss is handled correctly');
421
+ }
422
+ /**
423
+ * Run all error handling tests
424
+ */
425
+ async function runTests() {
426
+ console.log('=== Context Manager Error Handling Tests ===\n');
427
+ try {
428
+ await testConnectionFailure();
429
+ await testReconnectionLogic();
430
+ await testReconnectionMaxAttempts();
431
+ await testCommandTimeout();
432
+ await testFileOperationTimeout();
433
+ await testLatencyWarning();
434
+ await testConnectionLoss();
435
+ console.log('\n=== All error handling tests passed! ===');
436
+ }
437
+ catch (error) {
438
+ console.error('\n❌ Test failed:', error);
439
+ process.exit(1);
440
+ }
441
+ }
442
+ // Run tests if this file is executed directly
443
+ if (import.meta.url === `file://${process.argv[1]}`) {
444
+ runTests();
445
+ }
446
+ export { runTests };
447
+ //# sourceMappingURL=error-handling.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error-handling.test.js","sourceRoot":"","sources":["../../../src/context/__tests__/error-handling.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Command Detector - Detects subshell-initiating commands
3
+ */
4
+ import { SubshellHandler } from './subshell-handler';
5
+ /**
6
+ * Result of command detection
7
+ */
8
+ export interface DetectionResult {
9
+ /** The handler that can handle this command */
10
+ handler: SubshellHandler;
11
+ /** The original command */
12
+ command: string;
13
+ }
14
+ /**
15
+ * Command Detector intercepts commands to detect subshell entry
16
+ */
17
+ export declare class CommandDetector {
18
+ private handlers;
19
+ /**
20
+ * Register a subshell handler
21
+ */
22
+ registerHandler(handler: SubshellHandler): void;
23
+ /**
24
+ * Detect if a command should trigger a subshell
25
+ * @param command The command to check
26
+ * @returns Detection result if a handler matches, null otherwise
27
+ */
28
+ detect(command: string): DetectionResult | null;
29
+ /**
30
+ * Get all registered handlers
31
+ */
32
+ getHandlers(): SubshellHandler[];
33
+ /**
34
+ * Check if a specific handler is registered
35
+ */
36
+ hasHandler(type: string): boolean;
37
+ /**
38
+ * Get a handler by type
39
+ */
40
+ getHandlerByType(type: string): SubshellHandler | undefined;
41
+ /**
42
+ * Remove a handler by type
43
+ */
44
+ removeHandler(type: string): boolean;
45
+ /**
46
+ * Clear all registered handlers
47
+ */
48
+ clearHandlers(): void;
49
+ }
50
+ //# sourceMappingURL=command-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-detector.d.ts","sourceRoot":"","sources":["../../src/context/command-detector.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,+CAA+C;IAC/C,OAAO,EAAE,eAAe,CAAC;IAEzB,2BAA2B;IAC3B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAyB;IAEzC;;OAEG;IACH,eAAe,CAAC,OAAO,EAAE,eAAe,GAAG,IAAI;IAI/C;;;;OAIG;IACH,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI;IAoB/C;;OAEG;IACH,WAAW,IAAI,eAAe,EAAE;IAIhC;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAIjC;;OAEG;IACH,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAI3D;;OAEG;IACH,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IASpC;;OAEG;IACH,aAAa,IAAI,IAAI;CAGtB"}
@@ -0,0 +1,72 @@
1
+ /**
2
+ * Command Detector - Detects subshell-initiating commands
3
+ */
4
+ /**
5
+ * Command Detector intercepts commands to detect subshell entry
6
+ */
7
+ export class CommandDetector {
8
+ handlers = [];
9
+ /**
10
+ * Register a subshell handler
11
+ */
12
+ registerHandler(handler) {
13
+ this.handlers.push(handler);
14
+ }
15
+ /**
16
+ * Detect if a command should trigger a subshell
17
+ * @param command The command to check
18
+ * @returns Detection result if a handler matches, null otherwise
19
+ */
20
+ detect(command) {
21
+ const trimmedCommand = command.trim();
22
+ if (!trimmedCommand) {
23
+ return null;
24
+ }
25
+ // Check each registered handler
26
+ for (const handler of this.handlers) {
27
+ if (handler.detect(trimmedCommand)) {
28
+ return {
29
+ handler,
30
+ command: trimmedCommand,
31
+ };
32
+ }
33
+ }
34
+ return null;
35
+ }
36
+ /**
37
+ * Get all registered handlers
38
+ */
39
+ getHandlers() {
40
+ return [...this.handlers];
41
+ }
42
+ /**
43
+ * Check if a specific handler is registered
44
+ */
45
+ hasHandler(type) {
46
+ return this.handlers.some(h => h.type === type);
47
+ }
48
+ /**
49
+ * Get a handler by type
50
+ */
51
+ getHandlerByType(type) {
52
+ return this.handlers.find(h => h.type === type);
53
+ }
54
+ /**
55
+ * Remove a handler by type
56
+ */
57
+ removeHandler(type) {
58
+ const index = this.handlers.findIndex(h => h.type === type);
59
+ if (index !== -1) {
60
+ this.handlers.splice(index, 1);
61
+ return true;
62
+ }
63
+ return false;
64
+ }
65
+ /**
66
+ * Clear all registered handlers
67
+ */
68
+ clearHandlers() {
69
+ this.handlers = [];
70
+ }
71
+ }
72
+ //# sourceMappingURL=command-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"command-detector.js","sourceRoot":"","sources":["../../src/context/command-detector.ts"],"names":[],"mappings":"AAAA;;GAEG;AAeH;;GAEG;AACH,MAAM,OAAO,eAAe;IAClB,QAAQ,GAAsB,EAAE,CAAC;IAEzC;;OAEG;IACH,eAAe,CAAC,OAAwB;QACtC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC9B,CAAC;IAED;;;;OAIG;IACH,MAAM,CAAC,OAAe;QACpB,MAAM,cAAc,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;QAEtC,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,gCAAgC;QAChC,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YACpC,IAAI,OAAO,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC;gBACnC,OAAO;oBACL,OAAO;oBACP,OAAO,EAAE,cAAc;iBACxB,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,WAAW;QACT,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC5B,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,IAAY;QACrB,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAClD,CAAC;IAED;;OAEG;IACH,gBAAgB,CAAC,IAAY;QAC3B,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAClD,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,IAAY;QACxB,MAAM,KAAK,GAAG,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;QAC5D,IAAI,KAAK,KAAK,CAAC,CAAC,EAAE,CAAC;YACjB,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC;YAC/B,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;OAEG;IACH,aAAa;QACX,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;IACrB,CAAC;CACF"}