@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
|
@@ -23,6 +23,7 @@ import type {
|
|
|
23
23
|
} from '@vybestack/llxprt-code-core';
|
|
24
24
|
import type { ToolInfo } from '@vybestack/llxprt-code-agents';
|
|
25
25
|
import type { SlashCommandRuntime } from '../../../cliUiRuntime.js';
|
|
26
|
+
import type { QueuedSubmission } from '../../../hooks/agentStream/types.js';
|
|
26
27
|
import type { SlashCommand, CommandContext } from '../../../commands/types.js';
|
|
27
28
|
import type { LoadedSettings } from '../../../../config/settings.js';
|
|
28
29
|
import type {
|
|
@@ -135,7 +136,6 @@ export interface UIStateParams {
|
|
|
135
136
|
ctrlCPressedOnce: boolean;
|
|
136
137
|
ctrlDPressedOnce: boolean;
|
|
137
138
|
showEscapePrompt: boolean;
|
|
138
|
-
showIdeRestartPrompt: boolean;
|
|
139
139
|
quittingMessages: HistoryItem[] | null;
|
|
140
140
|
|
|
141
141
|
// Display options
|
|
@@ -143,6 +143,8 @@ export interface UIStateParams {
|
|
|
143
143
|
showErrorDetails: boolean;
|
|
144
144
|
showToolDescriptions: boolean;
|
|
145
145
|
isTodoPanelCollapsed: boolean;
|
|
146
|
+
isQueuedMessagesPanelCollapsed: boolean;
|
|
147
|
+
queuedSubmissions: readonly QueuedSubmission[];
|
|
146
148
|
isNarrow: boolean;
|
|
147
149
|
vimModeEnabled: boolean;
|
|
148
150
|
vimMode: string | undefined;
|
|
@@ -195,7 +197,6 @@ export interface UIStateParams {
|
|
|
195
197
|
currentIDE: IdeInfo | undefined;
|
|
196
198
|
|
|
197
199
|
// Trust
|
|
198
|
-
isRestarting: boolean;
|
|
199
200
|
isTrustedFolder: boolean;
|
|
200
201
|
|
|
201
202
|
// Welcome onboarding
|
|
@@ -316,7 +317,6 @@ function buildConfirmationAndExit(p: UIStateParams) {
|
|
|
316
317
|
ctrlCPressedOnce: p.ctrlCPressedOnce,
|
|
317
318
|
ctrlDPressedOnce: p.ctrlDPressedOnce,
|
|
318
319
|
showEscapePrompt: p.showEscapePrompt,
|
|
319
|
-
showIdeRestartPrompt: p.showIdeRestartPrompt,
|
|
320
320
|
quittingMessages: p.quittingMessages,
|
|
321
321
|
};
|
|
322
322
|
}
|
|
@@ -327,6 +327,8 @@ function buildDisplayAndContext(p: UIStateParams) {
|
|
|
327
327
|
showErrorDetails: p.showErrorDetails,
|
|
328
328
|
showToolDescriptions: p.showToolDescriptions,
|
|
329
329
|
isTodoPanelCollapsed: p.isTodoPanelCollapsed,
|
|
330
|
+
isQueuedMessagesPanelCollapsed: p.isQueuedMessagesPanelCollapsed,
|
|
331
|
+
queuedSubmissions: p.queuedSubmissions,
|
|
330
332
|
isNarrow: p.isNarrow,
|
|
331
333
|
vimModeEnabled: p.vimModeEnabled,
|
|
332
334
|
vimMode: p.vimMode,
|
|
@@ -365,7 +367,6 @@ function buildProcessingAndCommands(p: UIStateParams) {
|
|
|
365
367
|
commandContext: p.commandContext,
|
|
366
368
|
shouldShowIdePrompt: p.shouldShowIdePrompt,
|
|
367
369
|
currentIDE: p.currentIDE,
|
|
368
|
-
isRestarting: p.isRestarting,
|
|
369
370
|
isTrustedFolder: p.isTrustedFolder,
|
|
370
371
|
};
|
|
371
372
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type React from 'react';
|
|
8
|
-
import {
|
|
8
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
9
9
|
import { useStdin, useStdout } from 'ink';
|
|
10
10
|
import { useResponsive } from '../../../hooks/useResponsive.js';
|
|
11
11
|
import { useBracketedPaste } from '../../../hooks/useBracketedPaste.js';
|
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
} from '../../../../constants/historyLimits.js';
|
|
19
19
|
import { useHistory } from '../../../hooks/useHistoryManager.js';
|
|
20
20
|
import { useMemoryMonitor } from '../../../hooks/useMemoryMonitor.js';
|
|
21
|
-
import { TodoPausePreserver } from '../../../hooks/useTodoPausePreserver.js';
|
|
22
21
|
import {
|
|
23
22
|
type IContent,
|
|
24
23
|
type IdeInfo,
|
|
@@ -41,7 +40,6 @@ import { registerCleanup } from '../../../../utils/cleanup.js';
|
|
|
41
40
|
import type { Agent } from '@vybestack/llxprt-code-agents';
|
|
42
41
|
import type { LoadedSettings } from '../../../../config/settings.js';
|
|
43
42
|
import type { HistoryItem } from '../../../types.js';
|
|
44
|
-
import type { TodoContinuationHook } from './useTodoContinuationFlow.js';
|
|
45
43
|
import type {
|
|
46
44
|
AgentClientSource,
|
|
47
45
|
StreamRuntime,
|
|
@@ -106,13 +104,6 @@ export interface AppBootstrapResult {
|
|
|
106
104
|
tokenMetrics: ReturnType<typeof useTokenMetricsTracking>['tokenMetrics'];
|
|
107
105
|
todos: ReturnType<typeof useTodoContext>['todos'];
|
|
108
106
|
updateTodos: ReturnType<typeof useTodoContext>['updateTodos'];
|
|
109
|
-
todoPauseController: TodoPausePreserver;
|
|
110
|
-
todoContinuationRef: React.MutableRefObject<Pick<
|
|
111
|
-
TodoContinuationHook,
|
|
112
|
-
'handleTodoPause' | 'clearPause'
|
|
113
|
-
> | null>;
|
|
114
|
-
hadToolCallsRef: React.MutableRefObject<boolean>;
|
|
115
|
-
registerTodoPause: () => void;
|
|
116
107
|
recordingIntegrationRef: React.MutableRefObject<RecordingIntegration | null>;
|
|
117
108
|
recordingSwapCallbacks: ReturnType<
|
|
118
109
|
typeof useRecordingInfrastructure
|
|
@@ -192,27 +183,10 @@ function useBootstrapHistory(props: AppBootstrapProps) {
|
|
|
192
183
|
};
|
|
193
184
|
}
|
|
194
185
|
|
|
195
|
-
/** Initializes task-list state
|
|
186
|
+
/** Initializes task-list state */
|
|
196
187
|
function useBootstrapTodo() {
|
|
197
188
|
const { todos, updateTodos } = useTodoContext();
|
|
198
|
-
|
|
199
|
-
const todoContinuationRef = useRef<Pick<
|
|
200
|
-
TodoContinuationHook,
|
|
201
|
-
'handleTodoPause' | 'clearPause'
|
|
202
|
-
> | null>(null);
|
|
203
|
-
const hadToolCallsRef = useRef<boolean>(false);
|
|
204
|
-
const registerTodoPause = useCallback(() => {
|
|
205
|
-
todoPauseController.registerTodoPause();
|
|
206
|
-
todoContinuationRef.current?.handleTodoPause('paused by model');
|
|
207
|
-
}, [todoPauseController]);
|
|
208
|
-
return {
|
|
209
|
-
todos,
|
|
210
|
-
updateTodos,
|
|
211
|
-
todoPauseController,
|
|
212
|
-
todoContinuationRef,
|
|
213
|
-
hadToolCallsRef,
|
|
214
|
-
registerTodoPause,
|
|
215
|
-
};
|
|
189
|
+
return { todos, updateTodos };
|
|
216
190
|
}
|
|
217
191
|
|
|
218
192
|
/** Initializes recording, IDE prompt, messages, and token metrics */
|
|
@@ -324,10 +298,6 @@ export function useAppBootstrap(props: AppBootstrapProps): AppBootstrapResult {
|
|
|
324
298
|
stdout: h.stdout,
|
|
325
299
|
todos: t.todos,
|
|
326
300
|
updateTodos: t.updateTodos,
|
|
327
|
-
todoPauseController: t.todoPauseController,
|
|
328
|
-
todoContinuationRef: t.todoContinuationRef,
|
|
329
|
-
hadToolCallsRef: t.hadToolCallsRef,
|
|
330
|
-
registerTodoPause: t.registerTodoPause,
|
|
331
301
|
recordingIntegrationRef: e.recordingIntegrationRef,
|
|
332
302
|
recordingSwapCallbacks: e.recordingSwapCallbacks,
|
|
333
303
|
idePromptAnswered: e.idePromptAnswered,
|
|
@@ -11,7 +11,6 @@ import { useThemeCommand } from '../../../hooks/useThemeCommand.js';
|
|
|
11
11
|
import { useAuthCommand } from '../../../hooks/useAuthCommand.js';
|
|
12
12
|
import { useFolderTrust } from '../../../hooks/useFolderTrust.js';
|
|
13
13
|
import { useWelcomeOnboarding } from '../../../hooks/useWelcomeOnboarding.js';
|
|
14
|
-
import { useIdeTrustListener } from '../../../hooks/useIdeTrustListener.js';
|
|
15
14
|
import { useEditorSettings } from '../../../hooks/useEditorSettings.js';
|
|
16
15
|
import { useExtensionUpdates } from '../../../hooks/useExtensionUpdates.js';
|
|
17
16
|
import { useOAuthOrchestration } from '../../../hooks/useOAuthOrchestration.js';
|
|
@@ -27,7 +26,6 @@ import { useDisplayPreferences } from './useDisplayPreferences.js';
|
|
|
27
26
|
import { useModelTracking } from './useModelTracking.js';
|
|
28
27
|
import { useIdeContextBridge } from './useIdeContextBridge.js';
|
|
29
28
|
import { useQueueErrorTimeout } from './useQueueErrorTimeout.js';
|
|
30
|
-
import { useIdeRestartHotkey } from './useIdeRestartHotkey.js';
|
|
31
29
|
import { useMemoryRefreshAction } from './useMemoryRefreshAction.js';
|
|
32
30
|
import { useModelRuntimeSync } from './useModelRuntimeSync.js';
|
|
33
31
|
import { useAppEventHandlers } from './useAppEventHandlers.js';
|
|
@@ -73,7 +71,6 @@ function useDialogsState() {
|
|
|
73
71
|
IdeContext | undefined
|
|
74
72
|
>();
|
|
75
73
|
const [showEscapePrompt, setShowEscapePrompt] = useState(false);
|
|
76
|
-
const [showIdeRestartPrompt, setShowIdeRestartPrompt] = useState(false);
|
|
77
74
|
const [isProcessing, setIsProcessing] = useState<boolean>(false);
|
|
78
75
|
const [embeddedShellFocused, setEmbeddedShellFocused] = useState(false);
|
|
79
76
|
const [queueErrorMessage, setQueueErrorMessage] = useState<string | null>(
|
|
@@ -115,8 +112,6 @@ function useDialogsState() {
|
|
|
115
112
|
setIdeContextState,
|
|
116
113
|
showEscapePrompt,
|
|
117
114
|
setShowEscapePrompt,
|
|
118
|
-
showIdeRestartPrompt,
|
|
119
|
-
setShowIdeRestartPrompt,
|
|
120
115
|
isProcessing,
|
|
121
116
|
setIsProcessing,
|
|
122
117
|
embeddedShellFocused,
|
|
@@ -183,16 +178,11 @@ function useIdeTrustEffect(
|
|
|
183
178
|
config: AppDialogsParams['config'],
|
|
184
179
|
st: ReturnType<typeof useDialogsState>,
|
|
185
180
|
) {
|
|
186
|
-
const { needsRestart: ideNeedsRestart } = useIdeTrustListener(config);
|
|
187
|
-
useEffect(() => {
|
|
188
|
-
if (ideNeedsRestart) st.setShowIdeRestartPrompt(true);
|
|
189
|
-
}, [ideNeedsRestart, st]);
|
|
190
181
|
useQueueErrorTimeout({
|
|
191
182
|
queueErrorMessage: st.queueErrorMessage,
|
|
192
183
|
setQueueErrorMessage: st.setQueueErrorMessage,
|
|
193
184
|
timeoutMs: QUEUE_ERROR_DISPLAY_DURATION_MS,
|
|
194
185
|
});
|
|
195
|
-
useIdeRestartHotkey({ isActive: st.showIdeRestartPrompt });
|
|
196
186
|
}
|
|
197
187
|
|
|
198
188
|
function useDialogsAuthProviders(
|
|
@@ -280,11 +270,10 @@ function useDialogsAuth(
|
|
|
280
270
|
const { config, settings, appState, addItem } = p;
|
|
281
271
|
const theme = useThemeCommand(settings, appState, addItem);
|
|
282
272
|
const settingsCmd = useSettingsCommand();
|
|
283
|
-
const folderTrust = useFolderTrust(settings, addItem);
|
|
273
|
+
const folderTrust = useFolderTrust(settings, addItem, config);
|
|
284
274
|
const welcome = useWelcomeOnboarding({
|
|
285
275
|
settings,
|
|
286
|
-
isFolderTrustComplete:
|
|
287
|
-
!folderTrust.isFolderTrustDialogOpen && !folderTrust.isRestarting,
|
|
276
|
+
isFolderTrustComplete: !folderTrust.isFolderTrustDialogOpen,
|
|
288
277
|
agent: p.agent,
|
|
289
278
|
});
|
|
290
279
|
useIdeTrustEffect(config, st);
|
|
@@ -309,7 +298,6 @@ function useDialogsAuth(
|
|
|
309
298
|
closeSettingsDialog: settingsCmd.closeSettingsDialog,
|
|
310
299
|
isFolderTrustDialogOpen: folderTrust.isFolderTrustDialogOpen,
|
|
311
300
|
handleFolderTrustSelect: folderTrust.handleFolderTrustSelect,
|
|
312
|
-
isRestarting: folderTrust.isRestarting,
|
|
313
301
|
isWelcomeDialogOpen: welcome.showWelcome,
|
|
314
302
|
welcomeState: welcome.state,
|
|
315
303
|
welcomeActions: welcome.actions,
|
|
@@ -15,7 +15,7 @@ import { useVimMode } from '../../../contexts/VimModeContext.js';
|
|
|
15
15
|
import { useVim } from '../../../hooks/vim.js';
|
|
16
16
|
import { useTextBuffer } from '../../../components/shared/text-buffer.js';
|
|
17
17
|
import { useInputHistoryStore } from '../../../hooks/useInputHistoryStore.js';
|
|
18
|
-
import {
|
|
18
|
+
import { shouldClearTodos } from '../../../hooks/useTodoPausePreserver.js';
|
|
19
19
|
import { StreamingState, type HistoryItem } from '../../../types.js';
|
|
20
20
|
import { submitOAuthCode } from '../../../oauth-submission.js';
|
|
21
21
|
import { getPendingOAuthProvider } from '../../../oauthGlobalState.js';
|
|
@@ -28,6 +28,7 @@ import { useSlashCommandActions } from './useSlashCommandActions.js';
|
|
|
28
28
|
import { useExitHandling } from './useExitHandling.js';
|
|
29
29
|
import { useInputHandling } from './useInputHandling.js';
|
|
30
30
|
import { useShellFocusAutoReset } from './useShellFocusAutoReset.js';
|
|
31
|
+
import { useSteer } from './useSteer.js';
|
|
31
32
|
import * as fs from 'fs';
|
|
32
33
|
import type { AppBootstrapResult } from './useAppBootstrap.js';
|
|
33
34
|
import type { AppDialogsResult } from './useAppDialogs.js';
|
|
@@ -46,10 +47,6 @@ export interface AppInputParams {
|
|
|
46
47
|
loadHistory: AppBootstrapResult['loadHistory'];
|
|
47
48
|
todos: AppBootstrapResult['todos'];
|
|
48
49
|
updateTodos: AppBootstrapResult['updateTodos'];
|
|
49
|
-
todoPauseController: AppBootstrapResult['todoPauseController'];
|
|
50
|
-
todoContinuationRef: AppBootstrapResult['todoContinuationRef'];
|
|
51
|
-
hadToolCallsRef: AppBootstrapResult['hadToolCallsRef'];
|
|
52
|
-
registerTodoPause: AppBootstrapResult['registerTodoPause'];
|
|
53
50
|
recordingIntegrationRef: AppBootstrapResult['recordingIntegrationRef'];
|
|
54
51
|
recordingSwapCallbacks: AppBootstrapResult['recordingSwapCallbacks'];
|
|
55
52
|
recordingIntegration: AppBootstrapResult['recordingIntegration'];
|
|
@@ -313,7 +310,6 @@ function useInputStreamSetup(
|
|
|
313
310
|
settings,
|
|
314
311
|
history,
|
|
315
312
|
addItem,
|
|
316
|
-
registerTodoPause,
|
|
317
313
|
recordingIntegration,
|
|
318
314
|
runtimeMessageBus,
|
|
319
315
|
stdout,
|
|
@@ -345,7 +341,6 @@ function useInputStreamSetup(
|
|
|
345
341
|
setEmbeddedShellFocused,
|
|
346
342
|
stdout.columns,
|
|
347
343
|
stdout.rows,
|
|
348
|
-
registerTodoPause,
|
|
349
344
|
handleExternalEditorOpen,
|
|
350
345
|
recordingIntegration,
|
|
351
346
|
runtimeMessageBus,
|
|
@@ -358,21 +353,15 @@ function useInputStreamWiring(
|
|
|
358
353
|
core: ReturnType<typeof useInputCore>,
|
|
359
354
|
setup: ReturnType<typeof useInputStreamSetup>,
|
|
360
355
|
) {
|
|
361
|
-
const {
|
|
362
|
-
|
|
363
|
-
updateTodos,
|
|
364
|
-
todoPauseController,
|
|
365
|
-
todoContinuationRef,
|
|
366
|
-
hadToolCallsRef,
|
|
367
|
-
embeddedShellFocused,
|
|
368
|
-
setEmbeddedShellFocused,
|
|
369
|
-
} = p;
|
|
356
|
+
const { todos, updateTodos, embeddedShellFocused, setEmbeddedShellFocused } =
|
|
357
|
+
p;
|
|
370
358
|
const {
|
|
371
359
|
buffer,
|
|
372
360
|
inputHistoryStore,
|
|
373
361
|
lastSubmittedPromptRef,
|
|
374
362
|
agentStreamResult,
|
|
375
363
|
} = setup;
|
|
364
|
+
const { submitQuery } = agentStreamResult;
|
|
376
365
|
const pendingHistoryItems = useMemo(
|
|
377
366
|
() => [
|
|
378
367
|
...(core.pendingHistoryItems as HistoryItem[]),
|
|
@@ -390,30 +379,47 @@ function useInputStreamWiring(
|
|
|
390
379
|
const { handleFinalSubmit } = useInputHandling({
|
|
391
380
|
buffer,
|
|
392
381
|
inputHistoryStore,
|
|
393
|
-
submitQuery
|
|
382
|
+
submitQuery,
|
|
394
383
|
pendingHistoryItems,
|
|
395
384
|
lastSubmittedPromptRef,
|
|
396
|
-
hadToolCallsRef,
|
|
397
|
-
todoContinuationRef,
|
|
398
385
|
needsRelogin: p.appState.needsRelogin,
|
|
399
386
|
appDispatch: p.appDispatch,
|
|
400
387
|
});
|
|
401
|
-
const
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
388
|
+
const handleUserInputSubmit = useCallback(
|
|
389
|
+
(submittedValue: string) => {
|
|
390
|
+
if (shouldClearTodos(todos)) {
|
|
391
|
+
updateTodos([]);
|
|
392
|
+
}
|
|
393
|
+
handleFinalSubmit(submittedValue);
|
|
394
|
+
},
|
|
395
|
+
[todos, updateTodos, handleFinalSubmit],
|
|
396
|
+
);
|
|
397
|
+
const enqueueSteer = useCallback(
|
|
398
|
+
(message: string) => {
|
|
399
|
+
void submitQuery(message);
|
|
400
|
+
},
|
|
401
|
+
[submitQuery],
|
|
402
|
+
);
|
|
403
|
+
const handleSteer = useSteer(
|
|
404
|
+
p.agent,
|
|
405
|
+
agentStreamResult.streamingState,
|
|
406
|
+
agentStreamResult.sanitizeContent,
|
|
407
|
+
pendingHistoryItems,
|
|
408
|
+
enqueueSteer,
|
|
409
|
+
);
|
|
407
410
|
const {
|
|
408
411
|
activeShellPtyId: _ptyIdFromStream,
|
|
409
412
|
pendingHistoryItems: _pendingFromStream,
|
|
413
|
+
queuedSubmissions,
|
|
410
414
|
...streamRest
|
|
411
415
|
} = agentStreamResult;
|
|
412
416
|
return {
|
|
413
417
|
handleFinalSubmit,
|
|
414
418
|
handleUserInputSubmit,
|
|
419
|
+
handleSteer,
|
|
415
420
|
pendingHistoryItems,
|
|
416
421
|
activeShellPtyId,
|
|
422
|
+
queuedSubmissions,
|
|
417
423
|
...streamRest,
|
|
418
424
|
};
|
|
419
425
|
}
|
|
@@ -12,7 +12,6 @@ import { getAllLlxprtMdFilenames } from '@vybestack/llxprt-code-core';
|
|
|
12
12
|
import { useKeybindings } from './useKeybindings.js';
|
|
13
13
|
import { useLayoutMeasurement } from './useLayoutMeasurement.js';
|
|
14
14
|
import { useFlickerDetector } from '../../../hooks/useFlickerDetector.js';
|
|
15
|
-
import { useTodoContinuationFlow } from './useTodoContinuationFlow.js';
|
|
16
15
|
import { useSelectionDebugLogger } from './useSelectionDebugLogger.js';
|
|
17
16
|
import { useClearScreenAction } from './useClearScreenAction.js';
|
|
18
17
|
import { useConfirmationSelection } from './useConfirmationSelection.js';
|
|
@@ -29,10 +28,7 @@ import type { UiRuntime } from '../../../cliUiRuntime.js';
|
|
|
29
28
|
export interface AppLayoutParams {
|
|
30
29
|
// From bootstrap
|
|
31
30
|
uiRuntime: UiRuntime;
|
|
32
|
-
agent: AppBootstrapResult['agent'];
|
|
33
31
|
settings: AppBootstrapResult['settings'];
|
|
34
|
-
todoContinuationRef: AppBootstrapResult['todoContinuationRef'];
|
|
35
|
-
hadToolCallsRef: AppBootstrapResult['hadToolCallsRef'];
|
|
36
32
|
runtimeMessageBus: AppBootstrapResult['runtimeMessageBus'];
|
|
37
33
|
consoleMessages: AppBootstrapResult['consoleMessages'];
|
|
38
34
|
clearConsoleMessagesState: AppBootstrapResult['clearConsoleMessagesState'];
|
|
@@ -52,6 +48,8 @@ export interface AppLayoutParams {
|
|
|
52
48
|
setRenderMarkdown: AppDialogsResult['setRenderMarkdown'];
|
|
53
49
|
isTodoPanelCollapsed: AppDialogsResult['isTodoPanelCollapsed'];
|
|
54
50
|
setIsTodoPanelCollapsed: AppDialogsResult['setIsTodoPanelCollapsed'];
|
|
51
|
+
isQueuedMessagesPanelCollapsed: AppDialogsResult['isQueuedMessagesPanelCollapsed'];
|
|
52
|
+
setIsQueuedMessagesPanelCollapsed: AppDialogsResult['setIsQueuedMessagesPanelCollapsed'];
|
|
55
53
|
setFooterHeight: AppDialogsResult['setFooterHeight'];
|
|
56
54
|
footerHeight: AppDialogsResult['footerHeight'];
|
|
57
55
|
copyModeEnabled: AppDialogsResult['copyModeEnabled'];
|
|
@@ -84,6 +82,7 @@ export interface AppLayoutParams {
|
|
|
84
82
|
handleSlashCommand: AppInputResult['handleSlashCommand'];
|
|
85
83
|
inputHistoryStore: AppInputResult['inputHistoryStore'];
|
|
86
84
|
handleUserInputSubmit: AppInputResult['handleUserInputSubmit'];
|
|
85
|
+
handleSteer: AppInputResult['handleSteer'];
|
|
87
86
|
interactiveRuntimeReady: AppInputResult['interactiveRuntimeReady'];
|
|
88
87
|
vimModeEnabled: AppInputResult['vimModeEnabled'];
|
|
89
88
|
terminalHeight: AppInputResult['terminalHeight'];
|
|
@@ -98,6 +97,59 @@ function pickCopyModeKeybindingState(p: AppLayoutParams) {
|
|
|
98
97
|
};
|
|
99
98
|
}
|
|
100
99
|
|
|
100
|
+
function buildKeybindingsConfig(
|
|
101
|
+
p: AppLayoutParams,
|
|
102
|
+
exitState: {
|
|
103
|
+
requestCtrlCExit: AppLayoutParams['requestCtrlCExit'];
|
|
104
|
+
requestCtrlDExit: AppLayoutParams['requestCtrlDExit'];
|
|
105
|
+
ctrlCPressedOnce: AppLayoutParams['ctrlCPressedOnce'];
|
|
106
|
+
cancelOngoingRequest: AppLayoutParams['cancelOngoingRequest'];
|
|
107
|
+
bufferTextLength: number;
|
|
108
|
+
},
|
|
109
|
+
displayState: {
|
|
110
|
+
showErrorDetails: AppLayoutParams['showErrorDetails'];
|
|
111
|
+
setShowErrorDetails: AppLayoutParams['setShowErrorDetails'];
|
|
112
|
+
showToolDescriptions: AppLayoutParams['showToolDescriptions'];
|
|
113
|
+
setShowToolDescriptions: AppLayoutParams['setShowToolDescriptions'];
|
|
114
|
+
renderMarkdown: AppLayoutParams['renderMarkdown'];
|
|
115
|
+
setRenderMarkdown: AppLayoutParams['setRenderMarkdown'];
|
|
116
|
+
isTodoPanelCollapsed: AppLayoutParams['isTodoPanelCollapsed'];
|
|
117
|
+
setIsTodoPanelCollapsed: AppLayoutParams['setIsTodoPanelCollapsed'];
|
|
118
|
+
isQueuedMessagesPanelCollapsed: AppLayoutParams['isQueuedMessagesPanelCollapsed'];
|
|
119
|
+
setIsQueuedMessagesPanelCollapsed: AppLayoutParams['setIsQueuedMessagesPanelCollapsed'];
|
|
120
|
+
constrainHeight: AppLayoutParams['constrainHeight'];
|
|
121
|
+
setConstrainHeight: AppLayoutParams['setConstrainHeight'];
|
|
122
|
+
refreshStatic: AppLayoutParams['refreshStatic'];
|
|
123
|
+
addItem: AppLayoutParams['addItem'];
|
|
124
|
+
handleSlashCommand: AppLayoutParams['handleSlashCommand'];
|
|
125
|
+
},
|
|
126
|
+
shellState: {
|
|
127
|
+
activeShellPtyId: AppLayoutParams['activeShellPtyId'];
|
|
128
|
+
setEmbeddedShellFocused: AppLayoutParams['setEmbeddedShellFocused'];
|
|
129
|
+
ideContextState: AppLayoutParams['ideContextState'];
|
|
130
|
+
},
|
|
131
|
+
) {
|
|
132
|
+
const { uiRuntime } = p;
|
|
133
|
+
return {
|
|
134
|
+
exit: exitState,
|
|
135
|
+
display: displayState,
|
|
136
|
+
shell: {
|
|
137
|
+
activeShellPtyId: shellState.activeShellPtyId,
|
|
138
|
+
setEmbeddedShellFocused: shellState.setEmbeddedShellFocused,
|
|
139
|
+
getEnableInteractiveShell: () =>
|
|
140
|
+
uiRuntime.shell.getEnableInteractiveShell(),
|
|
141
|
+
},
|
|
142
|
+
copyMode: pickCopyModeKeybindingState(p),
|
|
143
|
+
ideContext: {
|
|
144
|
+
getIdeMode: () => uiRuntime.ide.getIdeMode(),
|
|
145
|
+
ideContextState: shellState.ideContextState,
|
|
146
|
+
},
|
|
147
|
+
mcp: {
|
|
148
|
+
getMcpServers: () => uiRuntime.mcp.getMcpServers(),
|
|
149
|
+
},
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
|
|
101
153
|
function useLayoutKeybindingsAndHistory(p: AppLayoutParams) {
|
|
102
154
|
const {
|
|
103
155
|
uiRuntime,
|
|
@@ -114,6 +166,8 @@ function useLayoutKeybindingsAndHistory(p: AppLayoutParams) {
|
|
|
114
166
|
setRenderMarkdown,
|
|
115
167
|
isTodoPanelCollapsed,
|
|
116
168
|
setIsTodoPanelCollapsed,
|
|
169
|
+
isQueuedMessagesPanelCollapsed,
|
|
170
|
+
setIsQueuedMessagesPanelCollapsed,
|
|
117
171
|
ideContextState,
|
|
118
172
|
activeShellPtyId,
|
|
119
173
|
setEmbeddedShellFocused,
|
|
@@ -127,44 +181,36 @@ function useLayoutKeybindingsAndHistory(p: AppLayoutParams) {
|
|
|
127
181
|
buffer,
|
|
128
182
|
useAlternateBuffer,
|
|
129
183
|
} = p;
|
|
130
|
-
useKeybindings(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
ideContext: {
|
|
161
|
-
getIdeMode: () => uiRuntime.ide.getIdeMode(),
|
|
162
|
-
ideContextState,
|
|
163
|
-
},
|
|
164
|
-
mcp: {
|
|
165
|
-
getMcpServers: () => uiRuntime.mcp.getMcpServers(),
|
|
166
|
-
},
|
|
167
|
-
});
|
|
184
|
+
useKeybindings(
|
|
185
|
+
buildKeybindingsConfig(
|
|
186
|
+
p,
|
|
187
|
+
{
|
|
188
|
+
requestCtrlCExit,
|
|
189
|
+
requestCtrlDExit,
|
|
190
|
+
ctrlCPressedOnce,
|
|
191
|
+
cancelOngoingRequest,
|
|
192
|
+
bufferTextLength: buffer.text.length,
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
showErrorDetails,
|
|
196
|
+
setShowErrorDetails,
|
|
197
|
+
showToolDescriptions,
|
|
198
|
+
setShowToolDescriptions,
|
|
199
|
+
renderMarkdown,
|
|
200
|
+
setRenderMarkdown,
|
|
201
|
+
isTodoPanelCollapsed,
|
|
202
|
+
setIsTodoPanelCollapsed,
|
|
203
|
+
isQueuedMessagesPanelCollapsed,
|
|
204
|
+
setIsQueuedMessagesPanelCollapsed,
|
|
205
|
+
constrainHeight,
|
|
206
|
+
setConstrainHeight,
|
|
207
|
+
refreshStatic,
|
|
208
|
+
addItem,
|
|
209
|
+
handleSlashCommand,
|
|
210
|
+
},
|
|
211
|
+
{ activeShellPtyId, setEmbeddedShellFocused, ideContextState },
|
|
212
|
+
),
|
|
213
|
+
);
|
|
168
214
|
const logger = useLogger(uiRuntime.storage);
|
|
169
215
|
useInputHistoryBootstrap({ inputHistoryStore, logger });
|
|
170
216
|
const handleClearScreen = useClearScreenAction({
|
|
@@ -178,19 +224,11 @@ function useLayoutKeybindingsAndHistory(p: AppLayoutParams) {
|
|
|
178
224
|
|
|
179
225
|
function useLayoutMeasure(p: AppLayoutParams) {
|
|
180
226
|
const {
|
|
181
|
-
uiRuntime,
|
|
182
|
-
agent,
|
|
183
|
-
todoContinuationRef,
|
|
184
|
-
hadToolCallsRef,
|
|
185
227
|
consoleMessages,
|
|
186
228
|
constrainHeight,
|
|
187
229
|
setFooterHeight,
|
|
188
230
|
footerHeight,
|
|
189
|
-
streamingState,
|
|
190
|
-
history,
|
|
191
|
-
pendingHistoryItems,
|
|
192
231
|
confirmationRequest,
|
|
193
|
-
setDebugMessage,
|
|
194
232
|
terminalHeight,
|
|
195
233
|
} = p;
|
|
196
234
|
useSelectionDebugLogger({ confirmationRequest });
|
|
@@ -212,16 +250,6 @@ function useLayoutMeasure(p: AppLayoutParams) {
|
|
|
212
250
|
[terminalHeight, footerHeight],
|
|
213
251
|
);
|
|
214
252
|
useFlickerDetector(rootUiRef, terminalHeight, constrainHeight);
|
|
215
|
-
useTodoContinuationFlow({
|
|
216
|
-
uiRuntime,
|
|
217
|
-
agent,
|
|
218
|
-
streamingState,
|
|
219
|
-
history,
|
|
220
|
-
pendingHistoryItems,
|
|
221
|
-
setDebugMessage,
|
|
222
|
-
todoContinuationRef,
|
|
223
|
-
hadToolCallsRef,
|
|
224
|
-
});
|
|
225
253
|
return {
|
|
226
254
|
mainControlsRef,
|
|
227
255
|
pendingHistoryItemRef,
|
|
@@ -249,6 +277,7 @@ function useLayoutContext(p: AppLayoutParams) {
|
|
|
249
277
|
terminalHeight,
|
|
250
278
|
terminalWidth,
|
|
251
279
|
handleUserInputSubmit,
|
|
280
|
+
handleSteer,
|
|
252
281
|
interactiveRuntimeReady,
|
|
253
282
|
vimModeEnabled,
|
|
254
283
|
startupGuardsInitialized,
|
|
@@ -298,6 +327,7 @@ function useLayoutContext(p: AppLayoutParams) {
|
|
|
298
327
|
mainAreaWidth,
|
|
299
328
|
placeholder,
|
|
300
329
|
activeHooks,
|
|
330
|
+
handleSteer,
|
|
301
331
|
};
|
|
302
332
|
}
|
|
303
333
|
|
|
@@ -43,6 +43,10 @@ export interface UseDisplayPreferencesResult {
|
|
|
43
43
|
isTodoPanelCollapsed: boolean;
|
|
44
44
|
setIsTodoPanelCollapsed: (collapsed: boolean) => void;
|
|
45
45
|
|
|
46
|
+
// Queued messages panel collapse state
|
|
47
|
+
isQueuedMessagesPanelCollapsed: boolean;
|
|
48
|
+
setIsQueuedMessagesPanelCollapsed: (collapsed: boolean) => void;
|
|
49
|
+
|
|
46
50
|
// Settings nonce for forcing re-renders when settings change
|
|
47
51
|
settingsNonce: number;
|
|
48
52
|
}
|
|
@@ -55,6 +59,8 @@ export function useDisplayPreferences(): UseDisplayPreferencesResult {
|
|
|
55
59
|
const [copyModeEnabled, setCopyModeEnabled] = useState(false);
|
|
56
60
|
const [renderMarkdown, setRenderMarkdown] = useState<boolean>(true);
|
|
57
61
|
const [isTodoPanelCollapsed, setIsTodoPanelCollapsed] = useState(false);
|
|
62
|
+
const [isQueuedMessagesPanelCollapsed, setIsQueuedMessagesPanelCollapsed] =
|
|
63
|
+
useState(false);
|
|
58
64
|
const [settingsNonce, setSettingsNonce] = useState(0);
|
|
59
65
|
|
|
60
66
|
const toggleDebugProfiler = useCallback(() => {
|
|
@@ -98,6 +104,10 @@ export function useDisplayPreferences(): UseDisplayPreferencesResult {
|
|
|
98
104
|
isTodoPanelCollapsed,
|
|
99
105
|
setIsTodoPanelCollapsed,
|
|
100
106
|
|
|
107
|
+
// Queued messages panel collapse state
|
|
108
|
+
isQueuedMessagesPanelCollapsed,
|
|
109
|
+
setIsQueuedMessagesPanelCollapsed,
|
|
110
|
+
|
|
101
111
|
// Settings nonce
|
|
102
112
|
settingsNonce,
|
|
103
113
|
};
|
|
@@ -18,10 +18,6 @@ export interface UseInputHandlingParams {
|
|
|
18
18
|
submitQuery: (query: string) => Promise<void>;
|
|
19
19
|
pendingHistoryItems: HistoryItemWithoutId[];
|
|
20
20
|
lastSubmittedPromptRef: React.MutableRefObject<string | null>;
|
|
21
|
-
hadToolCallsRef: React.MutableRefObject<boolean>;
|
|
22
|
-
todoContinuationRef: React.MutableRefObject<{
|
|
23
|
-
clearPause: () => void;
|
|
24
|
-
} | null>;
|
|
25
21
|
/** Whether the user needs to re-authenticate before continuing. */
|
|
26
22
|
needsRelogin: boolean;
|
|
27
23
|
/** Dispatch app actions (e.g., open auth dialog). */
|
|
@@ -39,7 +35,9 @@ export interface UseInputHandlingResult {
|
|
|
39
35
|
/**
|
|
40
36
|
* Checks if any tool is currently executing in pending history items.
|
|
41
37
|
*/
|
|
42
|
-
function isToolExecuting(
|
|
38
|
+
export function isToolExecuting(
|
|
39
|
+
pendingHistoryItems: HistoryItemWithoutId[],
|
|
40
|
+
): boolean {
|
|
43
41
|
return pendingHistoryItems.some((item) => {
|
|
44
42
|
if (item.type === 'tool_group') {
|
|
45
43
|
return item.tools.some(
|
|
@@ -80,8 +78,6 @@ function useFinalSubmitHandler({
|
|
|
80
78
|
inputHistoryStore,
|
|
81
79
|
submitQuery,
|
|
82
80
|
lastSubmittedPromptRef,
|
|
83
|
-
hadToolCallsRef,
|
|
84
|
-
todoContinuationRef,
|
|
85
81
|
needsRelogin,
|
|
86
82
|
appDispatch,
|
|
87
83
|
}: UseInputHandlingParams): (submittedValue: string) => void {
|
|
@@ -101,14 +97,6 @@ function useFinalSubmitHandler({
|
|
|
101
97
|
return;
|
|
102
98
|
}
|
|
103
99
|
|
|
104
|
-
/**
|
|
105
|
-
* @plan PLAN-20260129-TODOPERSIST.P12
|
|
106
|
-
* Reset continuation attempt counter when user submits a new prompt.
|
|
107
|
-
* This prevents the continuation limit from blocking future continuations
|
|
108
|
-
* after user interaction.
|
|
109
|
-
*/
|
|
110
|
-
hadToolCallsRef.current = false;
|
|
111
|
-
todoContinuationRef.current?.clearPause();
|
|
112
100
|
lastSubmittedPromptRef.current = trimmedValue;
|
|
113
101
|
inputHistoryStore.addInput(trimmedValue);
|
|
114
102
|
void submitQuery(trimmedValue);
|
|
@@ -116,8 +104,6 @@ function useFinalSubmitHandler({
|
|
|
116
104
|
[
|
|
117
105
|
submitQuery,
|
|
118
106
|
inputHistoryStore,
|
|
119
|
-
hadToolCallsRef,
|
|
120
|
-
todoContinuationRef,
|
|
121
107
|
lastSubmittedPromptRef,
|
|
122
108
|
needsRelogin,
|
|
123
109
|
appDispatch,
|