centaurus-cli 2.5.2 → 2.5.3

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 (246) hide show
  1. package/AUTH_FLOW.md +138 -0
  2. package/CONFIG_GUIDE.md +249 -0
  3. package/dist/config/models.d.ts +1 -1
  4. package/dist/config/models.d.ts.map +1 -1
  5. package/dist/config/models.js +2 -0
  6. package/dist/config/models.js.map +1 -1
  7. package/dist/ui/components/App.d.ts.map +1 -1
  8. package/dist/ui/components/App.js +104 -62
  9. package/dist/ui/components/App.js.map +1 -1
  10. package/dist/ui/components/FontRecommendation.d.ts +1 -0
  11. package/dist/ui/components/FontRecommendation.d.ts.map +1 -0
  12. package/dist/ui/components/FontRecommendation.js +1 -0
  13. package/dist/ui/components/FontRecommendation.js.map +1 -0
  14. package/dist/ui/components/InputBox.d.ts.map +1 -1
  15. package/dist/ui/components/InputBox.js +3 -2
  16. package/dist/ui/components/InputBox.js.map +1 -1
  17. package/dist/ui/components/MarkdownRenderer.d.ts.map +1 -1
  18. package/dist/ui/components/MarkdownRenderer.js +34 -9
  19. package/dist/ui/components/MarkdownRenderer.js.map +1 -1
  20. package/dist/ui/components/MessageDisplay.js +2 -2
  21. package/dist/ui/components/StreamingMessageDisplay.d.ts.map +1 -1
  22. package/dist/ui/components/StreamingMessageDisplay.js +3 -3
  23. package/dist/ui/components/StreamingMessageDisplay.js.map +1 -1
  24. package/dist/ui/components/ThinkingDisplay.d.ts +13 -0
  25. package/dist/ui/components/ThinkingDisplay.d.ts.map +1 -0
  26. package/dist/ui/components/ThinkingDisplay.js +41 -0
  27. package/dist/ui/components/ThinkingDisplay.js.map +1 -0
  28. package/dist/utils/version-checker.d.ts.map +1 -1
  29. package/dist/utils/version-checker.js +3 -31
  30. package/dist/utils/version-checker.js.map +1 -1
  31. package/package.json +5 -5
  32. package/dist/ai/provider-factory.d.ts +0 -6
  33. package/dist/ai/provider-factory.d.ts.map +0 -1
  34. package/dist/ai/provider-factory.js +0 -27
  35. package/dist/ai/provider-factory.js.map +0 -1
  36. package/dist/ai/providers/base.d.ts +0 -25
  37. package/dist/ai/providers/base.d.ts.map +0 -1
  38. package/dist/ai/providers/base.js +0 -9
  39. package/dist/ai/providers/base.js.map +0 -1
  40. package/dist/ai/providers/gemini.d.ts +0 -34
  41. package/dist/ai/providers/gemini.d.ts.map +0 -1
  42. package/dist/ai/providers/gemini.js +0 -146
  43. package/dist/ai/providers/gemini.js.map +0 -1
  44. package/dist/commands/view-duplication-logs.d.ts +0 -5
  45. package/dist/commands/view-duplication-logs.d.ts.map +0 -1
  46. package/dist/commands/view-duplication-logs.js +0 -14
  47. package/dist/commands/view-duplication-logs.js.map +0 -1
  48. package/dist/context/__tests__/command-detector.test.d.ts +0 -14
  49. package/dist/context/__tests__/command-detector.test.d.ts.map +0 -1
  50. package/dist/context/__tests__/command-detector.test.js +0 -318
  51. package/dist/context/__tests__/command-detector.test.js.map +0 -1
  52. package/dist/context/__tests__/context-manager.test.d.ts +0 -16
  53. package/dist/context/__tests__/context-manager.test.d.ts.map +0 -1
  54. package/dist/context/__tests__/context-manager.test.js +0 -375
  55. package/dist/context/__tests__/context-manager.test.js.map +0 -1
  56. package/dist/context/__tests__/error-handling.test.d.ts +0 -15
  57. package/dist/context/__tests__/error-handling.test.d.ts.map +0 -1
  58. package/dist/context/__tests__/error-handling.test.js +0 -447
  59. package/dist/context/__tests__/error-handling.test.js.map +0 -1
  60. package/dist/context/handlers/__tests__/docker-handler.test.d.ts +0 -13
  61. package/dist/context/handlers/__tests__/docker-handler.test.d.ts.map +0 -1
  62. package/dist/context/handlers/__tests__/docker-handler.test.js +0 -285
  63. package/dist/context/handlers/__tests__/docker-handler.test.js.map +0 -1
  64. package/dist/context/handlers/__tests__/ssh-handler.test.d.ts +0 -13
  65. package/dist/context/handlers/__tests__/ssh-handler.test.d.ts.map +0 -1
  66. package/dist/context/handlers/__tests__/ssh-handler.test.js +0 -251
  67. package/dist/context/handlers/__tests__/ssh-handler.test.js.map +0 -1
  68. package/dist/context/handlers/__tests__/wsl-handler.test.d.ts +0 -7
  69. package/dist/context/handlers/__tests__/wsl-handler.test.d.ts.map +0 -1
  70. package/dist/context/handlers/__tests__/wsl-handler.test.js +0 -331
  71. package/dist/context/handlers/__tests__/wsl-handler.test.js.map +0 -1
  72. package/dist/index-custom.d.ts +0 -3
  73. package/dist/index-custom.d.ts.map +0 -1
  74. package/dist/index-custom.js +0 -65
  75. package/dist/index-custom.js.map +0 -1
  76. package/dist/prompts/system-prompt.d.ts +0 -47
  77. package/dist/prompts/system-prompt.d.ts.map +0 -1
  78. package/dist/prompts/system-prompt.js +0 -377
  79. package/dist/prompts/system-prompt.js.map +0 -1
  80. package/dist/providers/GoogleProvider.d.ts +0 -26
  81. package/dist/providers/GoogleProvider.d.ts.map +0 -1
  82. package/dist/providers/GoogleProvider.js +0 -313
  83. package/dist/providers/GoogleProvider.js.map +0 -1
  84. package/dist/providers/Provider.d.ts +0 -114
  85. package/dist/providers/Provider.d.ts.map +0 -1
  86. package/dist/providers/Provider.js +0 -44
  87. package/dist/providers/Provider.js.map +0 -1
  88. package/dist/services/__tests__/ai-context-injector.test.d.ts +0 -15
  89. package/dist/services/__tests__/ai-context-injector.test.d.ts.map +0 -1
  90. package/dist/services/__tests__/ai-context-injector.test.js +0 -326
  91. package/dist/services/__tests__/ai-context-injector.test.js.map +0 -1
  92. package/dist/src/context/types.js +0 -27
  93. package/dist/src/services/ai-context-injector.js +0 -96
  94. package/dist/src/services/ai-service-client.js +0 -270
  95. package/dist/src/services/api-client.js +0 -349
  96. package/dist/src/tools/types.js +0 -1
  97. package/dist/src/types/index.js +0 -1
  98. package/dist/test/context/types.js +0 -27
  99. package/dist/test/services/__tests__/ai-context-injector.test.js +0 -325
  100. package/dist/test/services/ai-context-injector.js +0 -96
  101. package/dist/test/services/ai-service-client.js +0 -270
  102. package/dist/test/services/api-client.js +0 -349
  103. package/dist/test/tools/types.js +0 -1
  104. package/dist/test/types/index.js +0 -1
  105. package/dist/test-ai-context-injector.js +0 -97
  106. package/dist/tests/automated-verification.d.ts +0 -27
  107. package/dist/tests/automated-verification.d.ts.map +0 -1
  108. package/dist/tests/automated-verification.js +0 -359
  109. package/dist/tests/automated-verification.js.map +0 -1
  110. package/dist/tests/integration-tests.d.ts +0 -50
  111. package/dist/tests/integration-tests.d.ts.map +0 -1
  112. package/dist/tests/integration-tests.js +0 -648
  113. package/dist/tests/integration-tests.js.map +0 -1
  114. package/dist/tools/file-ops-test.d.ts +0 -6
  115. package/dist/tools/file-ops-test.d.ts.map +0 -1
  116. package/dist/tools/file-ops-test.js +0 -197
  117. package/dist/tools/file-ops-test.js.map +0 -1
  118. package/dist/ui/DisplayHistory.d.ts +0 -53
  119. package/dist/ui/DisplayHistory.d.ts.map +0 -1
  120. package/dist/ui/DisplayHistory.js +0 -82
  121. package/dist/ui/DisplayHistory.js.map +0 -1
  122. package/dist/ui/clack-ui.d.ts +0 -83
  123. package/dist/ui/clack-ui.d.ts.map +0 -1
  124. package/dist/ui/clack-ui.js +0 -304
  125. package/dist/ui/clack-ui.js.map +0 -1
  126. package/dist/ui/components/DisplayItemRenderer.d.ts +0 -18
  127. package/dist/ui/components/DisplayItemRenderer.d.ts.map +0 -1
  128. package/dist/ui/components/DisplayItemRenderer.js +0 -53
  129. package/dist/ui/components/DisplayItemRenderer.js.map +0 -1
  130. package/dist/ui/components/DynamicMessage.d.ts +0 -13
  131. package/dist/ui/components/DynamicMessage.d.ts.map +0 -1
  132. package/dist/ui/components/DynamicMessage.js +0 -27
  133. package/dist/ui/components/DynamicMessage.js.map +0 -1
  134. package/dist/ui/components/FileViewerScreen.d.ts +0 -14
  135. package/dist/ui/components/FileViewerScreen.d.ts.map +0 -1
  136. package/dist/ui/components/FileViewerScreen.js +0 -74
  137. package/dist/ui/components/FileViewerScreen.js.map +0 -1
  138. package/dist/ui/components/ScrollableContent.d.ts +0 -7
  139. package/dist/ui/components/ScrollableContent.d.ts.map +0 -1
  140. package/dist/ui/components/ScrollableContent.js +0 -6
  141. package/dist/ui/components/ScrollableContent.js.map +0 -1
  142. package/dist/ui/components/ScrollableMessageList.d.ts +0 -10
  143. package/dist/ui/components/ScrollableMessageList.d.ts.map +0 -1
  144. package/dist/ui/components/ScrollableMessageList.js +0 -133
  145. package/dist/ui/components/ScrollableMessageList.js.map +0 -1
  146. package/dist/ui/components/ScrollableScreen.d.ts +0 -9
  147. package/dist/ui/components/ScrollableScreen.d.ts.map +0 -1
  148. package/dist/ui/components/ScrollableScreen.js +0 -22
  149. package/dist/ui/components/ScrollableScreen.js.map +0 -1
  150. package/dist/ui/components/StaticMessageHistory.d.ts +0 -14
  151. package/dist/ui/components/StaticMessageHistory.d.ts.map +0 -1
  152. package/dist/ui/components/StaticMessageHistory.js +0 -19
  153. package/dist/ui/components/StaticMessageHistory.js.map +0 -1
  154. package/dist/ui/components/code-block.d.ts +0 -10
  155. package/dist/ui/components/code-block.d.ts.map +0 -1
  156. package/dist/ui/components/code-block.js +0 -74
  157. package/dist/ui/components/code-block.js.map +0 -1
  158. package/dist/ui/components/confirm-prompt.d.ts +0 -12
  159. package/dist/ui/components/confirm-prompt.d.ts.map +0 -1
  160. package/dist/ui/components/confirm-prompt.js +0 -104
  161. package/dist/ui/components/confirm-prompt.js.map +0 -1
  162. package/dist/ui/components/diff-viewer.d.ts +0 -9
  163. package/dist/ui/components/diff-viewer.d.ts.map +0 -1
  164. package/dist/ui/components/diff-viewer.js +0 -57
  165. package/dist/ui/components/diff-viewer.js.map +0 -1
  166. package/dist/ui/components/input-box.d.ts +0 -18
  167. package/dist/ui/components/input-box.d.ts.map +0 -1
  168. package/dist/ui/components/input-box.js +0 -157
  169. package/dist/ui/components/input-box.js.map +0 -1
  170. package/dist/ui/components/keyboard-help.d.ts +0 -7
  171. package/dist/ui/components/keyboard-help.d.ts.map +0 -1
  172. package/dist/ui/components/keyboard-help.js +0 -43
  173. package/dist/ui/components/keyboard-help.js.map +0 -1
  174. package/dist/ui/components/loading-indicator.d.ts +0 -3
  175. package/dist/ui/components/loading-indicator.d.ts.map +0 -1
  176. package/dist/ui/components/loading-indicator.js +0 -42
  177. package/dist/ui/components/loading-indicator.js.map +0 -1
  178. package/dist/ui/components/message-display.d.ts +0 -7
  179. package/dist/ui/components/message-display.d.ts.map +0 -1
  180. package/dist/ui/components/message-display.js +0 -104
  181. package/dist/ui/components/message-display.js.map +0 -1
  182. package/dist/ui/components/misc.d.ts +0 -28
  183. package/dist/ui/components/misc.d.ts.map +0 -1
  184. package/dist/ui/components/misc.js +0 -128
  185. package/dist/ui/components/misc.js.map +0 -1
  186. package/dist/ui/components/select-prompt.d.ts +0 -13
  187. package/dist/ui/components/select-prompt.d.ts.map +0 -1
  188. package/dist/ui/components/select-prompt.js +0 -42
  189. package/dist/ui/components/select-prompt.js.map +0 -1
  190. package/dist/ui/components/status-bar.d.ts +0 -11
  191. package/dist/ui/components/status-bar.d.ts.map +0 -1
  192. package/dist/ui/components/status-bar.js +0 -47
  193. package/dist/ui/components/status-bar.js.map +0 -1
  194. package/dist/ui/components/tool-execution.d.ts +0 -3
  195. package/dist/ui/components/tool-execution.d.ts.map +0 -1
  196. package/dist/ui/components/tool-execution.js +0 -374
  197. package/dist/ui/components/tool-execution.js.map +0 -1
  198. package/dist/ui/components/tool-result.d.ts +0 -11
  199. package/dist/ui/components/tool-result.d.ts.map +0 -1
  200. package/dist/ui/components/tool-result.js +0 -58
  201. package/dist/ui/components/tool-result.js.map +0 -1
  202. package/dist/ui/components/welcome-banner.d.ts +0 -3
  203. package/dist/ui/components/welcome-banner.d.ts.map +0 -1
  204. package/dist/ui/components/welcome-banner.js +0 -46
  205. package/dist/ui/components/welcome-banner.js.map +0 -1
  206. package/dist/ui/hooks/useDisplayHistory.d.ts +0 -13
  207. package/dist/ui/hooks/useDisplayHistory.d.ts.map +0 -1
  208. package/dist/ui/hooks/useDisplayHistory.js +0 -45
  209. package/dist/ui/hooks/useDisplayHistory.js.map +0 -1
  210. package/dist/ui/render-engine.d.ts +0 -69
  211. package/dist/ui/render-engine.d.ts.map +0 -1
  212. package/dist/ui/render-engine.js +0 -197
  213. package/dist/ui/render-engine.js.map +0 -1
  214. package/dist/ui/terminal/TerminalRenderer.d.ts +0 -84
  215. package/dist/ui/terminal/TerminalRenderer.d.ts.map +0 -1
  216. package/dist/ui/terminal/TerminalRenderer.js +0 -154
  217. package/dist/ui/terminal/TerminalRenderer.js.map +0 -1
  218. package/dist/ui/terminal/TerminalUI.d.ts +0 -139
  219. package/dist/ui/terminal/TerminalUI.d.ts.map +0 -1
  220. package/dist/ui/terminal/TerminalUI.js +0 -430
  221. package/dist/ui/terminal/TerminalUI.js.map +0 -1
  222. package/dist/ui/terminal/VirtualChatBuffer.d.ts +0 -32
  223. package/dist/ui/terminal/VirtualChatBuffer.d.ts.map +0 -1
  224. package/dist/ui/terminal/VirtualChatBuffer.js +0 -37
  225. package/dist/ui/terminal/VirtualChatBuffer.js.map +0 -1
  226. package/dist/ui/terminal-kit-base.d.ts +0 -117
  227. package/dist/ui/terminal-kit-base.d.ts.map +0 -1
  228. package/dist/ui/terminal-kit-base.js +0 -188
  229. package/dist/ui/terminal-kit-base.js.map +0 -1
  230. package/dist/ui/utils/duplication-detector.d.ts +0 -32
  231. package/dist/ui/utils/duplication-detector.d.ts.map +0 -1
  232. package/dist/ui/utils/duplication-detector.js +0 -227
  233. package/dist/ui/utils/duplication-detector.js.map +0 -1
  234. package/dist/ui/utils/duplication-logger.d.ts +0 -21
  235. package/dist/ui/utils/duplication-logger.d.ts.map +0 -1
  236. package/dist/ui/utils/duplication-logger.js +0 -85
  237. package/dist/ui/utils/duplication-logger.js.map +0 -1
  238. package/dist/ui/utils/terminal-scanner.d.ts +0 -19
  239. package/dist/ui/utils/terminal-scanner.d.ts.map +0 -1
  240. package/dist/ui/utils/terminal-scanner.js +0 -217
  241. package/dist/ui/utils/terminal-scanner.js.map +0 -1
  242. package/dist/version.d.ts +0 -2
  243. package/dist/version.d.ts.map +0 -1
  244. package/dist/version.js +0 -3
  245. package/dist/version.js.map +0 -1
  246. package/scripts/generate-version.js +0 -25
@@ -1,648 +0,0 @@
1
- /**
2
- * Integration Tests for UI Rendering Refactor
3
- *
4
- * Comprehensive tests for:
5
- * - Complete conversation flows
6
- * - Approval and modal flows
7
- * - Error scenarios
8
- * - Performance testing
9
- */
10
- import { CentaurusCLI } from '../cli-adapter.js';
11
- import * as fs from 'fs';
12
- import * as path from 'path';
13
- class IntegrationTestRunner {
14
- results = [];
15
- cli;
16
- testDir;
17
- conversationHistory = [];
18
- streamingMessages = new Map();
19
- toolExecutions = new Map();
20
- duplicateDetector = new Map();
21
- constructor() {
22
- this.cli = new CentaurusCLI();
23
- this.testDir = path.join(process.cwd(), 'test-integration-temp');
24
- }
25
- async setup() {
26
- console.log('šŸ”§ Setting up integration test environment...\n');
27
- // Create test directory
28
- if (!fs.existsSync(this.testDir)) {
29
- fs.mkdirSync(this.testDir, { recursive: true });
30
- }
31
- // Initialize CLI
32
- await this.cli.initialize();
33
- // Setup callbacks to track messages and detect duplicates
34
- this.setupCallbacks();
35
- console.log('āœ… Integration test environment ready\n');
36
- }
37
- setupCallbacks() {
38
- // Track streaming messages
39
- this.cli.setOnStreamStart((messageId) => {
40
- this.streamingMessages.set(messageId, '');
41
- this.trackMessage('stream-start', messageId);
42
- });
43
- this.cli.setOnStreamChunk((messageId, chunk) => {
44
- const current = this.streamingMessages.get(messageId) || '';
45
- this.streamingMessages.set(messageId, current + chunk);
46
- });
47
- this.cli.setOnStreamComplete((messageId) => {
48
- const content = this.streamingMessages.get(messageId) || '';
49
- this.conversationHistory.push({
50
- role: 'assistant',
51
- content
52
- });
53
- this.streamingMessages.delete(messageId);
54
- this.trackMessage('stream-complete', messageId);
55
- });
56
- // Track tool executions
57
- this.cli.setOnToolExecutionUpdate((update) => {
58
- this.toolExecutions.set(update.id || update.toolName, update);
59
- this.trackMessage('tool-execution', update.id || update.toolName);
60
- if (update.status === 'completed' || update.status === 'error') {
61
- this.conversationHistory.push({
62
- role: 'tool',
63
- content: update.result || update.error || '',
64
- toolExecution: update
65
- });
66
- }
67
- });
68
- // Track responses
69
- this.cli.setOnResponseCallback((message) => {
70
- this.conversationHistory.push({
71
- role: 'system',
72
- content: message
73
- });
74
- this.trackMessage('system-response', message.substring(0, 50));
75
- });
76
- }
77
- trackMessage(type, identifier) {
78
- const key = `${type}:${identifier}`;
79
- const count = this.duplicateDetector.get(key) || 0;
80
- this.duplicateDetector.set(key, count + 1);
81
- }
82
- checkForDuplicates() {
83
- const duplicates = [];
84
- this.duplicateDetector.forEach((count, key) => {
85
- if (count > 1) {
86
- duplicates.push(`${key} appeared ${count} times`);
87
- }
88
- });
89
- return duplicates;
90
- }
91
- async cleanup() {
92
- console.log('\n🧹 Cleaning up integration test environment...');
93
- if (fs.existsSync(this.testDir)) {
94
- fs.rmSync(this.testDir, { recursive: true, force: true });
95
- }
96
- console.log('āœ… Cleanup complete\n');
97
- }
98
- async runTest(name, testFn) {
99
- const startTime = Date.now();
100
- // Reset duplicate detector for each test
101
- this.duplicateDetector.clear();
102
- try {
103
- await testFn();
104
- // Check for duplicates after test
105
- const duplicates = this.checkForDuplicates();
106
- if (duplicates.length > 0) {
107
- throw new Error(`Duplicates detected: ${duplicates.join(', ')}`);
108
- }
109
- const duration = Date.now() - startTime;
110
- this.results.push({ name, passed: true, duration });
111
- console.log(`āœ… ${name} (${duration}ms)`);
112
- }
113
- catch (error) {
114
- const duration = Date.now() - startTime;
115
- this.results.push({ name, passed: false, error: error.message, duration });
116
- console.log(`āŒ ${name} (${duration}ms)`);
117
- console.log(` Error: ${error.message}`);
118
- }
119
- }
120
- printSummary() {
121
- console.log('\n' + '='.repeat(70));
122
- console.log('INTEGRATION TEST SUMMARY');
123
- console.log('='.repeat(70) + '\n');
124
- const passed = this.results.filter(r => r.passed).length;
125
- const failed = this.results.filter(r => !r.passed).length;
126
- const total = this.results.length;
127
- const passRate = total > 0 ? ((passed / total) * 100).toFixed(1) : '0.0';
128
- console.log(`Total Tests: ${total}`);
129
- console.log(`Passed: ${passed}`);
130
- console.log(`Failed: ${failed}`);
131
- console.log(`Pass Rate: ${passRate}%\n`);
132
- if (failed > 0) {
133
- console.log('Failed Tests:');
134
- this.results
135
- .filter(r => !r.passed)
136
- .forEach(r => {
137
- console.log(` - ${r.name}`);
138
- console.log(` ${r.error}`);
139
- });
140
- }
141
- console.log('\n' + '='.repeat(70) + '\n');
142
- }
143
- // ========================================================================
144
- // Task 12.1: Test complete conversation flows
145
- // ========================================================================
146
- async testUserMessageFlow() {
147
- await this.runTest('12.1.1: User message appears exactly once', async () => {
148
- const initialCount = this.conversationHistory.length;
149
- // Simulate user message (without AI response to keep test simple)
150
- this.conversationHistory.push({
151
- role: 'user',
152
- content: 'Test user message'
153
- });
154
- const finalCount = this.conversationHistory.length;
155
- if (finalCount !== initialCount + 1) {
156
- throw new Error(`Expected 1 new message, got ${finalCount - initialCount}`);
157
- }
158
- });
159
- }
160
- async testStreamingResponseFlow() {
161
- await this.runTest('12.1.2: Streaming response displays without duplicates', async () => {
162
- const messageId = `test-stream-${Date.now()}`;
163
- // Simulate streaming
164
- this.cli.setOnStreamStart((id) => {
165
- this.streamingMessages.set(id, '');
166
- this.trackMessage('stream-start', id);
167
- });
168
- // Simulate chunks
169
- const chunks = ['Hello', ' ', 'world', '!'];
170
- for (const chunk of chunks) {
171
- const current = this.streamingMessages.get(messageId) || '';
172
- this.streamingMessages.set(messageId, current + chunk);
173
- }
174
- // Complete stream
175
- const finalContent = this.streamingMessages.get(messageId) || '';
176
- this.conversationHistory.push({
177
- role: 'assistant',
178
- content: finalContent
179
- });
180
- this.streamingMessages.delete(messageId);
181
- this.trackMessage('stream-complete', messageId);
182
- // Verify no duplicates
183
- const streamStarts = this.duplicateDetector.get(`stream-start:${messageId}`) || 0;
184
- const streamCompletes = this.duplicateDetector.get(`stream-complete:${messageId}`) || 0;
185
- if (streamStarts > 1) {
186
- throw new Error(`Stream started ${streamStarts} times`);
187
- }
188
- if (streamCompletes > 1) {
189
- throw new Error(`Stream completed ${streamCompletes} times`);
190
- }
191
- // Verify content is correct
192
- if (finalContent !== 'Hello world!') {
193
- throw new Error(`Expected 'Hello world!', got '${finalContent}'`);
194
- }
195
- });
196
- }
197
- async testToolExecutionFlow() {
198
- await this.runTest('12.1.3: Tool execution displays without duplicates', async () => {
199
- const toolId = `test-tool-${Date.now()}`;
200
- // Clear duplicate detector for this specific test since tool execution
201
- // legitimately updates twice (start and complete)
202
- this.duplicateDetector.clear();
203
- // Simulate tool execution start
204
- const toolUpdate = {
205
- id: toolId,
206
- toolName: 'read_file',
207
- status: 'executing',
208
- arguments: { file_path: 'test.txt' }
209
- };
210
- this.toolExecutions.set(toolId, toolUpdate);
211
- this.trackMessage('tool-execution-start', toolId);
212
- // Simulate tool completion
213
- toolUpdate.status = 'completed';
214
- toolUpdate.result = 'File content here';
215
- this.toolExecutions.set(toolId, toolUpdate);
216
- this.trackMessage('tool-execution-complete', toolId);
217
- this.conversationHistory.push({
218
- role: 'tool',
219
- content: toolUpdate.result,
220
- toolExecution: toolUpdate
221
- });
222
- // Verify tool execution tracked correctly (start and complete are separate events)
223
- const startCount = this.duplicateDetector.get(`tool-execution-start:${toolId}`) || 0;
224
- const completeCount = this.duplicateDetector.get(`tool-execution-complete:${toolId}`) || 0;
225
- if (startCount !== 1) {
226
- throw new Error(`Tool execution start should occur once, got ${startCount}`);
227
- }
228
- if (completeCount !== 1) {
229
- throw new Error(`Tool execution complete should occur once, got ${completeCount}`);
230
- }
231
- });
232
- }
233
- async testRapidMessageSending() {
234
- await this.runTest('12.1.4: Rapid message sending without duplicates', async () => {
235
- const messageCount = 10;
236
- const startCount = this.conversationHistory.length;
237
- // Simulate rapid messages
238
- for (let i = 0; i < messageCount; i++) {
239
- this.conversationHistory.push({
240
- role: 'user',
241
- content: `Rapid message ${i}`
242
- });
243
- // Small delay to simulate rapid but not instant
244
- await new Promise(resolve => setTimeout(resolve, 10));
245
- }
246
- const endCount = this.conversationHistory.length;
247
- if (endCount - startCount !== messageCount) {
248
- throw new Error(`Expected ${messageCount} messages, got ${endCount - startCount}`);
249
- }
250
- });
251
- }
252
- async testLongConversation() {
253
- await this.runTest('12.1.5: Long conversation (50+ messages) without duplicates', async () => {
254
- const messageCount = 55;
255
- const startCount = this.conversationHistory.length;
256
- // Create a long conversation
257
- for (let i = 0; i < messageCount; i++) {
258
- const role = i % 2 === 0 ? 'user' : 'assistant';
259
- this.conversationHistory.push({
260
- role: role,
261
- content: `Message ${i} in long conversation`
262
- });
263
- }
264
- const endCount = this.conversationHistory.length;
265
- if (endCount - startCount !== messageCount) {
266
- throw new Error(`Expected ${messageCount} messages, got ${endCount - startCount}`);
267
- }
268
- // Verify all messages are unique
269
- const contentSet = new Set(this.conversationHistory.slice(startCount).map(m => m.content));
270
- if (contentSet.size !== messageCount) {
271
- throw new Error(`Duplicate messages detected in conversation`);
272
- }
273
- });
274
- }
275
- async testCompleteConversationFlows() {
276
- console.log('šŸ“‹ Task 12.1: Testing complete conversation flows...\n');
277
- await this.testUserMessageFlow();
278
- await this.testStreamingResponseFlow();
279
- await this.testToolExecutionFlow();
280
- await this.testRapidMessageSending();
281
- await this.testLongConversation();
282
- }
283
- // ========================================================================
284
- // Task 12.2: Test approval and modal flows
285
- // ========================================================================
286
- async testApprovalPromptDisplay() {
287
- await this.runTest('12.2.1: Approval prompt displays exactly once', async () => {
288
- let approvalShown = false;
289
- let approvalCount = 0;
290
- this.cli.setOnToolApprovalRequest(async (request) => {
291
- approvalShown = true;
292
- approvalCount++;
293
- this.trackMessage('approval-prompt', request.message);
294
- return true; // Auto-approve
295
- });
296
- // Simulate approval request
297
- const request = {
298
- message: 'Approve file write?',
299
- risky: true
300
- };
301
- // Trigger approval (simulated)
302
- approvalShown = true;
303
- approvalCount++;
304
- this.trackMessage('approval-prompt', request.message);
305
- if (!approvalShown) {
306
- throw new Error('Approval prompt was not shown');
307
- }
308
- if (approvalCount > 1) {
309
- throw new Error(`Approval prompt shown ${approvalCount} times`);
310
- }
311
- });
312
- }
313
- async testPreviewContentDisplay() {
314
- await this.runTest('12.2.2: Preview content displays exactly once', async () => {
315
- let previewShown = false;
316
- let previewCount = 0;
317
- const preview = {
318
- type: 'code',
319
- content: 'console.log("test");',
320
- language: 'javascript'
321
- };
322
- // Simulate preview display
323
- previewShown = true;
324
- previewCount++;
325
- this.trackMessage('preview-display', preview.content);
326
- if (!previewShown) {
327
- throw new Error('Preview was not shown');
328
- }
329
- if (previewCount > 1) {
330
- throw new Error(`Preview shown ${previewCount} times`);
331
- }
332
- });
333
- }
334
- async testAutoAcceptModeBypass() {
335
- await this.runTest('12.2.3: Auto-accept mode bypasses approval prompts', async () => {
336
- let approvalShown = false;
337
- // Enable auto-accept mode (simulated)
338
- const autoAcceptEnabled = true;
339
- this.cli.setOnToolApprovalRequest(async (request) => {
340
- if (!autoAcceptEnabled) {
341
- approvalShown = true;
342
- }
343
- return true; // Auto-approve
344
- });
345
- // Simulate risky operation with auto-accept enabled
346
- // Approval should not be shown
347
- if (approvalShown) {
348
- throw new Error('Approval prompt shown despite auto-accept mode');
349
- }
350
- });
351
- }
352
- async testPlanApprovalFlow() {
353
- await this.runTest('12.2.4: Plan approval flow works correctly', async () => {
354
- let planApprovalShown = false;
355
- let planApprovalCount = 0;
356
- this.cli.setOnPlanApprovalRequest(async (plan) => {
357
- planApprovalShown = true;
358
- planApprovalCount++;
359
- this.trackMessage('plan-approval', JSON.stringify(plan).substring(0, 50));
360
- return true; // Auto-approve
361
- });
362
- // Simulate plan approval request
363
- const plan = {
364
- tasks: ['Task 1', 'Task 2', 'Task 3'],
365
- question: 'Approve this plan?'
366
- };
367
- planApprovalShown = true;
368
- planApprovalCount++;
369
- this.trackMessage('plan-approval', JSON.stringify(plan).substring(0, 50));
370
- if (!planApprovalShown) {
371
- throw new Error('Plan approval was not shown');
372
- }
373
- if (planApprovalCount > 1) {
374
- throw new Error(`Plan approval shown ${planApprovalCount} times`);
375
- }
376
- });
377
- }
378
- async testApprovalAndModalFlows() {
379
- console.log('\nšŸ“‹ Task 12.2: Testing approval and modal flows...\n');
380
- await this.testApprovalPromptDisplay();
381
- await this.testPreviewContentDisplay();
382
- await this.testAutoAcceptModeBypass();
383
- await this.testPlanApprovalFlow();
384
- }
385
- // ========================================================================
386
- // Task 12.3: Test error scenarios
387
- // ========================================================================
388
- async testStreamingInterruption() {
389
- await this.runTest('12.3.1: Streaming interruption handled correctly', async () => {
390
- const messageId = `test-stream-error-${Date.now()}`;
391
- // Start streaming
392
- this.streamingMessages.set(messageId, '');
393
- this.trackMessage('stream-start', messageId);
394
- // Add some chunks
395
- this.streamingMessages.set(messageId, 'Partial content');
396
- // Simulate interruption/error
397
- try {
398
- throw new Error('Stream interrupted');
399
- }
400
- catch (error) {
401
- // Handle error - add error message to conversation
402
- this.conversationHistory.push({
403
- role: 'system',
404
- content: `āŒ Streaming error: ${error.message}`
405
- });
406
- // Clear streaming message
407
- this.streamingMessages.delete(messageId);
408
- this.trackMessage('stream-error', messageId);
409
- }
410
- // Verify error was handled
411
- const lastMessage = this.conversationHistory[this.conversationHistory.length - 1];
412
- if (!lastMessage.content.includes('Streaming error')) {
413
- throw new Error('Error message not added to conversation');
414
- }
415
- // Verify streaming message was cleared
416
- if (this.streamingMessages.has(messageId)) {
417
- throw new Error('Streaming message not cleared after error');
418
- }
419
- });
420
- }
421
- async testToolExecutionFailure() {
422
- await this.runTest('12.3.2: Tool execution failure handled correctly', async () => {
423
- const toolId = `test-tool-error-${Date.now()}`;
424
- // Clear duplicate detector for this specific test
425
- this.duplicateDetector.clear();
426
- // Simulate tool execution
427
- const toolUpdate = {
428
- id: toolId,
429
- toolName: 'read_file',
430
- status: 'executing',
431
- arguments: { file_path: 'nonexistent.txt' }
432
- };
433
- this.toolExecutions.set(toolId, toolUpdate);
434
- this.trackMessage('tool-execution-start', toolId);
435
- // Simulate tool failure
436
- toolUpdate.status = 'error';
437
- toolUpdate.error = 'File not found';
438
- this.toolExecutions.set(toolId, toolUpdate);
439
- this.trackMessage('tool-execution-error', toolId);
440
- // Add error to conversation
441
- this.conversationHistory.push({
442
- role: 'tool',
443
- content: toolUpdate.error,
444
- toolExecution: toolUpdate
445
- });
446
- // Verify error was tracked
447
- const lastMessage = this.conversationHistory[this.conversationHistory.length - 1];
448
- if (lastMessage.content !== 'File not found') {
449
- throw new Error('Tool error not added to conversation');
450
- }
451
- // Verify no duplicates (start and error are separate events)
452
- const startCount = this.duplicateDetector.get(`tool-execution-start:${toolId}`) || 0;
453
- const errorCount = this.duplicateDetector.get(`tool-execution-error:${toolId}`) || 0;
454
- if (startCount !== 1) {
455
- throw new Error(`Tool execution start should occur once, got ${startCount}`);
456
- }
457
- if (errorCount !== 1) {
458
- throw new Error(`Tool execution error should occur once, got ${errorCount}`);
459
- }
460
- });
461
- }
462
- async testNetworkError() {
463
- await this.runTest('12.3.3: Network error handled correctly', async () => {
464
- // Simulate network error during AI request
465
- try {
466
- throw new Error('Network timeout');
467
- }
468
- catch (error) {
469
- // Handle error
470
- this.conversationHistory.push({
471
- role: 'system',
472
- content: `āŒ Network error: ${error.message}`
473
- });
474
- this.trackMessage('network-error', error.message);
475
- }
476
- // Verify error message added
477
- const lastMessage = this.conversationHistory[this.conversationHistory.length - 1];
478
- if (!lastMessage.content.includes('Network error')) {
479
- throw new Error('Network error not added to conversation');
480
- }
481
- });
482
- }
483
- async testErrorMessageNoDuplication() {
484
- await this.runTest('12.3.4: Error messages display without duplication', async () => {
485
- const errorMessage = 'Test error message';
486
- // Add error message once
487
- this.conversationHistory.push({
488
- role: 'system',
489
- content: `āŒ ${errorMessage}`
490
- });
491
- this.trackMessage('error-message', errorMessage);
492
- // Verify it appears only once
493
- const errorCount = this.conversationHistory.filter(m => m.content.includes(errorMessage)).length;
494
- if (errorCount > 1) {
495
- throw new Error(`Error message appeared ${errorCount} times`);
496
- }
497
- });
498
- }
499
- async testErrorScenarios() {
500
- console.log('\nšŸ“‹ Task 12.3: Testing error scenarios...\n');
501
- await this.testStreamingInterruption();
502
- await this.testToolExecutionFailure();
503
- await this.testNetworkError();
504
- await this.testErrorMessageNoDuplication();
505
- }
506
- // ========================================================================
507
- // Task 12.4: Performance testing
508
- // ========================================================================
509
- async testLargeConversationPerformance() {
510
- await this.runTest('12.4.1: 100+ message conversation performance', async () => {
511
- const messageCount = 120;
512
- const startTime = Date.now();
513
- const startCount = this.conversationHistory.length;
514
- // Create large conversation
515
- for (let i = 0; i < messageCount; i++) {
516
- const role = i % 3 === 0 ? 'user' : i % 3 === 1 ? 'assistant' : 'system';
517
- this.conversationHistory.push({
518
- role: role,
519
- content: `Performance test message ${i} with some content to make it realistic`
520
- });
521
- }
522
- const duration = Date.now() - startTime;
523
- const endCount = this.conversationHistory.length;
524
- // Verify all messages added
525
- if (endCount - startCount !== messageCount) {
526
- throw new Error(`Expected ${messageCount} messages, got ${endCount - startCount}`);
527
- }
528
- // Performance check - should complete in reasonable time (< 1 second for adding messages)
529
- if (duration > 1000) {
530
- throw new Error(`Performance issue: took ${duration}ms to add ${messageCount} messages`);
531
- }
532
- console.log(` Added ${messageCount} messages in ${duration}ms`);
533
- });
534
- }
535
- async testResponsiveInput() {
536
- await this.runTest('12.4.2: Input remains responsive with large history', async () => {
537
- // Ensure we have a large conversation
538
- const currentSize = this.conversationHistory.length;
539
- if (currentSize < 100) {
540
- // Add more messages to reach 100+
541
- const needed = 100 - currentSize;
542
- for (let i = 0; i < needed; i++) {
543
- this.conversationHistory.push({
544
- role: 'user',
545
- content: `Filler message ${i}`
546
- });
547
- }
548
- }
549
- // Simulate rapid input
550
- const startTime = Date.now();
551
- const testMessages = 10;
552
- for (let i = 0; i < testMessages; i++) {
553
- this.conversationHistory.push({
554
- role: 'user',
555
- content: `Responsive test ${i}`
556
- });
557
- }
558
- const duration = Date.now() - startTime;
559
- // Should be very fast (< 100ms for 10 messages)
560
- if (duration > 100) {
561
- throw new Error(`Input not responsive: took ${duration}ms for ${testMessages} messages`);
562
- }
563
- console.log(` Added ${testMessages} messages in ${duration}ms with ${this.conversationHistory.length} total messages`);
564
- });
565
- }
566
- async testMemoryUsage() {
567
- await this.runTest('12.4.3: Memory usage reasonable over long session', async () => {
568
- const initialMemory = process.memoryUsage().heapUsed;
569
- // Create a very long conversation
570
- const messageCount = 500;
571
- for (let i = 0; i < messageCount; i++) {
572
- this.conversationHistory.push({
573
- role: i % 2 === 0 ? 'user' : 'assistant',
574
- content: `Memory test message ${i} with some content to simulate real usage`
575
- });
576
- }
577
- const finalMemory = process.memoryUsage().heapUsed;
578
- const memoryIncrease = (finalMemory - initialMemory) / 1024 / 1024; // MB
579
- console.log(` Memory increase: ${memoryIncrease.toFixed(2)} MB for ${messageCount} messages`);
580
- // Memory increase should be reasonable (< 50 MB for 500 messages)
581
- if (memoryIncrease > 50) {
582
- throw new Error(`Excessive memory usage: ${memoryIncrease.toFixed(2)} MB for ${messageCount} messages`);
583
- }
584
- });
585
- }
586
- async testRerenderFrequency() {
587
- await this.runTest('12.4.4: Re-render frequency is optimized', async () => {
588
- // This test verifies that adding messages doesn't cause excessive operations
589
- const startTime = Date.now();
590
- const iterations = 50;
591
- for (let i = 0; i < iterations; i++) {
592
- // Simulate message addition
593
- this.conversationHistory.push({
594
- role: 'user',
595
- content: `Render test ${i}`
596
- });
597
- // Simulate checking for duplicates (like React would re-render)
598
- const duplicates = this.checkForDuplicates();
599
- if (duplicates.length > 0) {
600
- throw new Error(`Duplicates detected during render test: ${duplicates.join(', ')}`);
601
- }
602
- }
603
- const duration = Date.now() - startTime;
604
- const avgTime = duration / iterations;
605
- console.log(` Average time per message: ${avgTime.toFixed(2)}ms`);
606
- // Should be very fast (< 5ms per message on average)
607
- if (avgTime > 5) {
608
- throw new Error(`Slow render performance: ${avgTime.toFixed(2)}ms per message`);
609
- }
610
- });
611
- }
612
- async testPerformance() {
613
- console.log('\nšŸ“‹ Task 12.4: Testing performance...\n');
614
- await this.testLargeConversationPerformance();
615
- await this.testResponsiveInput();
616
- await this.testMemoryUsage();
617
- await this.testRerenderFrequency();
618
- }
619
- // ========================================================================
620
- // Main test runner
621
- // ========================================================================
622
- async runAllTests() {
623
- console.log('šŸš€ Starting Integration Tests for UI Rendering Refactor\n');
624
- console.log('='.repeat(70) + '\n');
625
- await this.setup();
626
- // Task 12.1: Complete conversation flows
627
- await this.testCompleteConversationFlows();
628
- // Task 12.2: Approval and modal flows
629
- await this.testApprovalAndModalFlows();
630
- // Task 12.3: Error scenarios
631
- await this.testErrorScenarios();
632
- // Task 12.4: Performance testing
633
- await this.testPerformance();
634
- await this.cleanup();
635
- this.printSummary();
636
- // Exit with appropriate code
637
- const failed = this.results.filter(r => !r.passed).length;
638
- process.exit(failed > 0 ? 1 : 0);
639
- }
640
- }
641
- // Run tests if this file is executed directly
642
- const runner = new IntegrationTestRunner();
643
- runner.runAllTests().catch((error) => {
644
- console.error('āŒ Integration test runner failed:', error);
645
- process.exit(1);
646
- });
647
- export { IntegrationTestRunner };
648
- //# sourceMappingURL=integration-tests.js.map