@vybestack/llxprt-code 0.1.19-alpha → 0.1.19-beta

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 (135) hide show
  1. package/dist/package.json +3 -3
  2. package/dist/src/config/auth.js +5 -0
  3. package/dist/src/config/auth.js.map +1 -1
  4. package/dist/src/config/config.js +32 -24
  5. package/dist/src/config/config.js.map +1 -1
  6. package/dist/src/config/keyBindings.d.ts +64 -0
  7. package/dist/src/config/keyBindings.js +137 -0
  8. package/dist/src/config/keyBindings.js.map +1 -0
  9. package/dist/src/config/settings.d.ts +1 -0
  10. package/dist/src/config/settings.js.map +1 -1
  11. package/dist/src/gemini.js +9 -2
  12. package/dist/src/gemini.js.map +1 -1
  13. package/dist/src/generated/git-commit.d.ts +1 -1
  14. package/dist/src/generated/git-commit.js +1 -1
  15. package/dist/src/providers/logging/git-stats-service-impl.d.ts +19 -0
  16. package/dist/src/providers/logging/git-stats-service-impl.js +25 -0
  17. package/dist/src/providers/logging/git-stats-service-impl.js.map +1 -0
  18. package/dist/src/providers/logging/git-stats.d.ts +43 -0
  19. package/dist/src/providers/logging/git-stats.js +137 -0
  20. package/dist/src/providers/logging/git-stats.js.map +1 -0
  21. package/dist/src/providers/providerManagerInstance.js +4 -0
  22. package/dist/src/providers/providerManagerInstance.js.map +1 -1
  23. package/dist/src/services/BuiltinCommandLoader.js +2 -0
  24. package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
  25. package/dist/src/services/todo-continuation/todoContinuationService.d.ts +172 -0
  26. package/dist/src/services/todo-continuation/todoContinuationService.js +387 -0
  27. package/dist/src/services/todo-continuation/todoContinuationService.js.map +1 -0
  28. package/dist/src/services/todo-continuation/todoContinuationService.spec.d.ts +6 -0
  29. package/dist/src/services/todo-continuation/todoContinuationService.spec.js +385 -0
  30. package/dist/src/services/todo-continuation/todoContinuationService.spec.js.map +1 -0
  31. package/dist/src/ui/App.js +61 -25
  32. package/dist/src/ui/App.js.map +1 -1
  33. package/dist/src/ui/colors.d.ts +5 -0
  34. package/dist/src/ui/colors.js +51 -0
  35. package/dist/src/ui/colors.js.map +1 -1
  36. package/dist/src/ui/commands/chatCommand.js +16 -0
  37. package/dist/src/ui/commands/chatCommand.js.map +1 -1
  38. package/dist/src/ui/commands/ideCommand.js +67 -31
  39. package/dist/src/ui/commands/ideCommand.js.map +1 -1
  40. package/dist/src/ui/commands/loggingCommand.d.ts +15 -0
  41. package/dist/src/ui/commands/loggingCommand.js +421 -0
  42. package/dist/src/ui/commands/loggingCommand.js.map +1 -0
  43. package/dist/src/ui/commands/privacyCommand.d.ts +3 -0
  44. package/dist/src/ui/commands/privacyCommand.js +6 -3
  45. package/dist/src/ui/commands/privacyCommand.js.map +1 -1
  46. package/dist/src/ui/commands/types.d.ts +14 -2
  47. package/dist/src/ui/commands/types.js.map +1 -1
  48. package/dist/src/ui/components/ContextUsageDisplay.js +14 -2
  49. package/dist/src/ui/components/ContextUsageDisplay.js.map +1 -1
  50. package/dist/src/ui/components/FolderTrustDialog.d.ts +16 -0
  51. package/dist/src/ui/components/FolderTrustDialog.js +38 -0
  52. package/dist/src/ui/components/FolderTrustDialog.js.map +1 -0
  53. package/dist/src/ui/components/Footer.d.ts +0 -1
  54. package/dist/src/ui/components/Footer.js +136 -16
  55. package/dist/src/ui/components/Footer.js.map +1 -1
  56. package/dist/src/ui/components/InputPrompt.js +32 -28
  57. package/dist/src/ui/components/InputPrompt.js.map +1 -1
  58. package/dist/src/ui/components/LoggingDialog.d.ts +37 -0
  59. package/dist/src/ui/components/LoggingDialog.js +155 -0
  60. package/dist/src/ui/components/LoggingDialog.js.map +1 -0
  61. package/dist/src/ui/components/MemoryUsageDisplay.js +6 -4
  62. package/dist/src/ui/components/MemoryUsageDisplay.js.map +1 -1
  63. package/dist/src/ui/components/ProviderDialog.js +100 -26
  64. package/dist/src/ui/components/ProviderDialog.js.map +1 -1
  65. package/dist/src/ui/components/ProviderModelDialog.js +99 -27
  66. package/dist/src/ui/components/ProviderModelDialog.js.map +1 -1
  67. package/dist/src/ui/components/TodoPanel.js +93 -18
  68. package/dist/src/ui/components/TodoPanel.js.map +1 -1
  69. package/dist/src/ui/components/messages/ToolConfirmationMessage.js +85 -7
  70. package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
  71. package/dist/src/ui/contexts/SettingsContext.d.ts +9 -0
  72. package/dist/src/ui/contexts/SettingsContext.js +15 -0
  73. package/dist/src/ui/contexts/SettingsContext.js.map +1 -0
  74. package/dist/src/ui/hooks/atCommandProcessor.js +21 -0
  75. package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
  76. package/dist/src/ui/hooks/slashCommandProcessor.d.ts +5 -1
  77. package/dist/src/ui/hooks/slashCommandProcessor.js +137 -112
  78. package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
  79. package/dist/src/ui/hooks/useConsoleMessages.js +7 -0
  80. package/dist/src/ui/hooks/useConsoleMessages.js.map +1 -1
  81. package/dist/src/ui/hooks/useFolderTrust.d.ts +11 -0
  82. package/dist/src/ui/hooks/useFolderTrust.js +22 -0
  83. package/dist/src/ui/hooks/useFolderTrust.js.map +1 -0
  84. package/dist/src/ui/hooks/useGeminiStream.js +14 -3
  85. package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
  86. package/dist/src/ui/hooks/useResponsive.d.ts +14 -0
  87. package/dist/src/ui/hooks/useResponsive.js +19 -0
  88. package/dist/src/ui/hooks/useResponsive.js.map +1 -0
  89. package/dist/src/ui/hooks/useTodoContinuation.d.ts +31 -0
  90. package/dist/src/ui/hooks/useTodoContinuation.js +148 -0
  91. package/dist/src/ui/hooks/useTodoContinuation.js.map +1 -0
  92. package/dist/src/ui/hooks/useTodoContinuation.spec.d.ts +6 -0
  93. package/dist/src/ui/hooks/useTodoContinuation.spec.js +378 -0
  94. package/dist/src/ui/hooks/useTodoContinuation.spec.js.map +1 -0
  95. package/dist/src/ui/keyMatchers.d.ts +26 -0
  96. package/dist/src/ui/keyMatchers.js +68 -0
  97. package/dist/src/ui/keyMatchers.js.map +1 -0
  98. package/dist/src/ui/privacy/PrivacyNotice.js +10 -4
  99. package/dist/src/ui/privacy/PrivacyNotice.js.map +1 -1
  100. package/dist/src/ui/themes/semantic-resolver.d.ts +12 -0
  101. package/dist/src/ui/themes/semantic-resolver.js +32 -0
  102. package/dist/src/ui/themes/semantic-resolver.js.map +1 -0
  103. package/dist/src/ui/themes/semantic-tokens.d.ts +52 -0
  104. package/dist/src/ui/themes/semantic-tokens.js +7 -0
  105. package/dist/src/ui/themes/semantic-tokens.js.map +1 -0
  106. package/dist/src/ui/themes/theme-compat.d.ts +34 -0
  107. package/dist/src/ui/themes/theme-compat.js +65 -0
  108. package/dist/src/ui/themes/theme-compat.js.map +1 -0
  109. package/dist/src/ui/themes/theme-manager.d.ts +8 -0
  110. package/dist/src/ui/themes/theme-manager.js +18 -0
  111. package/dist/src/ui/themes/theme-manager.js.map +1 -1
  112. package/dist/src/ui/utils/CodeColorizer.d.ts +2 -1
  113. package/dist/src/ui/utils/CodeColorizer.js +4 -3
  114. package/dist/src/ui/utils/CodeColorizer.js.map +1 -1
  115. package/dist/src/ui/utils/MarkdownDisplay.js +4 -2
  116. package/dist/src/ui/utils/MarkdownDisplay.js.map +1 -1
  117. package/dist/src/ui/utils/responsive.d.ts +16 -0
  118. package/dist/src/ui/utils/responsive.js +111 -0
  119. package/dist/src/ui/utils/responsive.js.map +1 -0
  120. package/dist/src/utils/cleanup.d.ts +2 -2
  121. package/dist/src/utils/cleanup.js +2 -2
  122. package/dist/src/utils/cleanup.js.map +1 -1
  123. package/dist/src/utils/privacy/ConversationDataRedactor.d.ts +75 -0
  124. package/dist/src/utils/privacy/ConversationDataRedactor.js +412 -0
  125. package/dist/src/utils/privacy/ConversationDataRedactor.js.map +1 -0
  126. package/dist/src/utils/privacy/PrivacyManager.d.ts +58 -0
  127. package/dist/src/utils/privacy/PrivacyManager.js +133 -0
  128. package/dist/src/utils/privacy/PrivacyManager.js.map +1 -0
  129. package/dist/src/utils/sandbox.js +10 -0
  130. package/dist/src/utils/sandbox.js.map +1 -1
  131. package/dist/tsconfig.tsbuildinfo +1 -1
  132. package/package.json +3 -3
  133. package/dist/src/ui/components/IDEContextDetailDisplay.d.ts +0 -12
  134. package/dist/src/ui/components/IDEContextDetailDisplay.js +0 -30
  135. package/dist/src/ui/components/IDEContextDetailDisplay.js.map +0 -1
@@ -0,0 +1,385 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Vybestack LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+ import { describe, it, expect, beforeEach } from 'vitest';
7
+ import { TodoContinuationService, } from './todoContinuationService.js';
8
+ describe('TodoContinuationService', () => {
9
+ let service;
10
+ let mockConfig;
11
+ let mockState;
12
+ beforeEach(() => {
13
+ service = new TodoContinuationService();
14
+ mockConfig = {};
15
+ mockState = {
16
+ isActive: false,
17
+ attemptCount: 0,
18
+ };
19
+ });
20
+ // Helper functions to create test data
21
+ const createTodo = (id, content, status = 'pending', priority = 'medium') => ({
22
+ id,
23
+ content,
24
+ status,
25
+ priority,
26
+ });
27
+ const createConfig = (overrides = {}) => ({
28
+ taskDescription: 'Complete user authentication',
29
+ isYoloMode: false,
30
+ ...overrides,
31
+ });
32
+ const createContext = (overrides = {}) => ({
33
+ todos: [],
34
+ hadToolCalls: false,
35
+ isResponding: false,
36
+ config: mockConfig,
37
+ currentState: mockState,
38
+ ...overrides,
39
+ });
40
+ describe('Prompt Generation', () => {
41
+ describe('@requirement REQ-002.1 REQ-002.2', () => {
42
+ it('generates standard mode prompt with task description', () => {
43
+ const config = createConfig({
44
+ taskDescription: 'Implement user registration feature',
45
+ isYoloMode: false,
46
+ });
47
+ const result = service.generateContinuationPrompt(config);
48
+ expect(result).toContain('Implement user registration feature');
49
+ expect(result).toMatch(/continue|proceed|working/i);
50
+ expect(result).not.toMatch(/urgent|critical|immediately/i);
51
+ });
52
+ it('includes specific task description in prompt', () => {
53
+ const specificTask = 'Fix database connection timeout in UserService.authenticate method';
54
+ const config = createConfig({
55
+ taskDescription: specificTask,
56
+ isYoloMode: false,
57
+ });
58
+ const result = service.generateContinuationPrompt(config);
59
+ expect(result).toContain(specificTask);
60
+ });
61
+ it('handles task descriptions with special characters', () => {
62
+ const complexTask = 'Update API endpoints: /users/{id}/profile & /auth/tokens (v2.1)';
63
+ const config = createConfig({
64
+ taskDescription: complexTask,
65
+ isYoloMode: false,
66
+ });
67
+ const result = service.generateContinuationPrompt(config);
68
+ expect(result).toContain(complexTask);
69
+ });
70
+ });
71
+ describe('@requirement REQ-002.3', () => {
72
+ it('generates YOLO mode prompt with stronger wording', () => {
73
+ const config = createConfig({
74
+ taskDescription: 'Deploy production hotfix',
75
+ isYoloMode: true,
76
+ });
77
+ const result = service.generateContinuationPrompt(config);
78
+ expect(result).toContain('Deploy production hotfix');
79
+ expect(result).toMatch(/urgent|critical|immediately|essential/i);
80
+ expect(result.length).toBeGreaterThan(50); // YOLO prompts should be more detailed
81
+ });
82
+ it('uses different wording between standard and YOLO mode', () => {
83
+ const taskDescription = 'Complete user authentication';
84
+ const standardPrompt = service.generateContinuationPrompt(createConfig({ taskDescription, isYoloMode: false }));
85
+ const yoloPrompt = service.generateContinuationPrompt(createConfig({ taskDescription, isYoloMode: true }));
86
+ expect(standardPrompt).not.toEqual(yoloPrompt);
87
+ expect(yoloPrompt).toMatch(/urgent|critical|immediately/i);
88
+ expect(standardPrompt).not.toMatch(/urgent|critical|immediately/i);
89
+ });
90
+ });
91
+ it('handles retry attempts in prompt generation', () => {
92
+ const config = createConfig({
93
+ taskDescription: 'Fix failing tests',
94
+ isYoloMode: false,
95
+ attemptCount: 2,
96
+ });
97
+ const result = service.generateContinuationPrompt(config);
98
+ expect(result).toContain('Fix failing tests');
99
+ expect(result).toMatch(/attempt|retry|try again/i);
100
+ });
101
+ it('handles previous failure information in prompts', () => {
102
+ const config = createConfig({
103
+ taskDescription: 'Deploy application',
104
+ isYoloMode: true,
105
+ attemptCount: 1,
106
+ previousFailure: 'Connection timeout during database migration',
107
+ });
108
+ const result = service.generateContinuationPrompt(config);
109
+ expect(result).toContain('Deploy application');
110
+ expect(result).toContain('Connection timeout during database migration');
111
+ });
112
+ it('truncates very long task descriptions', () => {
113
+ const longTask = 'A'.repeat(500); // Exceeds MAX_TASK_DESCRIPTION_LENGTH
114
+ const config = createConfig({
115
+ taskDescription: longTask,
116
+ isYoloMode: false,
117
+ });
118
+ const result = service.generateContinuationPrompt(config);
119
+ expect(result.length).toBeLessThan(longTask.length + 100); // Should be truncated
120
+ expect(result).toMatch(/\.\.\./); // Should have ellipsis
121
+ });
122
+ });
123
+ describe('Continuation Logic', () => {
124
+ describe('@requirement REQ-002.1', () => {
125
+ it('should continue when todos are active and no tool calls were made', () => {
126
+ const todos = [
127
+ createTodo('1', 'Task 1', 'in_progress'),
128
+ createTodo('2', 'Task 2', 'pending'),
129
+ ];
130
+ const context = createContext({
131
+ todos,
132
+ hadToolCalls: false,
133
+ currentState: { ...mockState, isActive: false },
134
+ });
135
+ const result = service.checkContinuationConditions(context);
136
+ expect(result.shouldContinue).toBe(true);
137
+ expect(result.reason).toMatch(/active.*todo/i);
138
+ expect(result.activeTodo).toBeDefined();
139
+ });
140
+ it('should not continue when continuation is disabled in config', () => {
141
+ const todos = [createTodo('1', 'Task 1', 'in_progress')];
142
+ // Mock config with continuation disabled
143
+ const disabledConfig = {
144
+ continuationEnabled: false,
145
+ };
146
+ const context = createContext({
147
+ todos,
148
+ hadToolCalls: false,
149
+ config: disabledConfig,
150
+ });
151
+ const result = service.checkContinuationConditions(context);
152
+ expect(result.shouldContinue).toBe(false);
153
+ expect(result.reason).toMatch(/disabled/i);
154
+ });
155
+ it('should not continue when tool calls were made in current turn', () => {
156
+ const todos = [createTodo('1', 'Task 1', 'in_progress')];
157
+ const context = createContext({
158
+ todos,
159
+ hadToolCalls: true,
160
+ });
161
+ const result = service.checkContinuationConditions(context);
162
+ expect(result.shouldContinue).toBe(false);
163
+ expect(result.reason).toMatch(/tool.*call/i);
164
+ });
165
+ it('should not continue when no active todos exist', () => {
166
+ const todos = [
167
+ createTodo('1', 'Task 1', 'completed'),
168
+ createTodo('2', 'Task 2', 'completed'),
169
+ ];
170
+ const context = createContext({
171
+ todos,
172
+ hadToolCalls: false,
173
+ });
174
+ const result = service.checkContinuationConditions(context);
175
+ expect(result.shouldContinue).toBe(false);
176
+ expect(result.reason).toMatch(/no.*active.*todo/i);
177
+ });
178
+ it('should not continue when maximum attempts exceeded', () => {
179
+ const todos = [createTodo('1', 'Task 1', 'in_progress')];
180
+ const stateWithMaxAttempts = {
181
+ ...mockState,
182
+ attemptCount: 5, // Exceeds MAX_CONTINUATION_ATTEMPTS
183
+ };
184
+ const context = createContext({
185
+ todos,
186
+ hadToolCalls: false,
187
+ currentState: stateWithMaxAttempts,
188
+ });
189
+ const result = service.checkContinuationConditions(context);
190
+ expect(result.shouldContinue).toBe(false);
191
+ expect(result.reason).toMatch(/attempt.*limit/i);
192
+ });
193
+ it('should not continue when already in continuation state', () => {
194
+ const todos = [createTodo('1', 'Task 1', 'in_progress')];
195
+ const activeState = {
196
+ ...mockState,
197
+ isActive: true,
198
+ };
199
+ const context = createContext({
200
+ todos,
201
+ hadToolCalls: false,
202
+ currentState: activeState,
203
+ });
204
+ const result = service.checkContinuationConditions(context);
205
+ expect(result.shouldContinue).toBe(false);
206
+ expect(result.reason).toMatch(/already.*continuing/i);
207
+ });
208
+ it('should respect time constraints between continuation attempts', () => {
209
+ const todos = [createTodo('1', 'Task 1', 'in_progress')];
210
+ const recentState = {
211
+ ...mockState,
212
+ lastPromptTime: new Date(Date.now() - 500), // Very recent
213
+ };
214
+ const context = createContext({
215
+ todos,
216
+ hadToolCalls: false,
217
+ currentState: recentState,
218
+ });
219
+ const result = service.checkContinuationConditions(context);
220
+ expect(result.shouldContinue).toBe(false);
221
+ expect(result.reason).toMatch(/time.*constraint/i);
222
+ });
223
+ });
224
+ it('provides detailed condition evaluation in result', () => {
225
+ const todos = [createTodo('1', 'Task 1', 'in_progress')];
226
+ const context = createContext({
227
+ todos,
228
+ hadToolCalls: false,
229
+ });
230
+ const result = service.checkContinuationConditions(context);
231
+ expect(result.conditions).toBeDefined();
232
+ expect(result.conditions.hasActiveTodos).toBe(true);
233
+ expect(result.conditions.noToolCallsMade).toBe(true);
234
+ expect(result.conditions.continuationEnabled).toBeDefined();
235
+ expect(result.conditions.notCurrentlyContinuing).toBeDefined();
236
+ expect(result.conditions.withinAttemptLimits).toBeDefined();
237
+ expect(result.conditions.withinTimeConstraints).toBeDefined();
238
+ });
239
+ });
240
+ describe('Task Description Extraction', () => {
241
+ describe('@requirement REQ-002.2', () => {
242
+ it('extracts task description from in_progress todos first', () => {
243
+ const inProgressTodo = createTodo('1', 'Critical bug fix in payment processor', 'in_progress');
244
+ const pendingTodo = createTodo('2', 'Add unit tests for user service', 'pending');
245
+ const todos = [pendingTodo, inProgressTodo]; // Order shouldn't matter
246
+ const context = createContext({ todos, hadToolCalls: false });
247
+ const result = service.checkContinuationConditions(context);
248
+ expect(result.shouldContinue).toBe(true);
249
+ expect(result.activeTodo).toEqual(inProgressTodo);
250
+ });
251
+ it('falls back to pending todos when no in_progress todos exist', () => {
252
+ const pendingTodo1 = createTodo('1', 'Implement user authentication', 'pending', 'high');
253
+ const pendingTodo2 = createTodo('2', 'Update documentation', 'pending', 'low');
254
+ const todos = [pendingTodo2, pendingTodo1]; // Lower priority first
255
+ const context = createContext({ todos, hadToolCalls: false });
256
+ const result = service.checkContinuationConditions(context);
257
+ expect(result.shouldContinue).toBe(true);
258
+ expect(result.activeTodo).toEqual(pendingTodo1); // Should pick higher priority
259
+ });
260
+ it('formats todo content into readable task description', () => {
261
+ const todo = createTodo('1', 'Fix: Database connection pool exhaustion in UserService.authenticate() method');
262
+ const result = service.formatTaskDescription(todo);
263
+ expect(result).toBe('Fix: Database connection pool exhaustion in UserService.authenticate() method');
264
+ expect(result.length).toBeGreaterThan(0);
265
+ });
266
+ it('handles malformed todo content gracefully', () => {
267
+ const malformedTodo = createTodo('1', ''); // Empty content (should not happen due to schema)
268
+ const result = service.formatTaskDescription(malformedTodo);
269
+ expect(result).toBeDefined();
270
+ expect(typeof result).toBe('string');
271
+ expect(result.length).toBeGreaterThan(0); // Should provide fallback
272
+ });
273
+ it('prioritizes high-priority pending todos over low-priority ones', () => {
274
+ const lowPriorityTodo = createTodo('1', 'Update README', 'pending', 'low');
275
+ const highPriorityTodo = createTodo('2', 'Fix security vulnerability', 'pending', 'high');
276
+ const todos = [lowPriorityTodo, highPriorityTodo];
277
+ const context = createContext({ todos, hadToolCalls: false });
278
+ const result = service.checkContinuationConditions(context);
279
+ expect(result.activeTodo).toEqual(highPriorityTodo);
280
+ });
281
+ });
282
+ });
283
+ describe('Edge Cases and Error Handling', () => {
284
+ it('handles empty todo list gracefully', () => {
285
+ const context = createContext({
286
+ todos: [],
287
+ hadToolCalls: false,
288
+ });
289
+ const result = service.checkContinuationConditions(context);
290
+ expect(result.shouldContinue).toBe(false);
291
+ expect(result.reason).toMatch(/no.*active.*todo/i);
292
+ expect(result.activeTodo).toBeUndefined();
293
+ });
294
+ it('handles null/undefined inputs safely', () => {
295
+ expect(() => {
296
+ const nullContext = null;
297
+ service.checkContinuationConditions(nullContext);
298
+ }).toThrow();
299
+ expect(() => {
300
+ const nullConfig = null;
301
+ service.generateContinuationPrompt(nullConfig);
302
+ }).toThrow();
303
+ });
304
+ it('handles empty task description strings', () => {
305
+ const config = createConfig({
306
+ taskDescription: '',
307
+ isYoloMode: false,
308
+ });
309
+ const result = service.generateContinuationPrompt(config);
310
+ expect(result).toBeDefined();
311
+ expect(typeof result).toBe('string');
312
+ expect(result.length).toBeGreaterThan(0); // Should provide fallback prompt
313
+ });
314
+ it('handles very long task descriptions by truncating', () => {
315
+ const veryLongDescription = 'Task: ' + 'A'.repeat(1000);
316
+ const config = createConfig({
317
+ taskDescription: veryLongDescription,
318
+ isYoloMode: false,
319
+ });
320
+ const result = service.generateContinuationPrompt(config);
321
+ expect(result.length).toBeLessThan(veryLongDescription.length + 50);
322
+ expect(result).toContain('Task:');
323
+ });
324
+ it('handles todos with undefined optional fields', () => {
325
+ const minimalTodo = {
326
+ id: '1',
327
+ content: 'Minimal todo item',
328
+ status: 'in_progress',
329
+ priority: 'medium',
330
+ // subtasks and toolCalls are undefined
331
+ };
332
+ const result = service.formatTaskDescription(minimalTodo);
333
+ expect(result).toBe('Minimal todo item');
334
+ });
335
+ it('creates initial continuation state correctly', () => {
336
+ const state = service.createContinuationState();
337
+ expect(state.isActive).toBe(false);
338
+ expect(state.attemptCount).toBe(0);
339
+ expect(state.taskDescription).toBeUndefined();
340
+ expect(state.lastPromptTime).toBeUndefined();
341
+ });
342
+ });
343
+ describe('Helper Methods', () => {
344
+ describe('shouldContinue', () => {
345
+ it('returns true when conditions are met', () => {
346
+ const result = service.shouldContinue(mockConfig, true, false);
347
+ expect(typeof result).toBe('boolean');
348
+ // Implementation will determine exact behavior
349
+ });
350
+ it('returns false when no active todos', () => {
351
+ const result = service.shouldContinue(mockConfig, false, false);
352
+ expect(result).toBe(false);
353
+ });
354
+ it('returns false when tool calls were made', () => {
355
+ const result = service.shouldContinue(mockConfig, true, true);
356
+ expect(result).toBe(false);
357
+ });
358
+ });
359
+ describe('formatPrompt', () => {
360
+ it('formats prompt with task description and mode', () => {
361
+ const taskDescription = 'Implement OAuth2 flow';
362
+ const standardPrompt = service.formatPrompt(taskDescription, false);
363
+ const yoloPrompt = service.formatPrompt(taskDescription, true);
364
+ expect(standardPrompt).toContain(taskDescription);
365
+ expect(yoloPrompt).toContain(taskDescription);
366
+ expect(standardPrompt).not.toEqual(yoloPrompt);
367
+ });
368
+ });
369
+ describe('shouldAllowContinuation', () => {
370
+ it('respects configuration settings', () => {
371
+ const result = service.shouldAllowContinuation(mockConfig, mockState);
372
+ expect(typeof result).toBe('boolean');
373
+ });
374
+ it('considers attempt limits', () => {
375
+ const maxAttemptState = {
376
+ ...mockState,
377
+ attemptCount: 10, // High number
378
+ };
379
+ const result = service.shouldAllowContinuation(mockConfig, maxAttemptState);
380
+ expect(typeof result).toBe('boolean');
381
+ });
382
+ });
383
+ });
384
+ });
385
+ //# sourceMappingURL=todoContinuationService.spec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"todoContinuationService.spec.js","sourceRoot":"","sources":["../../../../src/services/todo-continuation/todoContinuationService.spec.ts"],"names":[],"mappings":"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"}
@@ -5,13 +5,14 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
5
5
  * SPDX-License-Identifier: Apache-2.0
6
6
  */
7
7
  import { useCallback, useEffect, useMemo, useState, useRef, useReducer, } from 'react';
8
- import { Box, measureElement, Static, Text, useStdin, useStdout, useInput, } from 'ink';
8
+ import { Box, measureElement, Static, Text, useStdin, useStdout, } from 'ink';
9
9
  import { StreamingState, MessageType } from './types.js';
10
10
  import { useTerminalSize } from './hooks/useTerminalSize.js';
11
11
  import { useGeminiStream } from './hooks/useGeminiStream.js';
12
12
  import { useLoadingIndicator } from './hooks/useLoadingIndicator.js';
13
13
  import { useThemeCommand } from './hooks/useThemeCommand.js';
14
14
  import { useAuthCommand } from './hooks/useAuthCommand.js';
15
+ import { useFolderTrust } from './hooks/useFolderTrust.js';
15
16
  import { useEditorSettings } from './hooks/useEditorSettings.js';
16
17
  import { useSlashCommandProcessor } from './hooks/slashCommandProcessor.js';
17
18
  import { useAutoAcceptIndicator } from './hooks/useAutoAcceptIndicator.js';
@@ -26,7 +27,9 @@ import { ThemeDialog } from './components/ThemeDialog.js';
26
27
  import { AuthDialog } from './components/AuthDialog.js';
27
28
  import { AuthInProgress } from './components/AuthInProgress.js';
28
29
  import { EditorSettingsDialog } from './components/EditorSettingsDialog.js';
30
+ import { FolderTrustDialog } from './components/FolderTrustDialog.js';
29
31
  import { ShellConfirmationDialog } from './components/ShellConfirmationDialog.js';
32
+ import { RadioButtonSelect } from './components/shared/RadioButtonSelect.js';
30
33
  import { Colors } from './colors.js';
31
34
  import { Help } from './components/Help.js';
32
35
  import { loadHierarchicalLlxprtMemory } from '../config/config.js';
@@ -37,7 +40,6 @@ import { registerCleanup } from '../utils/cleanup.js';
37
40
  import { DetailedMessagesDisplay } from './components/DetailedMessagesDisplay.js';
38
41
  import { HistoryItemDisplay } from './components/HistoryItemDisplay.js';
39
42
  import { ContextSummaryDisplay } from './components/ContextSummaryDisplay.js';
40
- import { IDEContextDetailDisplay } from './components/IDEContextDetailDisplay.js';
41
43
  import { useHistory } from './hooks/useHistoryManager.js';
42
44
  import process from 'node:process';
43
45
  import { getErrorMessage, getAllLlxprtMdFilenames, ApprovalMode, isEditorAvailable, FlashFallbackEvent, logFlashFallback, AuthType, ideContext, } from '@vybestack/llxprt-code-core';
@@ -52,6 +54,8 @@ import { useBracketedPaste } from './hooks/useBracketedPaste.js';
52
54
  import { useTextBuffer } from './components/shared/text-buffer.js';
53
55
  import { useVimMode, VimModeProvider } from './contexts/VimModeContext.js';
54
56
  import { useVim } from './hooks/vim.js';
57
+ import { useKeypress } from './hooks/useKeypress.js';
58
+ import { keyMatchers, Command } from './keyMatchers.js';
55
59
  import * as fs from 'fs';
56
60
  import { appReducer, initialAppState, } from './reducers/appReducer.js';
57
61
  import { AppDispatchProvider } from './contexts/AppDispatchContext.js';
@@ -95,6 +99,12 @@ const App = (props) => {
95
99
  const { updateTodos } = useTodoContext();
96
100
  const [idePromptAnswered, setIdePromptAnswered] = useState(false);
97
101
  const currentIDE = config.getIdeClient()?.getCurrentIde();
102
+ useEffect(() => {
103
+ const ideClient = config.getIdeClient();
104
+ if (ideClient) {
105
+ registerCleanup(() => ideClient.disconnect());
106
+ }
107
+ }, [config]);
98
108
  const shouldShowIdePrompt = config.getIdeModeFeature() &&
99
109
  currentIDE &&
100
110
  !config.getIdeMode() &&
@@ -132,7 +142,6 @@ const App = (props) => {
132
142
  const [shellModeActive, setShellModeActive] = useState(false);
133
143
  const [showErrorDetails, setShowErrorDetails] = useState(false);
134
144
  const [showToolDescriptions, setShowToolDescriptions] = useState(false);
135
- const [showIDEContextDetail, setShowIDEContextDetail] = useState(false);
136
145
  const [ctrlCPressedOnce, setCtrlCPressedOnce] = useState(false);
137
146
  const [quittingMessages, setQuittingMessages] = useState(null);
138
147
  const ctrlCTimerRef = useRef(null);
@@ -178,6 +187,7 @@ const App = (props) => {
178
187
  .filter((msg) => msg.type === 'error')
179
188
  .reduce((total, msg) => total + msg.count, 0), [consoleMessages]);
180
189
  const { isThemeDialogOpen, openThemeDialog, handleThemeSelect, handleThemeHighlight, } = useThemeCommand(settings, appState, addItem);
190
+ const { isFolderTrustDialogOpen, handleFolderTrustSelect } = useFolderTrust(settings);
181
191
  const { isAuthDialogOpen, openAuthDialog, handleAuthSelect, isAuthenticating, cancelAuthentication, } = useAuthCommand(settings, appState, config);
182
192
  useEffect(() => {
183
193
  if (settings.merged.selectedAuthType && !settings.merged.useExternalAuth) {
@@ -406,7 +416,7 @@ const App = (props) => {
406
416
  }, []);
407
417
  // Core hooks and processors
408
418
  const { vimEnabled: vimModeEnabled, vimMode, toggleVimEnabled, } = useVimMode();
409
- const { handleSlashCommand, slashCommands, pendingHistoryItems: pendingSlashCommandHistoryItems, commandContext, shellConfirmationRequest, } = useSlashCommandProcessor(config, settings, addItem, clearItems, loadHistory, refreshStatic, setShowHelp, setDebugMessage, openThemeDialog, openAuthDialog, openEditorDialog, openProviderDialog, openProviderModelDialog, openLoadProfileDialog, openToolsDialog, toggleCorgiMode, setQuittingMessages, openPrivacyNotice, toggleVimEnabled, setIsProcessing, setLlxprtMdFileCount);
419
+ const { handleSlashCommand, slashCommands, pendingHistoryItems: pendingSlashCommandHistoryItems, commandContext, shellConfirmationRequest, confirmationRequest, } = useSlashCommandProcessor(config, settings, addItem, clearItems, loadHistory, refreshStatic, setShowHelp, setDebugMessage, openThemeDialog, openAuthDialog, openEditorDialog, openProviderDialog, openProviderModelDialog, openLoadProfileDialog, openToolsDialog, toggleCorgiMode, setQuittingMessages, openPrivacyNotice, toggleVimEnabled, setIsProcessing, setLlxprtMdFileCount);
410
420
  const buffer = useTextBuffer({
411
421
  initialText: '',
412
422
  viewport: { height: 10, width: inputWidth },
@@ -466,20 +476,16 @@ const App = (props) => {
466
476
  }, CTRL_EXIT_PROMPT_DURATION_MS);
467
477
  }
468
478
  }, [handleSlashCommand]);
469
- useInput((input, key) => {
479
+ const handleGlobalKeypress = useCallback((key) => {
470
480
  let enteringConstrainHeightMode = false;
471
481
  if (!constrainHeight) {
472
- // Automatically re-enter constrain height mode if the user types
473
- // anything. When constrainHeight==false, the user will experience
474
- // significant flickering so it is best to disable it immediately when
475
- // the user starts interacting with the app.
476
482
  enteringConstrainHeightMode = true;
477
483
  setConstrainHeight(true);
478
484
  }
479
- if (key.ctrl && input === 'o') {
485
+ if (keyMatchers[Command.SHOW_ERROR_DETAILS](key)) {
480
486
  setShowErrorDetails((prev) => !prev);
481
487
  }
482
- else if (key.ctrl && input === 't') {
488
+ else if (keyMatchers[Command.TOGGLE_TOOL_DESCRIPTIONS](key)) {
483
489
  const newValue = !showToolDescriptions;
484
490
  setShowToolDescriptions(newValue);
485
491
  const mcpServers = config.getMcpServers();
@@ -487,30 +493,49 @@ const App = (props) => {
487
493
  handleSlashCommand(newValue ? '/mcp desc' : '/mcp nodesc');
488
494
  }
489
495
  }
490
- else if (key.ctrl &&
491
- input === 'e' &&
496
+ else if (keyMatchers[Command.TOGGLE_IDE_CONTEXT_DETAIL](key) &&
492
497
  config.getIdeMode() &&
493
498
  ideContextState) {
494
- setShowIDEContextDetail((prev) => !prev);
499
+ // Show IDE status when in IDE mode and context is available.
500
+ handleSlashCommand('/ide status');
495
501
  }
496
- else if (key.ctrl && (input === 'c' || input === 'C')) {
502
+ else if (keyMatchers[Command.QUIT](key)) {
503
+ // When authenticating, let AuthInProgress component handle Ctrl+C.
497
504
  if (isAuthenticating) {
498
- // Let AuthInProgress component handle the input.
499
505
  return;
500
506
  }
501
507
  handleExit(ctrlCPressedOnce, setCtrlCPressedOnce, ctrlCTimerRef);
502
508
  }
503
- else if (key.ctrl && (input === 'd' || input === 'D')) {
509
+ else if (keyMatchers[Command.EXIT](key)) {
504
510
  if (buffer.text.length > 0) {
505
- // Do nothing if there is text in the input.
506
511
  return;
507
512
  }
508
513
  handleExit(ctrlDPressedOnce, setCtrlDPressedOnce, ctrlDTimerRef);
509
514
  }
510
- else if (key.ctrl && input === 's' && !enteringConstrainHeightMode) {
515
+ else if (keyMatchers[Command.SHOW_MORE_LINES](key) &&
516
+ !enteringConstrainHeightMode) {
511
517
  setConstrainHeight(false);
512
518
  }
513
- });
519
+ }, [
520
+ constrainHeight,
521
+ setConstrainHeight,
522
+ setShowErrorDetails,
523
+ showToolDescriptions,
524
+ setShowToolDescriptions,
525
+ config,
526
+ ideContextState,
527
+ handleExit,
528
+ ctrlCPressedOnce,
529
+ setCtrlCPressedOnce,
530
+ ctrlCTimerRef,
531
+ buffer.text.length,
532
+ ctrlDPressedOnce,
533
+ setCtrlDPressedOnce,
534
+ ctrlDTimerRef,
535
+ handleSlashCommand,
536
+ isAuthenticating,
537
+ ]);
538
+ useKeypress(handleGlobalKeypress, { isActive: true });
514
539
  useEffect(() => {
515
540
  if (config) {
516
541
  setLlxprtMdFileCount(config.getLlxprtMdFileCount());
@@ -553,6 +578,11 @@ const App = (props) => {
553
578
  console.clear();
554
579
  refreshStatic();
555
580
  }, [clearItems, clearConsoleMessagesState, refreshStatic]);
581
+ const handleConfirmationSelect = useCallback((value) => {
582
+ if (confirmationRequest) {
583
+ confirmationRequest.onConfirm(value);
584
+ }
585
+ }, [confirmationRequest]);
556
586
  const mainControlsRef = useRef(null);
557
587
  const pendingHistoryItemRef = useRef(null);
558
588
  useEffect(() => {
@@ -636,16 +666,24 @@ const App = (props) => {
636
666
  // Arbitrary threshold to ensure that items in the static area are large
637
667
  // enough but not too large to make the terminal hard to use.
638
668
  const staticAreaMaxItemHeight = Math.max(terminalHeight * 4, 100);
669
+ // Detect PowerShell for file reference syntax tip
670
+ const isPowerShell = process.env.PSModulePath !== undefined ||
671
+ process.env.PSVERSION !== undefined;
639
672
  const placeholder = vimModeEnabled
640
673
  ? " Press 'i' for INSERT mode and 'Esc' for NORMAL mode."
641
- : ' Type your message or @path/to/file';
674
+ : isPowerShell
675
+ ? ' Type your message, @path/to/file or +path/to/file'
676
+ : ' Type your message or @path/to/file';
642
677
  return (_jsx(StreamingContext.Provider, { value: streamingState, children: _jsxs(Box, { flexDirection: "column", width: "90%", children: [_jsx(Static, { items: [
643
678
  _jsxs(Box, { flexDirection: "column", children: [!settings.merged.hideBanner && (_jsx(Header, { terminalWidth: terminalWidth, version: version, nightly: nightly })), !settings.merged.hideTips && _jsx(Tips, { config: config })] }, "header"),
644
679
  ...history.map((h) => (_jsx(HistoryItemDisplay, { terminalWidth: mainAreaWidth, availableTerminalHeight: staticAreaMaxItemHeight, item: h, isPending: false, config: config }, h.id))),
645
680
  ], children: (item) => item }, staticKey), _jsx(OverflowProvider, { children: _jsxs(Box, { ref: pendingHistoryItemRef, flexDirection: "column", children: [pendingHistoryItems.map((item, i) => (_jsx(HistoryItemDisplay, { availableTerminalHeight: constrainHeight ? availableTerminalHeight : undefined, terminalWidth: mainAreaWidth,
646
681
  // TODO(taehykim): It seems like references to ids aren't necessary in
647
682
  // HistoryItemDisplay. Refactor later. Use a fake id for now.
648
- item: { ...item, id: 0 }, isPending: true, config: config, isFocused: !isEditorDialogOpen }, i))), _jsx(ShowMoreLines, { constrainHeight: constrainHeight })] }) }), showHelp && _jsx(Help, { commands: slashCommands }), _jsxs(Box, { flexDirection: "column", ref: mainControlsRef, children: [updateInfo && _jsx(UpdateNotification, { message: updateInfo.message }), startupWarnings.length > 0 && (_jsx(Box, { borderStyle: "round", borderColor: Colors.AccentYellow, paddingX: 1, marginY: 1, flexDirection: "column", children: startupWarnings.map((warning, index) => (_jsx(Text, { color: Colors.AccentYellow, children: warning }, index))) })), _jsx(TodoPanel, { width: inputWidth }), shouldShowIdePrompt ? (_jsx(IdeIntegrationNudge, { question: "Do you want to connect your VS Code editor to LLxprt Code?", description: "If you select Yes, we'll install an extension that allows the CLI to access your open files and display diffs directly in VS Code.", onComplete: handleIdePromptComplete })) : shellConfirmationRequest ? (_jsx(ShellConfirmationDialog, { request: shellConfirmationRequest })) : isThemeDialogOpen ? (_jsxs(Box, { flexDirection: "column", children: [_themeError && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: Colors.AccentRed, children: _themeError }) })), _jsx(ThemeDialog, { onSelect: handleThemeSelect, onHighlight: handleThemeHighlight, settings: settings, availableTerminalHeight: constrainHeight
683
+ item: { ...item, id: 0 }, isPending: true, config: config, isFocused: !isEditorDialogOpen }, i))), _jsx(ShowMoreLines, { constrainHeight: constrainHeight })] }) }), showHelp && _jsx(Help, { commands: slashCommands }), _jsxs(Box, { flexDirection: "column", ref: mainControlsRef, children: [updateInfo && _jsx(UpdateNotification, { message: updateInfo.message }), startupWarnings.length > 0 && (_jsx(Box, { borderStyle: "round", borderColor: Colors.AccentYellow, paddingX: 1, marginY: 1, flexDirection: "column", children: startupWarnings.map((warning, index) => (_jsx(Text, { color: Colors.AccentYellow, children: warning }, index))) })), _jsx(TodoPanel, { width: inputWidth }), shouldShowIdePrompt ? (_jsx(IdeIntegrationNudge, { question: "Do you want to connect your VS Code editor to LLxprt Code?", description: "If you select Yes, we'll install an extension that allows the CLI to access your open files and display diffs directly in VS Code.", onComplete: handleIdePromptComplete })) : isFolderTrustDialogOpen ? (_jsx(FolderTrustDialog, { onSelect: handleFolderTrustSelect })) : shellConfirmationRequest ? (_jsx(ShellConfirmationDialog, { request: shellConfirmationRequest })) : confirmationRequest ? (_jsxs(Box, { flexDirection: "column", children: [confirmationRequest.prompt, _jsx(Box, { paddingY: 1, children: _jsx(RadioButtonSelect, { items: [
684
+ { label: 'Yes', value: true },
685
+ { label: 'No', value: false },
686
+ ], onSelect: handleConfirmationSelect }) })] })) : isThemeDialogOpen ? (_jsxs(Box, { flexDirection: "column", children: [_themeError && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: Colors.AccentRed, children: _themeError }) })), _jsx(ThemeDialog, { onSelect: handleThemeSelect, onHighlight: handleThemeHighlight, settings: settings, availableTerminalHeight: constrainHeight
649
687
  ? terminalHeight - staticExtraHeight
650
688
  : undefined, terminalWidth: mainAreaWidth })] })) : isAuthenticating ? (_jsxs(_Fragment, { children: [_jsx(AuthInProgress, { onTimeout: handleAuthTimeout }), showErrorDetails && (_jsx(OverflowProvider, { children: _jsxs(Box, { flexDirection: "column", children: [_jsx(DetailedMessagesDisplay, { messages: filteredConsoleMessages, maxHeight: constrainHeight ? debugConsoleMaxHeight : undefined, width: inputWidth }), _jsx(ShowMoreLines, { constrainHeight: constrainHeight })] }) }))] })) : isAuthDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(AuthDialog, { onSelect: handleAuthSelect, settings: settings, initialErrorMessage: authError }) })) : isEditorDialogOpen ? (_jsxs(Box, { flexDirection: "column", children: [_editorError && (_jsx(Box, { marginBottom: 1, children: _jsx(Text, { color: Colors.AccentRed, children: _editorError }) })), _jsx(EditorSettingsDialog, { onSelect: handleEditorSelect, settings: settings, onExit: exitEditorDialog })] })) : isProviderDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(ProviderDialog, { providers: providerManager.listProviders(), currentProvider: providerManager.getActiveProviderName(), onSelect: handleProviderSelect, onClose: exitProviderDialog }) })) : isProviderModelDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(ProviderModelDialog, { models: providerModels, currentModel: currentModel, onSelect: handleProviderModelChange, onClose: exitProviderModelDialog }) })) : isLoadProfileDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(LoadProfileDialog, { profiles: profiles, onSelect: handleProfileSelect, onClose: exitLoadProfileDialog }) })) : isToolsDialogOpen ? (_jsx(Box, { flexDirection: "column", children: _jsx(ToolsDialog, { tools: toolsDialogTools, action: toolsDialogAction, disabledTools: toolsDialogDisabledTools, onSelect: handleToolsSelect, onClose: exitToolsDialog }) })) : showPrivacyNotice ? (_jsx(PrivacyNotice, { onExit: handlePrivacyNoticeExit, config: config })) : (_jsxs(_Fragment, { children: [_jsx(LoadingIndicator, { thought: streamingState === StreamingState.WaitingForConfirmation ||
651
689
  config.getAccessibility()?.disableLoadingPhrases
@@ -653,8 +691,6 @@ const App = (props) => {
653
691
  : thought, currentLoadingPhrase: config.getAccessibility()?.disableLoadingPhrases
654
692
  ? undefined
655
693
  : currentLoadingPhrase, elapsedTime: elapsedTime }), _jsxs(Box, { marginTop: 1, display: "flex", justifyContent: "space-between", width: "100%", children: [_jsxs(Box, { children: [process.env.GEMINI_SYSTEM_MD && (_jsx(Text, { color: Colors.AccentRed, children: "|\u2310\u25A0_\u25A0| " })), ctrlCPressedOnce ? (_jsx(Text, { color: Colors.AccentYellow, children: "Press Ctrl+C again to exit." })) : ctrlDPressedOnce ? (_jsx(Text, { color: Colors.AccentYellow, children: "Press Ctrl+D again to exit." })) : (_jsx(ContextSummaryDisplay, { ideContext: ideContextState, llxprtMdFileCount: llxprtMdFileCount, contextFileNames: contextFileNames, mcpServers: config.getMcpServers(), blockedMcpServers: config.getBlockedMcpServers(), showToolDescriptions: showToolDescriptions }))] }), _jsxs(Box, { children: [showAutoAcceptIndicator !== ApprovalMode.DEFAULT &&
656
- !shellModeActive && (_jsx(AutoAcceptIndicator, { approvalMode: showAutoAcceptIndicator })), shellModeActive && _jsx(ShellModeIndicator, {})] })] }), showIDEContextDetail && (_jsx(IDEContextDetailDisplay, { ideContext: ideContextState, detectedIdeDisplay: config
657
- .getIdeClient()
658
- ?.getDetectedIdeDisplayName() })), showErrorDetails && (_jsx(OverflowProvider, { children: _jsxs(Box, { flexDirection: "column", children: [_jsx(DetailedMessagesDisplay, { messages: filteredConsoleMessages, maxHeight: constrainHeight ? debugConsoleMaxHeight : undefined, width: inputWidth }), _jsx(ShowMoreLines, { constrainHeight: constrainHeight })] }) })), isInputActive && (_jsx(_Fragment, { children: _jsx(InputPrompt, { buffer: buffer, inputWidth: inputWidth, suggestionsWidth: suggestionsWidth, onSubmit: handleUserInputSubmit, userMessages: userMessages, onClearScreen: handleClearScreen, config: config, slashCommands: slashCommands, commandContext: commandContext, shellModeActive: shellModeActive, setShellModeActive: setShellModeActive, focus: isFocused, vimHandleInput: vimHandleInput, placeholder: placeholder }) }))] })), initError && streamingState !== StreamingState.Responding && (_jsx(Box, { borderStyle: "round", borderColor: Colors.AccentRed, paddingX: 1, marginBottom: 1, children: history.find((item) => item.type === 'error' && item.text?.includes(initError))?.text ? (_jsx(Text, { color: Colors.AccentRed, children: history.find((item) => item.type === 'error' && item.text?.includes(initError))?.text })) : (_jsxs(_Fragment, { children: [_jsxs(Text, { color: Colors.AccentRed, children: ["Initialization Error: ", initError] }), _jsxs(Text, { color: Colors.AccentRed, children: [' ', "Please check API key and configuration."] })] })) })), _jsx(Footer, { model: currentModel, targetDir: config.getTargetDir(), debugMode: config.getDebugMode(), branchName: branchName, debugMessage: debugMessage, errorCount: errorCount, showErrorDetails: showErrorDetails, showMemoryUsage: config.getDebugMode() || config.getShowMemoryUsage(), promptTokenCount: sessionStats.lastPromptTokenCount, nightly: nightly, vimMode: vimModeEnabled ? vimMode : undefined, contextLimit: config.getEphemeralSetting('context-limit') })] })] }) }));
694
+ !shellModeActive && (_jsx(AutoAcceptIndicator, { approvalMode: showAutoAcceptIndicator })), shellModeActive && _jsx(ShellModeIndicator, {})] })] }), showErrorDetails && (_jsx(OverflowProvider, { children: _jsxs(Box, { flexDirection: "column", children: [_jsx(DetailedMessagesDisplay, { messages: filteredConsoleMessages, maxHeight: constrainHeight ? debugConsoleMaxHeight : undefined, width: inputWidth }), _jsx(ShowMoreLines, { constrainHeight: constrainHeight })] }) })), isInputActive && (_jsx(_Fragment, { children: _jsx(InputPrompt, { buffer: buffer, inputWidth: inputWidth, suggestionsWidth: suggestionsWidth, onSubmit: handleUserInputSubmit, userMessages: userMessages, onClearScreen: handleClearScreen, config: config, slashCommands: slashCommands, commandContext: commandContext, shellModeActive: shellModeActive, setShellModeActive: setShellModeActive, focus: isFocused, vimHandleInput: vimHandleInput, placeholder: placeholder }) }))] })), initError && streamingState !== StreamingState.Responding && (_jsx(Box, { borderStyle: "round", borderColor: Colors.AccentRed, paddingX: 1, marginBottom: 1, children: history.find((item) => item.type === 'error' && item.text?.includes(initError))?.text ? (_jsx(Text, { color: Colors.AccentRed, children: history.find((item) => item.type === 'error' && item.text?.includes(initError))?.text })) : (_jsxs(_Fragment, { children: [_jsxs(Text, { color: Colors.AccentRed, children: ["Initialization Error: ", initError] }), _jsxs(Text, { color: Colors.AccentRed, children: [' ', "Please check API key and configuration."] })] })) })), _jsx(Footer, { model: currentModel, targetDir: config.getTargetDir(), debugMode: config.getDebugMode(), branchName: branchName, debugMessage: debugMessage, errorCount: errorCount, showErrorDetails: showErrorDetails, promptTokenCount: sessionStats.lastPromptTokenCount, nightly: nightly, vimMode: vimModeEnabled ? vimMode : undefined, contextLimit: config.getEphemeralSetting('context-limit') })] })] }) }));
659
695
  };
660
696
  //# sourceMappingURL=App.js.map