@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.
- package/dist/package.json +3 -3
- package/dist/src/config/auth.js +5 -0
- package/dist/src/config/auth.js.map +1 -1
- package/dist/src/config/config.js +32 -24
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/keyBindings.d.ts +64 -0
- package/dist/src/config/keyBindings.js +137 -0
- package/dist/src/config/keyBindings.js.map +1 -0
- package/dist/src/config/settings.d.ts +1 -0
- package/dist/src/config/settings.js.map +1 -1
- package/dist/src/gemini.js +9 -2
- package/dist/src/gemini.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +1 -1
- package/dist/src/generated/git-commit.js +1 -1
- package/dist/src/providers/logging/git-stats-service-impl.d.ts +19 -0
- package/dist/src/providers/logging/git-stats-service-impl.js +25 -0
- package/dist/src/providers/logging/git-stats-service-impl.js.map +1 -0
- package/dist/src/providers/logging/git-stats.d.ts +43 -0
- package/dist/src/providers/logging/git-stats.js +137 -0
- package/dist/src/providers/logging/git-stats.js.map +1 -0
- package/dist/src/providers/providerManagerInstance.js +4 -0
- package/dist/src/providers/providerManagerInstance.js.map +1 -1
- package/dist/src/services/BuiltinCommandLoader.js +2 -0
- package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
- package/dist/src/services/todo-continuation/todoContinuationService.d.ts +172 -0
- package/dist/src/services/todo-continuation/todoContinuationService.js +387 -0
- package/dist/src/services/todo-continuation/todoContinuationService.js.map +1 -0
- package/dist/src/services/todo-continuation/todoContinuationService.spec.d.ts +6 -0
- package/dist/src/services/todo-continuation/todoContinuationService.spec.js +385 -0
- package/dist/src/services/todo-continuation/todoContinuationService.spec.js.map +1 -0
- package/dist/src/ui/App.js +61 -25
- package/dist/src/ui/App.js.map +1 -1
- package/dist/src/ui/colors.d.ts +5 -0
- package/dist/src/ui/colors.js +51 -0
- package/dist/src/ui/colors.js.map +1 -1
- package/dist/src/ui/commands/chatCommand.js +16 -0
- package/dist/src/ui/commands/chatCommand.js.map +1 -1
- package/dist/src/ui/commands/ideCommand.js +67 -31
- package/dist/src/ui/commands/ideCommand.js.map +1 -1
- package/dist/src/ui/commands/loggingCommand.d.ts +15 -0
- package/dist/src/ui/commands/loggingCommand.js +421 -0
- package/dist/src/ui/commands/loggingCommand.js.map +1 -0
- package/dist/src/ui/commands/privacyCommand.d.ts +3 -0
- package/dist/src/ui/commands/privacyCommand.js +6 -3
- package/dist/src/ui/commands/privacyCommand.js.map +1 -1
- package/dist/src/ui/commands/types.d.ts +14 -2
- package/dist/src/ui/commands/types.js.map +1 -1
- package/dist/src/ui/components/ContextUsageDisplay.js +14 -2
- package/dist/src/ui/components/ContextUsageDisplay.js.map +1 -1
- package/dist/src/ui/components/FolderTrustDialog.d.ts +16 -0
- package/dist/src/ui/components/FolderTrustDialog.js +38 -0
- package/dist/src/ui/components/FolderTrustDialog.js.map +1 -0
- package/dist/src/ui/components/Footer.d.ts +0 -1
- package/dist/src/ui/components/Footer.js +136 -16
- package/dist/src/ui/components/Footer.js.map +1 -1
- package/dist/src/ui/components/InputPrompt.js +32 -28
- package/dist/src/ui/components/InputPrompt.js.map +1 -1
- package/dist/src/ui/components/LoggingDialog.d.ts +37 -0
- package/dist/src/ui/components/LoggingDialog.js +155 -0
- package/dist/src/ui/components/LoggingDialog.js.map +1 -0
- package/dist/src/ui/components/MemoryUsageDisplay.js +6 -4
- package/dist/src/ui/components/MemoryUsageDisplay.js.map +1 -1
- package/dist/src/ui/components/ProviderDialog.js +100 -26
- package/dist/src/ui/components/ProviderDialog.js.map +1 -1
- package/dist/src/ui/components/ProviderModelDialog.js +99 -27
- package/dist/src/ui/components/ProviderModelDialog.js.map +1 -1
- package/dist/src/ui/components/TodoPanel.js +93 -18
- package/dist/src/ui/components/TodoPanel.js.map +1 -1
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js +85 -7
- package/dist/src/ui/components/messages/ToolConfirmationMessage.js.map +1 -1
- package/dist/src/ui/contexts/SettingsContext.d.ts +9 -0
- package/dist/src/ui/contexts/SettingsContext.js +15 -0
- package/dist/src/ui/contexts/SettingsContext.js.map +1 -0
- package/dist/src/ui/hooks/atCommandProcessor.js +21 -0
- package/dist/src/ui/hooks/atCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/slashCommandProcessor.d.ts +5 -1
- package/dist/src/ui/hooks/slashCommandProcessor.js +137 -112
- package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/useConsoleMessages.js +7 -0
- package/dist/src/ui/hooks/useConsoleMessages.js.map +1 -1
- package/dist/src/ui/hooks/useFolderTrust.d.ts +11 -0
- package/dist/src/ui/hooks/useFolderTrust.js +22 -0
- package/dist/src/ui/hooks/useFolderTrust.js.map +1 -0
- package/dist/src/ui/hooks/useGeminiStream.js +14 -3
- package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
- package/dist/src/ui/hooks/useResponsive.d.ts +14 -0
- package/dist/src/ui/hooks/useResponsive.js +19 -0
- package/dist/src/ui/hooks/useResponsive.js.map +1 -0
- package/dist/src/ui/hooks/useTodoContinuation.d.ts +31 -0
- package/dist/src/ui/hooks/useTodoContinuation.js +148 -0
- package/dist/src/ui/hooks/useTodoContinuation.js.map +1 -0
- package/dist/src/ui/hooks/useTodoContinuation.spec.d.ts +6 -0
- package/dist/src/ui/hooks/useTodoContinuation.spec.js +378 -0
- package/dist/src/ui/hooks/useTodoContinuation.spec.js.map +1 -0
- package/dist/src/ui/keyMatchers.d.ts +26 -0
- package/dist/src/ui/keyMatchers.js +68 -0
- package/dist/src/ui/keyMatchers.js.map +1 -0
- package/dist/src/ui/privacy/PrivacyNotice.js +10 -4
- package/dist/src/ui/privacy/PrivacyNotice.js.map +1 -1
- package/dist/src/ui/themes/semantic-resolver.d.ts +12 -0
- package/dist/src/ui/themes/semantic-resolver.js +32 -0
- package/dist/src/ui/themes/semantic-resolver.js.map +1 -0
- package/dist/src/ui/themes/semantic-tokens.d.ts +52 -0
- package/dist/src/ui/themes/semantic-tokens.js +7 -0
- package/dist/src/ui/themes/semantic-tokens.js.map +1 -0
- package/dist/src/ui/themes/theme-compat.d.ts +34 -0
- package/dist/src/ui/themes/theme-compat.js +65 -0
- package/dist/src/ui/themes/theme-compat.js.map +1 -0
- package/dist/src/ui/themes/theme-manager.d.ts +8 -0
- package/dist/src/ui/themes/theme-manager.js +18 -0
- package/dist/src/ui/themes/theme-manager.js.map +1 -1
- package/dist/src/ui/utils/CodeColorizer.d.ts +2 -1
- package/dist/src/ui/utils/CodeColorizer.js +4 -3
- package/dist/src/ui/utils/CodeColorizer.js.map +1 -1
- package/dist/src/ui/utils/MarkdownDisplay.js +4 -2
- package/dist/src/ui/utils/MarkdownDisplay.js.map +1 -1
- package/dist/src/ui/utils/responsive.d.ts +16 -0
- package/dist/src/ui/utils/responsive.js +111 -0
- package/dist/src/ui/utils/responsive.js.map +1 -0
- package/dist/src/utils/cleanup.d.ts +2 -2
- package/dist/src/utils/cleanup.js +2 -2
- package/dist/src/utils/cleanup.js.map +1 -1
- package/dist/src/utils/privacy/ConversationDataRedactor.d.ts +75 -0
- package/dist/src/utils/privacy/ConversationDataRedactor.js +412 -0
- package/dist/src/utils/privacy/ConversationDataRedactor.js.map +1 -0
- package/dist/src/utils/privacy/PrivacyManager.d.ts +58 -0
- package/dist/src/utils/privacy/PrivacyManager.js +133 -0
- package/dist/src/utils/privacy/PrivacyManager.js.map +1 -0
- package/dist/src/utils/sandbox.js +10 -0
- package/dist/src/utils/sandbox.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/dist/src/ui/components/IDEContextDetailDisplay.d.ts +0 -12
- package/dist/src/ui/components/IDEContextDetailDisplay.js +0 -30
- 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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"}
|
package/dist/src/ui/App.js
CHANGED
@@ -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,
|
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
|
-
|
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
|
485
|
+
if (keyMatchers[Command.SHOW_ERROR_DETAILS](key)) {
|
480
486
|
setShowErrorDetails((prev) => !prev);
|
481
487
|
}
|
482
|
-
else if (key
|
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
|
491
|
-
input === 'e' &&
|
496
|
+
else if (keyMatchers[Command.TOGGLE_IDE_CONTEXT_DETAIL](key) &&
|
492
497
|
config.getIdeMode() &&
|
493
498
|
ideContextState) {
|
494
|
-
|
499
|
+
// Show IDE status when in IDE mode and context is available.
|
500
|
+
handleSlashCommand('/ide status');
|
495
501
|
}
|
496
|
-
else if (
|
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 (
|
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
|
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
|
-
:
|
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 })) :
|
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, {})] })] }),
|
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
|