@vybestack/llxprt-code 0.10.0 → 0.11.0-nightly.260728.ffaa8d5d7
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/package.json +13 -13
- package/src/commands/mcp/add.ts +8 -4
- package/src/config/cliArgParser.ts +2 -0
- package/src/config/config.ts +2 -0
- package/src/config/configBuilder.ts +3 -0
- package/src/config/configError.ts +23 -0
- package/src/config/extensions/extensionEnablement.ts +62 -1
- package/src/config/interactiveContext.ts +2 -1
- package/src/config/intermediateConfig.ts +4 -0
- package/src/config/keyBindings.ts +29 -3
- package/src/config/policy.ts +7 -1
- package/src/config/postConfigRuntime.ts +20 -14
- package/src/config/settings-schema/schema-ui.ts +9 -0
- package/src/config/settingsLoader.ts +21 -17
- package/src/config/settingsSchema.ts +2 -2
- package/src/config/trustedFolders.ts +275 -58
- package/src/config/yargsOptions.ts +7 -0
- package/src/generated/git-commit.json +1 -1
- package/src/nonInteractiveCli.ts +1 -0
- package/src/nonInteractiveCliSupport.ts +171 -51
- package/src/runtime/interactiveToolScheduler.ts +6 -6
- package/src/services/BuiltinCommandLoader.ts +33 -25
- package/src/services/FileCommandLoader.ts +34 -7
- package/src/test-utils/async.ts +20 -0
- package/src/test-utils/render.tsx +10 -1
- package/src/ui/App.tsx +17 -10
- package/src/ui/AppContainerRuntime.tsx +7 -9
- package/src/ui/cliUiRuntime.ts +28 -0
- package/src/ui/commands/authCommand.ts +240 -3
- package/src/ui/commands/compressCommand.ts +9 -1
- package/src/ui/commands/directoryCommand.tsx +1 -1
- package/src/ui/commands/logoutCommand.ts +2 -2
- package/src/ui/commands/permissionsCommand.ts +77 -20
- package/src/ui/commands/policiesCommand.ts +6 -1
- package/src/ui/commands/quotaCommand.ts +501 -0
- package/src/ui/commands/statsCommand.ts +2 -2
- package/src/ui/commands/statsQuota.ts +1 -1
- package/src/ui/commands/subagentCommand.ts +59 -27
- package/src/ui/components/AuthDialog.tsx +3 -3
- package/src/ui/components/Composer.tsx +1 -0
- package/src/ui/components/DialogManager.tsx +9 -2
- package/src/ui/components/FolderTrustDialog.tsx +71 -60
- package/src/ui/components/PermissionsModifyTrustDialog.tsx +211 -146
- package/src/ui/components/ProfileCreateWizard/constants.ts +13 -1
- package/src/ui/components/QueuedMessagesPanel.tsx +388 -0
- package/src/ui/components/inputPromptHooks.ts +2 -0
- package/src/ui/components/inputPromptKeyHandlers.ts +14 -0
- package/src/ui/components/inputPromptTypes.ts +6 -0
- package/src/ui/components/messages/AiMessage.tsx +24 -12
- package/src/ui/components/messages/ToolMessage.tsx +26 -40
- package/src/ui/containers/AppContainer/builders/buildUIActions.ts +3 -1
- package/src/ui/containers/AppContainer/builders/buildUIState.ts +5 -4
- package/src/ui/containers/AppContainer/hooks/useAppBootstrap.ts +3 -33
- package/src/ui/containers/AppContainer/hooks/useAppDialogs.ts +2 -14
- package/src/ui/containers/AppContainer/hooks/useAppInput.ts +31 -25
- package/src/ui/containers/AppContainer/hooks/useAppLayout.ts +90 -60
- package/src/ui/containers/AppContainer/hooks/useDisplayPreferences.ts +10 -0
- package/src/ui/containers/AppContainer/hooks/useInputHandling.ts +3 -17
- package/src/ui/containers/AppContainer/hooks/useKeybindings.ts +51 -38
- package/src/ui/containers/AppContainer/hooks/useSteer.ts +51 -0
- package/src/ui/contexts/KeypressContext.tsx +13 -2
- package/src/ui/contexts/ShellCommandDisplayContext.tsx +103 -0
- package/src/ui/contexts/TodoContext.tsx +0 -13
- package/src/ui/contexts/TodoProvider.tsx +1 -34
- package/src/ui/contexts/UIActionsContext.tsx +2 -1
- package/src/ui/contexts/UIStateContext.tsx +3 -2
- package/src/ui/hooks/agentStream/streamUtils.ts +0 -24
- package/src/ui/hooks/agentStream/thoughtState.ts +110 -30
- package/src/ui/hooks/agentStream/types.ts +1 -0
- package/src/ui/hooks/agentStream/useAgentEventStream.ts +8 -17
- package/src/ui/hooks/agentStream/useAgentStream.ts +2 -2
- package/src/ui/hooks/agentStream/useAgentStreamLifecycle.ts +4 -5
- package/src/ui/hooks/agentStream/useAgentStreamOrchestration.ts +12 -5
- package/src/ui/hooks/agentStream/useQueuedSubmissions.ts +99 -0
- package/src/ui/hooks/agentStream/useStreamEventHandlers.ts +4 -13
- package/src/ui/hooks/agentStream/useStreamState.ts +60 -41
- package/src/ui/hooks/agentStream/useSubmitQuery.ts +284 -59
- package/src/ui/hooks/slashCommandProcessorSupport.ts +4 -0
- package/src/ui/hooks/useAgentStream-test-helpers.ts +1 -0
- package/src/ui/hooks/useAutoAcceptIndicator.ts +13 -0
- package/src/ui/hooks/useFolderTrust.ts +118 -81
- package/src/ui/hooks/useGitBranchName.ts +79 -33
- package/src/ui/hooks/useIdeTrustListener.ts +5 -19
- package/src/ui/hooks/usePermissionsModifyTrust.ts +223 -85
- package/src/ui/hooks/useReactToolScheduler.ts +13 -17
- package/src/ui/hooks/useTodoPausePreserver.ts +0 -55
- package/src/ui/layouts/DefaultAppLayout.tsx +2 -0
- package/src/ui/layouts/DefaultAppLayoutHelpers.tsx +37 -162
- package/src/ui/layouts/InlineContent.tsx +198 -0
- package/src/ui/trustDialogHelpers.ts +190 -0
- package/src/utils/cleanup-state.ts +115 -0
- package/src/utils/cleanup.ts +32 -34
- package/src/utils/sandbox-containers.ts +183 -53
- package/src/utils/sandbox-exec.ts +9 -3
- package/src/zed-integration/acp-terminal-shell-host.ts +112 -0
- package/src/zed-integration/acp-types.ts +35 -0
- package/src/zed-integration/fileSystemService.ts +1 -1
- package/src/zed-integration/runZedIntegration.ts +142 -0
- package/src/zed-integration/zed-agent-event-handler.ts +179 -0
- package/src/zed-integration/zed-agent-setup.ts +43 -0
- package/src/zed-integration/zed-command-registry.ts +167 -0
- package/src/zed-integration/zed-config-options.ts +280 -0
- package/src/zed-integration/zed-content-utils.ts +2 -2
- package/src/zed-integration/zed-helpers.ts +132 -0
- package/src/zed-integration/zed-initialize.ts +64 -0
- package/src/zed-integration/zed-plan-update.ts +20 -0
- package/src/zed-integration/zed-prompt-command.ts +77 -0
- package/src/zed-integration/zed-session-config.ts +119 -0
- package/src/zed-integration/zed-session-errors.ts +337 -0
- package/src/zed-integration/zed-session-events.ts +216 -0
- package/src/zed-integration/zed-session-info.ts +255 -0
- package/src/zed-integration/zed-session-lifecycle.ts +186 -0
- package/src/zed-integration/zed-session-listing.ts +153 -0
- package/src/zed-integration/zed-session-loader.ts +193 -0
- package/src/zed-integration/zed-session-pagination.ts +240 -0
- package/src/zed-integration/zed-session-replay.ts +564 -0
- package/src/zed-integration/zed-stream-batcher.ts +236 -0
- package/src/zed-integration/zed-terminal-manager.ts +416 -0
- package/src/zed-integration/zed-terminal-setup.ts +72 -0
- package/src/zed-integration/zed-test-helpers.ts +349 -4
- package/src/zed-integration/zed-tool-handler.ts +47 -5
- package/src/zed-integration/zedIntegration.ts +538 -587
- package/src/services/todo-continuation/todoContinuationService.ts +0 -610
- package/src/ui/containers/AppContainer/hooks/useIdeRestartHotkey.ts +0 -33
- package/src/ui/containers/AppContainer/hooks/useTodoContinuationFlow.ts +0 -160
- package/src/ui/hooks/useTodoContinuation.ts +0 -299
|
@@ -1,610 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2025 Vybestack LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type { Config, Todo } from '@vybestack/llxprt-code-core';
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Test mock config interface for unit tests
|
|
11
|
-
*/
|
|
12
|
-
interface MockConfig {
|
|
13
|
-
continuationEnabled?: boolean;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
type ContinuationConfig = Config | MockConfig | null | undefined;
|
|
17
|
-
|
|
18
|
-
interface ConfigWithEphemeralSettings {
|
|
19
|
-
getEphemeralSetting(key: string): unknown;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Type guard to check if config has continuation enabled property (test mock)
|
|
24
|
-
*/
|
|
25
|
-
function isMockConfig(config: unknown): config is MockConfig {
|
|
26
|
-
return (
|
|
27
|
-
typeof config === 'object' &&
|
|
28
|
-
config !== null &&
|
|
29
|
-
'continuationEnabled' in config
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function hasEphemeralSettings(
|
|
34
|
-
config: unknown,
|
|
35
|
-
): config is ConfigWithEphemeralSettings {
|
|
36
|
-
return (
|
|
37
|
-
typeof config === 'object' &&
|
|
38
|
-
config !== null &&
|
|
39
|
-
'getEphemeralSetting' in config &&
|
|
40
|
-
typeof config.getEphemeralSetting === 'function'
|
|
41
|
-
);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
function getContinuationEnabled(config: ContinuationConfig): unknown {
|
|
45
|
-
if (config === null || config === undefined) {
|
|
46
|
-
return true;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (isMockConfig(config)) {
|
|
50
|
-
return config.continuationEnabled;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (hasEphemeralSettings(config)) {
|
|
54
|
-
return config.getEphemeralSetting('todo-continuation');
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return true;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* Configuration for generating continuation prompts
|
|
62
|
-
*/
|
|
63
|
-
export interface ContinuationPromptConfig {
|
|
64
|
-
readonly taskDescription: string;
|
|
65
|
-
readonly isYoloMode: boolean;
|
|
66
|
-
readonly attemptCount?: number;
|
|
67
|
-
readonly previousFailure?: string;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* Context information for evaluating continuation conditions
|
|
72
|
-
*/
|
|
73
|
-
export interface ContinuationContext {
|
|
74
|
-
readonly todos: readonly Todo[];
|
|
75
|
-
readonly hadToolCalls: boolean;
|
|
76
|
-
readonly isResponding: boolean;
|
|
77
|
-
readonly config: Config;
|
|
78
|
-
readonly currentState: ContinuationState;
|
|
79
|
-
readonly todoPaused?: boolean;
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* Result of evaluating continuation conditions
|
|
84
|
-
*/
|
|
85
|
-
export interface ContinuationEvaluation {
|
|
86
|
-
readonly shouldContinue: boolean;
|
|
87
|
-
readonly reason: string;
|
|
88
|
-
readonly activeTodo?: Todo;
|
|
89
|
-
readonly conditions: ConditionSet;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* State tracking for continuation attempts
|
|
94
|
-
*/
|
|
95
|
-
export interface ContinuationState {
|
|
96
|
-
isActive: boolean;
|
|
97
|
-
attemptCount: number;
|
|
98
|
-
taskDescription?: string;
|
|
99
|
-
lastPromptTime?: Date;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* Set of conditions evaluated for continuation
|
|
104
|
-
*/
|
|
105
|
-
export interface ConditionSet {
|
|
106
|
-
readonly hasActiveTodos: boolean;
|
|
107
|
-
readonly noToolCallsMade: boolean;
|
|
108
|
-
readonly continuationEnabled: boolean;
|
|
109
|
-
readonly notCurrentlyContinuing: boolean;
|
|
110
|
-
readonly withinAttemptLimits: boolean;
|
|
111
|
-
readonly withinTimeConstraints: boolean;
|
|
112
|
-
readonly todoPaused: boolean;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Template structure for continuation prompts
|
|
117
|
-
*/
|
|
118
|
-
export interface ContinuationPromptTemplates {
|
|
119
|
-
readonly standard: {
|
|
120
|
-
readonly base: string;
|
|
121
|
-
readonly retry: string;
|
|
122
|
-
};
|
|
123
|
-
readonly yolo: {
|
|
124
|
-
readonly base: string;
|
|
125
|
-
readonly retry: string;
|
|
126
|
-
readonly urgent: string;
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Service responsible for generating continuation prompts and managing continuation logic
|
|
132
|
-
*/
|
|
133
|
-
export class TodoContinuationService {
|
|
134
|
-
private static readonly MAX_CONTINUATION_ATTEMPTS = 3;
|
|
135
|
-
private static readonly MIN_CONTINUATION_INTERVAL_MS = 1000;
|
|
136
|
-
// Future enhancement: Add timeout functionality
|
|
137
|
-
// private static readonly CONTINUATION_TIMEOUT_MS = 30000;
|
|
138
|
-
private static readonly MAX_TASK_DESCRIPTION_LENGTH = 200;
|
|
139
|
-
// Matches a leading list marker (-, *, or +) with trailing spaces. The
|
|
140
|
-
// pattern is passed to RegExp via an identifier so it is not a static literal
|
|
141
|
-
// flagged by sonarjs/regular-expr.
|
|
142
|
-
private static readonly LIST_MARKER_PATTERN = '^[-*+]\\s*';
|
|
143
|
-
private static readonly LIST_MARKER_REGEX = new RegExp(
|
|
144
|
-
TodoContinuationService.LIST_MARKER_PATTERN,
|
|
145
|
-
);
|
|
146
|
-
|
|
147
|
-
/**
|
|
148
|
-
* Generates a continuation prompt based on the provided configuration
|
|
149
|
-
* @param config Configuration for prompt generation
|
|
150
|
-
* @returns Formatted continuation prompt string
|
|
151
|
-
*/
|
|
152
|
-
generateContinuationPrompt(
|
|
153
|
-
config: ContinuationPromptConfig | null | undefined,
|
|
154
|
-
): string {
|
|
155
|
-
if (config === null || config === undefined) {
|
|
156
|
-
throw new Error('Configuration is required');
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const taskDescription = this.truncateTaskDescription(
|
|
160
|
-
config.taskDescription,
|
|
161
|
-
);
|
|
162
|
-
|
|
163
|
-
if (config.isYoloMode) {
|
|
164
|
-
return this.generateYoloModePrompt(
|
|
165
|
-
taskDescription,
|
|
166
|
-
config.attemptCount,
|
|
167
|
-
config.previousFailure,
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
return this.generateStandardPrompt(
|
|
171
|
-
taskDescription,
|
|
172
|
-
config.attemptCount,
|
|
173
|
-
config.previousFailure,
|
|
174
|
-
);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* Evaluates whether continuation should occur based on current conditions
|
|
179
|
-
* @param context Current continuation context
|
|
180
|
-
* @returns Evaluation result with decision and reasoning
|
|
181
|
-
*/
|
|
182
|
-
checkContinuationConditions(
|
|
183
|
-
context: ContinuationContext | null | undefined,
|
|
184
|
-
): ContinuationEvaluation {
|
|
185
|
-
if (context === null || context === undefined) {
|
|
186
|
-
throw new Error('Context is required');
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
const conditions = this.evaluateAllConditions(context);
|
|
190
|
-
|
|
191
|
-
// Check each condition and provide specific feedback
|
|
192
|
-
if (!conditions.continuationEnabled) {
|
|
193
|
-
return {
|
|
194
|
-
shouldContinue: false,
|
|
195
|
-
reason: 'Todo continuation is disabled in ephemeral settings',
|
|
196
|
-
conditions,
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (!conditions.hasActiveTodos) {
|
|
201
|
-
return {
|
|
202
|
-
shouldContinue: false,
|
|
203
|
-
reason: 'No active todos found (pending or in_progress)',
|
|
204
|
-
conditions,
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (context.todoPaused === true) {
|
|
209
|
-
return {
|
|
210
|
-
shouldContinue: false,
|
|
211
|
-
reason: 'Todo continuation paused by todo_pause tool',
|
|
212
|
-
conditions,
|
|
213
|
-
};
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (!conditions.noToolCallsMade) {
|
|
217
|
-
return {
|
|
218
|
-
shouldContinue: false,
|
|
219
|
-
reason: 'Tool calls were made during stream - no continuation needed',
|
|
220
|
-
conditions,
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
if (!conditions.notCurrentlyContinuing) {
|
|
225
|
-
return {
|
|
226
|
-
shouldContinue: false,
|
|
227
|
-
reason: 'Already continuing task',
|
|
228
|
-
conditions,
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
if (!conditions.withinAttemptLimits) {
|
|
233
|
-
return {
|
|
234
|
-
shouldContinue: false,
|
|
235
|
-
reason: 'Continuation attempt limit reached',
|
|
236
|
-
conditions,
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
if (!conditions.withinTimeConstraints) {
|
|
241
|
-
return {
|
|
242
|
-
shouldContinue: false,
|
|
243
|
-
reason: 'Time constraint violated - too soon since last attempt',
|
|
244
|
-
conditions,
|
|
245
|
-
};
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
// Find the active task to continue
|
|
249
|
-
const activeTodo = this.findBestActiveTodo(context.todos);
|
|
250
|
-
if (!activeTodo) {
|
|
251
|
-
return {
|
|
252
|
-
shouldContinue: false,
|
|
253
|
-
reason: 'No suitable active todo found',
|
|
254
|
-
conditions,
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
|
|
258
|
-
// All conditions met
|
|
259
|
-
return {
|
|
260
|
-
shouldContinue: true,
|
|
261
|
-
reason: 'Active todo found and all continuation conditions satisfied',
|
|
262
|
-
conditions,
|
|
263
|
-
activeTodo,
|
|
264
|
-
};
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* Formats a task item's content into a task description
|
|
269
|
-
* @param taskItem Task item to format
|
|
270
|
-
* @returns Formatted task description string
|
|
271
|
-
*/
|
|
272
|
-
formatTaskDescription(taskItem: Todo | null | undefined): string {
|
|
273
|
-
if (
|
|
274
|
-
taskItem === null ||
|
|
275
|
-
taskItem === undefined ||
|
|
276
|
-
taskItem.content.length === 0
|
|
277
|
-
) {
|
|
278
|
-
return 'Complete task';
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
let description = taskItem.content.trim();
|
|
282
|
-
|
|
283
|
-
if (description.length === 0) {
|
|
284
|
-
return 'Complete task';
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
// Clean up formatting
|
|
288
|
-
// Static regex for whitespace normalization - no dynamic parts
|
|
289
|
-
|
|
290
|
-
description = description.replace(/\s+/g, ' '); // Normalize whitespace
|
|
291
|
-
description = description.replace(
|
|
292
|
-
TodoContinuationService.LIST_MARKER_REGEX,
|
|
293
|
-
'',
|
|
294
|
-
); // Remove list markers
|
|
295
|
-
|
|
296
|
-
// Truncate if too long
|
|
297
|
-
if (
|
|
298
|
-
description.length > TodoContinuationService.MAX_TASK_DESCRIPTION_LENGTH
|
|
299
|
-
) {
|
|
300
|
-
description =
|
|
301
|
-
description.substring(
|
|
302
|
-
0,
|
|
303
|
-
TodoContinuationService.MAX_TASK_DESCRIPTION_LENGTH - 3,
|
|
304
|
-
) + '...';
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
return description;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* Checks if continuation should be allowed based on configuration and state
|
|
312
|
-
* @param config Application configuration
|
|
313
|
-
* @param state Current continuation state
|
|
314
|
-
* @returns Whether continuation is allowed
|
|
315
|
-
*/
|
|
316
|
-
shouldAllowContinuation(
|
|
317
|
-
config: ContinuationConfig,
|
|
318
|
-
state: ContinuationState,
|
|
319
|
-
): boolean {
|
|
320
|
-
// Check ephemeral setting safely
|
|
321
|
-
const continuationEnabled = getContinuationEnabled(config);
|
|
322
|
-
|
|
323
|
-
if (continuationEnabled === false) {
|
|
324
|
-
return false;
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Check attempt limits
|
|
328
|
-
if (
|
|
329
|
-
state.attemptCount >= TodoContinuationService.MAX_CONTINUATION_ATTEMPTS
|
|
330
|
-
) {
|
|
331
|
-
return false;
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
// Check time constraints
|
|
335
|
-
if (state.lastPromptTime !== undefined) {
|
|
336
|
-
const timeSinceLastPrompt = Date.now() - state.lastPromptTime.getTime();
|
|
337
|
-
if (
|
|
338
|
-
timeSinceLastPrompt <
|
|
339
|
-
TodoContinuationService.MIN_CONTINUATION_INTERVAL_MS
|
|
340
|
-
) {
|
|
341
|
-
return false;
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
return true;
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
/**
|
|
349
|
-
* Creates a new, empty continuation state
|
|
350
|
-
* @returns Initial continuation state
|
|
351
|
-
*/
|
|
352
|
-
createContinuationState(): ContinuationState {
|
|
353
|
-
return {
|
|
354
|
-
isActive: false,
|
|
355
|
-
attemptCount: 0,
|
|
356
|
-
taskDescription: undefined,
|
|
357
|
-
lastPromptTime: undefined,
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
// Additional method mentioned in requirements but not in original pseudocode
|
|
362
|
-
/**
|
|
363
|
-
* Checks whether continuation should occur based on settings, todos, and tool calls
|
|
364
|
-
* @param settings Application settings/config
|
|
365
|
-
* @param hasActiveTodos Whether there are active todos
|
|
366
|
-
* @param hasToolCalls Whether tool calls were made
|
|
367
|
-
* @returns Whether continuation should proceed
|
|
368
|
-
*/
|
|
369
|
-
shouldContinue(
|
|
370
|
-
settings: ContinuationConfig,
|
|
371
|
-
hasActiveTodos: boolean,
|
|
372
|
-
hasToolCalls: boolean,
|
|
373
|
-
): boolean {
|
|
374
|
-
// Don't continue if tool calls were made
|
|
375
|
-
if (hasToolCalls) {
|
|
376
|
-
return false;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
// Don't continue if no active todos
|
|
380
|
-
if (!hasActiveTodos) {
|
|
381
|
-
return false;
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
// Check if continuation is enabled safely
|
|
385
|
-
const continuationEnabled = getContinuationEnabled(settings);
|
|
386
|
-
|
|
387
|
-
return continuationEnabled !== false;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
// Additional method mentioned in requirements but not in original pseudocode
|
|
391
|
-
/**
|
|
392
|
-
* Formats a prompt for task description and YOLO mode
|
|
393
|
-
* @param taskDescription Description of the task to continue
|
|
394
|
-
* @param isYoloMode Whether YOLO mode is enabled
|
|
395
|
-
* @returns Formatted prompt string
|
|
396
|
-
*/
|
|
397
|
-
formatPrompt(taskDescription: string, isYoloMode: boolean): string {
|
|
398
|
-
const truncatedDescription = this.truncateTaskDescription(taskDescription);
|
|
399
|
-
|
|
400
|
-
if (isYoloMode) {
|
|
401
|
-
return this.generateYoloModePrompt(truncatedDescription);
|
|
402
|
-
}
|
|
403
|
-
return this.generateStandardPrompt(truncatedDescription);
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
/**
|
|
407
|
-
* Private method to truncate task descriptions to acceptable length
|
|
408
|
-
* @param description Task description to truncate
|
|
409
|
-
* @returns Truncated description
|
|
410
|
-
*/
|
|
411
|
-
private truncateTaskDescription(description: string): string {
|
|
412
|
-
if (!description || description.length === 0) {
|
|
413
|
-
return 'Complete task';
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
if (
|
|
417
|
-
description.length <= TodoContinuationService.MAX_TASK_DESCRIPTION_LENGTH
|
|
418
|
-
) {
|
|
419
|
-
return description;
|
|
420
|
-
}
|
|
421
|
-
|
|
422
|
-
// Try to truncate at word boundary
|
|
423
|
-
const truncated = description.substring(
|
|
424
|
-
0,
|
|
425
|
-
TodoContinuationService.MAX_TASK_DESCRIPTION_LENGTH,
|
|
426
|
-
);
|
|
427
|
-
const lastSpaceIndex = truncated.lastIndexOf(' ');
|
|
428
|
-
|
|
429
|
-
if (
|
|
430
|
-
lastSpaceIndex >
|
|
431
|
-
TodoContinuationService.MAX_TASK_DESCRIPTION_LENGTH * 0.8
|
|
432
|
-
) {
|
|
433
|
-
// Good word boundary found
|
|
434
|
-
return truncated.substring(0, lastSpaceIndex) + '...';
|
|
435
|
-
}
|
|
436
|
-
// No good word boundary, hard truncate
|
|
437
|
-
return (
|
|
438
|
-
truncated.substring(
|
|
439
|
-
0,
|
|
440
|
-
TodoContinuationService.MAX_TASK_DESCRIPTION_LENGTH - 3,
|
|
441
|
-
) + '...'
|
|
442
|
-
);
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
/**
|
|
446
|
-
* Private method to generate standard continuation prompt
|
|
447
|
-
* @param taskDescription Task description
|
|
448
|
-
* @param attemptCount Optional attempt count
|
|
449
|
-
* @returns Standard prompt string
|
|
450
|
-
*/
|
|
451
|
-
private generateStandardPrompt(
|
|
452
|
-
taskDescription: string,
|
|
453
|
-
attemptCount?: number,
|
|
454
|
-
previousFailure?: string,
|
|
455
|
-
): string {
|
|
456
|
-
const basePrompt = [
|
|
457
|
-
'You have an active task that needs completion:',
|
|
458
|
-
`'${taskDescription}'`,
|
|
459
|
-
'',
|
|
460
|
-
"Continue working on this task. Call todo_pause('reason') ONLY if there's an error preventing you from continuing.",
|
|
461
|
-
'',
|
|
462
|
-
'Remember to:',
|
|
463
|
-
'- Focus on the specific task described',
|
|
464
|
-
'- Make concrete progress toward completion',
|
|
465
|
-
'- Update the task status when appropriate',
|
|
466
|
-
'- Use todo_pause() if you encounter blockers',
|
|
467
|
-
].join('\n');
|
|
468
|
-
|
|
469
|
-
let result = basePrompt;
|
|
470
|
-
|
|
471
|
-
if (previousFailure !== undefined && previousFailure.length > 0) {
|
|
472
|
-
result += `\n\nPrevious failure information: ${previousFailure}`;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
if (attemptCount !== undefined && attemptCount > 1) {
|
|
476
|
-
const retryNote = `\n\nNote: This is continuation attempt #${attemptCount}. Please make sure to take concrete action.`;
|
|
477
|
-
result += retryNote;
|
|
478
|
-
}
|
|
479
|
-
|
|
480
|
-
return result;
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
/**
|
|
484
|
-
* Private method to generate YOLO mode continuation prompt
|
|
485
|
-
* @param taskDescription Task description
|
|
486
|
-
* @param attemptCount Optional attempt count
|
|
487
|
-
* @returns YOLO mode prompt string
|
|
488
|
-
*/
|
|
489
|
-
private generateYoloModePrompt(
|
|
490
|
-
taskDescription: string,
|
|
491
|
-
attemptCount?: number,
|
|
492
|
-
previousFailure?: string,
|
|
493
|
-
): string {
|
|
494
|
-
const basePrompt = [
|
|
495
|
-
'CONTINUE TASK IMMEDIATELY:',
|
|
496
|
-
`'${taskDescription}'`,
|
|
497
|
-
'',
|
|
498
|
-
"You MUST continue working on this task. Call todo_pause('reason') ONLY if there's an error preventing you from proceeding.",
|
|
499
|
-
'',
|
|
500
|
-
'YOLO MODE - Take action now:',
|
|
501
|
-
'- Execute the task without asking for confirmation',
|
|
502
|
-
'- Make concrete progress immediately',
|
|
503
|
-
'- Only pause if there are actual blocking errors',
|
|
504
|
-
'- Update task status when complete',
|
|
505
|
-
].join('\n');
|
|
506
|
-
|
|
507
|
-
let result = basePrompt;
|
|
508
|
-
|
|
509
|
-
if (previousFailure !== undefined && previousFailure.length > 0) {
|
|
510
|
-
result += `\n\nPrevious failure information: ${previousFailure}`;
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
if (attemptCount !== undefined && attemptCount > 1) {
|
|
514
|
-
const urgentRetry = `\n\nATTEMPT #${attemptCount} - YOU MUST TAKE ACTION NOW. No more analysis, proceed with execution.`;
|
|
515
|
-
result += urgentRetry;
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
return result;
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
/**
|
|
522
|
-
* Private method to evaluate all continuation conditions
|
|
523
|
-
* @param context Continuation context
|
|
524
|
-
* @returns Evaluated condition set
|
|
525
|
-
*/
|
|
526
|
-
private evaluateAllConditions(context: ContinuationContext): ConditionSet {
|
|
527
|
-
// Safely get ephemeral setting with fallback
|
|
528
|
-
const continuationSetting = getContinuationEnabled(context.config);
|
|
529
|
-
|
|
530
|
-
const hasActiveTodos = this.hasAnyActiveTodos(context.todos);
|
|
531
|
-
const todoPaused = context.todoPaused === true;
|
|
532
|
-
const hadBlockingToolCalls =
|
|
533
|
-
context.hadToolCalls && (todoPaused || !hasActiveTodos);
|
|
534
|
-
|
|
535
|
-
return {
|
|
536
|
-
hasActiveTodos,
|
|
537
|
-
noToolCallsMade: !hadBlockingToolCalls,
|
|
538
|
-
continuationEnabled: continuationSetting !== false,
|
|
539
|
-
notCurrentlyContinuing: !context.currentState.isActive,
|
|
540
|
-
withinAttemptLimits:
|
|
541
|
-
context.currentState.attemptCount <
|
|
542
|
-
TodoContinuationService.MAX_CONTINUATION_ATTEMPTS,
|
|
543
|
-
withinTimeConstraints: this.checkTimeConstraints(
|
|
544
|
-
context.currentState.lastPromptTime,
|
|
545
|
-
),
|
|
546
|
-
todoPaused,
|
|
547
|
-
};
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
/**
|
|
551
|
-
* Private method to check if there are any active todos
|
|
552
|
-
* @param todos Array of todos to check
|
|
553
|
-
* @returns Whether active todos exist
|
|
554
|
-
*/
|
|
555
|
-
private hasAnyActiveTodos(todos: readonly Todo[]): boolean {
|
|
556
|
-
return todos.some(
|
|
557
|
-
(todo) => todo.status === 'pending' || todo.status === 'in_progress',
|
|
558
|
-
);
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
/**
|
|
562
|
-
* Private method to find the best active task to continue
|
|
563
|
-
* @param todos Array of tasks to search
|
|
564
|
-
* @returns Best active task or undefined
|
|
565
|
-
*/
|
|
566
|
-
private findBestActiveTodo(todos: readonly Todo[]): Todo | undefined {
|
|
567
|
-
// First: Find in_progress todos (should be max 1)
|
|
568
|
-
const inProgressTodos = todos.filter(
|
|
569
|
-
(todo) => todo.status === 'in_progress',
|
|
570
|
-
);
|
|
571
|
-
if (inProgressTodos.length > 0) {
|
|
572
|
-
return inProgressTodos[0];
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
// Second: Find pending todos, sort alphabetically by content
|
|
576
|
-
const pendingTodos = todos.filter((todo) => todo.status === 'pending');
|
|
577
|
-
if (pendingTodos.length > 0) {
|
|
578
|
-
// Sort alphabetically by content
|
|
579
|
-
pendingTodos.sort((a, b) => a.content.localeCompare(b.content));
|
|
580
|
-
return pendingTodos[0];
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
return undefined;
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
/**
|
|
587
|
-
* Private method to check time constraints for continuation
|
|
588
|
-
* @param lastPromptTime Time of last continuation prompt
|
|
589
|
-
* @returns Whether time constraints are satisfied
|
|
590
|
-
*/
|
|
591
|
-
private checkTimeConstraints(lastPromptTime?: Date): boolean {
|
|
592
|
-
if (lastPromptTime === undefined) {
|
|
593
|
-
return true; // No previous attempt, allowed
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
const timeSinceLastPrompt = Date.now() - lastPromptTime.getTime();
|
|
597
|
-
return (
|
|
598
|
-
timeSinceLastPrompt >=
|
|
599
|
-
TodoContinuationService.MIN_CONTINUATION_INTERVAL_MS
|
|
600
|
-
);
|
|
601
|
-
}
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
/**
|
|
605
|
-
* Factory function to create a new TodoContinuationService instance
|
|
606
|
-
* @returns New service instance
|
|
607
|
-
*/
|
|
608
|
-
export function createTodoContinuationService(): TodoContinuationService {
|
|
609
|
-
return new TodoContinuationService();
|
|
610
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @license
|
|
3
|
-
* Copyright 2025 Vybestack LLC
|
|
4
|
-
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import process from 'node:process';
|
|
8
|
-
import { useKeypress } from '../../../hooks/useKeypress.js';
|
|
9
|
-
|
|
10
|
-
interface UseIdeRestartHotkeyParams {
|
|
11
|
-
isActive: boolean;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* @hook useIdeRestartHotkey
|
|
16
|
-
* @description Exits process when restart prompt is active and user presses R
|
|
17
|
-
* @inputs isActive
|
|
18
|
-
* @outputs void
|
|
19
|
-
* @sideEffects Registers keypress handler
|
|
20
|
-
* @cleanup useKeypress handles cleanup
|
|
21
|
-
*/
|
|
22
|
-
export function useIdeRestartHotkey({
|
|
23
|
-
isActive,
|
|
24
|
-
}: UseIdeRestartHotkeyParams): void {
|
|
25
|
-
useKeypress(
|
|
26
|
-
(key) => {
|
|
27
|
-
if (key.name === 'r' || key.name === 'R') {
|
|
28
|
-
process.exit(0);
|
|
29
|
-
}
|
|
30
|
-
},
|
|
31
|
-
{ isActive },
|
|
32
|
-
);
|
|
33
|
-
}
|