@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
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
SlashCommandActionReturn,
|
|
15
15
|
} from './types.js';
|
|
16
16
|
import { CommandKind } from './types.js';
|
|
17
|
+
import type { CommandArgumentSchema } from './schema/types.js';
|
|
17
18
|
import { MessageType } from '../types.js';
|
|
18
19
|
import { Colors } from '../colors.js';
|
|
19
20
|
import { DebugLogger } from '@vybestack/llxprt-code-telemetry';
|
|
@@ -111,6 +112,60 @@ async function saveSubagent(
|
|
|
111
112
|
}
|
|
112
113
|
}
|
|
113
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Shared completer that lists existing subagents as autocomplete suggestions.
|
|
117
|
+
*
|
|
118
|
+
* @plan:PLAN-20251013-AUTOCOMPLETE.P08
|
|
119
|
+
* @requirement:REQ-002
|
|
120
|
+
* @requirement:REQ-004
|
|
121
|
+
*/
|
|
122
|
+
const subagentNameCompleter = withFuzzyFilter(async (ctx: CommandContext) => {
|
|
123
|
+
const manager = ctx.services.subagentManager;
|
|
124
|
+
if (!manager) {
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
const names = await manager.listSubagents();
|
|
129
|
+
|
|
130
|
+
const suggestions = await Promise.all(
|
|
131
|
+
names.map(async (name) => {
|
|
132
|
+
try {
|
|
133
|
+
const details = await manager.loadSubagent(name);
|
|
134
|
+
return {
|
|
135
|
+
value: name,
|
|
136
|
+
description: `Profile: ${details.profile}`,
|
|
137
|
+
};
|
|
138
|
+
} catch (error) {
|
|
139
|
+
logger.warn(
|
|
140
|
+
() =>
|
|
141
|
+
`Error loading subagent '${name}' for autocomplete: ${error instanceof Error ? error.message : String(error)}`,
|
|
142
|
+
);
|
|
143
|
+
return {
|
|
144
|
+
value: name,
|
|
145
|
+
description: 'Subagent',
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}),
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
return suggestions;
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Schema exposing subagent-name autocomplete for single-argument commands
|
|
156
|
+
* (`/subagent edit|show|delete <name>`).
|
|
157
|
+
*
|
|
158
|
+
* @requirement:REQ-004
|
|
159
|
+
*/
|
|
160
|
+
export const subagentNameSchema: CommandArgumentSchema = [
|
|
161
|
+
{
|
|
162
|
+
kind: 'value',
|
|
163
|
+
name: 'name',
|
|
164
|
+
description: 'Enter subagent name',
|
|
165
|
+
completer: subagentNameCompleter,
|
|
166
|
+
},
|
|
167
|
+
];
|
|
168
|
+
|
|
114
169
|
/**
|
|
115
170
|
* @plan:PLAN-20251013-AUTOCOMPLETE.P08
|
|
116
171
|
* @requirement:REQ-002
|
|
@@ -124,33 +179,7 @@ const subagentSchema = [
|
|
|
124
179
|
kind: 'value' as const,
|
|
125
180
|
name: 'name',
|
|
126
181
|
description: 'Enter subagent name',
|
|
127
|
-
completer:
|
|
128
|
-
const manager = ctx.services.subagentManager;
|
|
129
|
-
if (!manager) {
|
|
130
|
-
return [];
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
const names = await manager.listSubagents();
|
|
134
|
-
|
|
135
|
-
const suggestions = await Promise.all(
|
|
136
|
-
names.map(async (name) => {
|
|
137
|
-
try {
|
|
138
|
-
const details = await manager.loadSubagent(name);
|
|
139
|
-
return {
|
|
140
|
-
value: name,
|
|
141
|
-
description: `Profile: ${details.profile}`,
|
|
142
|
-
};
|
|
143
|
-
} catch {
|
|
144
|
-
return {
|
|
145
|
-
value: name,
|
|
146
|
-
description: 'Subagent',
|
|
147
|
-
};
|
|
148
|
-
}
|
|
149
|
-
}),
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
return suggestions;
|
|
153
|
-
}),
|
|
182
|
+
completer: subagentNameCompleter,
|
|
154
183
|
},
|
|
155
184
|
{
|
|
156
185
|
kind: 'value' as const,
|
|
@@ -393,6 +422,7 @@ const showCommand: SlashCommand = {
|
|
|
393
422
|
name: 'show',
|
|
394
423
|
description: 'Show detailed subagent configuration (interactive)',
|
|
395
424
|
kind: CommandKind.BUILT_IN,
|
|
425
|
+
schema: subagentNameSchema,
|
|
396
426
|
action: async (
|
|
397
427
|
context: CommandContext,
|
|
398
428
|
args: string,
|
|
@@ -445,6 +475,7 @@ const deleteCommand: SlashCommand = {
|
|
|
445
475
|
name: 'delete',
|
|
446
476
|
description: 'Delete a subagent configuration (interactive)',
|
|
447
477
|
kind: CommandKind.BUILT_IN,
|
|
478
|
+
schema: subagentNameSchema,
|
|
448
479
|
action: async (
|
|
449
480
|
context: CommandContext,
|
|
450
481
|
args: string,
|
|
@@ -528,6 +559,7 @@ const editCommand: SlashCommand = {
|
|
|
528
559
|
name: 'edit',
|
|
529
560
|
description: 'Edit subagent configuration (interactive)',
|
|
530
561
|
kind: CommandKind.BUILT_IN,
|
|
562
|
+
schema: subagentNameSchema,
|
|
531
563
|
action: async (
|
|
532
564
|
context: CommandContext,
|
|
533
565
|
args: string,
|
|
@@ -100,9 +100,9 @@ function buildAuthItems(
|
|
|
100
100
|
}> {
|
|
101
101
|
return [
|
|
102
102
|
{
|
|
103
|
-
key: '
|
|
104
|
-
label: `
|
|
105
|
-
value: '
|
|
103
|
+
key: 'oauth_claudecode',
|
|
104
|
+
label: `Claude Code (Claude.ai OAuth) ${enabledProviders.has('oauth_claudecode') ? '[ON]' : '[OFF]'}${getStatusLabel('claudecode', authStatuses)}`,
|
|
105
|
+
value: 'oauth_claudecode',
|
|
106
106
|
},
|
|
107
107
|
{
|
|
108
108
|
key: 'oauth_codex',
|
|
@@ -73,6 +73,7 @@ export const Composer = ({
|
|
|
73
73
|
inputWidth={inputWidth}
|
|
74
74
|
suggestionsWidth={suggestionsWidth}
|
|
75
75
|
onSubmit={uiActions.handleUserInputSubmit}
|
|
76
|
+
onSteer={uiActions.handleSteer}
|
|
76
77
|
userMessages={inputHistory}
|
|
77
78
|
onClearScreen={uiActions.handleClearScreen}
|
|
78
79
|
config={config}
|
|
@@ -218,6 +218,7 @@ function renderEarlyDialogs(
|
|
|
218
218
|
uiState: ReturnType<typeof useUIState>,
|
|
219
219
|
uiActions: ReturnType<typeof useUIActions>,
|
|
220
220
|
terminalWidth: number,
|
|
221
|
+
config: CliUiRuntime,
|
|
221
222
|
) {
|
|
222
223
|
if (uiState.showWorkspaceMigrationDialog) {
|
|
223
224
|
return (
|
|
@@ -239,8 +240,8 @@ function renderEarlyDialogs(
|
|
|
239
240
|
if (uiState.isFolderTrustDialogOpen) {
|
|
240
241
|
return (
|
|
241
242
|
<FolderTrustDialog
|
|
243
|
+
workingDirectory={config.getWorkingDir()}
|
|
242
244
|
onSelect={uiActions.handleFolderTrustSelect}
|
|
243
|
-
isRestarting={uiState.isRestarting}
|
|
244
245
|
/>
|
|
245
246
|
);
|
|
246
247
|
}
|
|
@@ -743,6 +744,7 @@ function renderDialogBodySecondHalf(
|
|
|
743
744
|
<PermissionsModifyTrustDialog
|
|
744
745
|
onExit={uiActions.closePermissionsDialog}
|
|
745
746
|
addItem={addItem}
|
|
747
|
+
config={config}
|
|
746
748
|
/>
|
|
747
749
|
);
|
|
748
750
|
}
|
|
@@ -823,7 +825,12 @@ export const DialogManager = ({
|
|
|
823
825
|
);
|
|
824
826
|
|
|
825
827
|
// NOTE: IdeTrustChangeDialog not yet ported from upstream
|
|
826
|
-
const earlyDialog = renderEarlyDialogs(
|
|
828
|
+
const earlyDialog = renderEarlyDialogs(
|
|
829
|
+
uiState,
|
|
830
|
+
uiActions,
|
|
831
|
+
terminalWidth,
|
|
832
|
+
config,
|
|
833
|
+
);
|
|
827
834
|
if (earlyDialog) return earlyDialog;
|
|
828
835
|
|
|
829
836
|
return renderDialogBody(uiState, uiActions, settings, config, addItem, state);
|
|
@@ -6,48 +6,30 @@
|
|
|
6
6
|
|
|
7
7
|
import { Box, Text } from 'ink';
|
|
8
8
|
import type React from 'react';
|
|
9
|
-
import { useState } from 'react';
|
|
9
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
10
10
|
import { Colors } from '../colors.js';
|
|
11
11
|
import { theme } from '../semantic-colors.js';
|
|
12
|
-
import type { RadioSelectItem } from './shared/RadioButtonSelect.js';
|
|
13
12
|
import { RadioButtonSelect } from './shared/RadioButtonSelect.js';
|
|
14
13
|
import { useKeypress } from '../hooks/useKeypress.js';
|
|
15
14
|
import * as process from 'node:process';
|
|
16
15
|
import * as path from 'node:path';
|
|
17
|
-
import { ExitCodes } from '@vybestack/llxprt-code-core';
|
|
16
|
+
import { DebugLogger, ExitCodes } from '@vybestack/llxprt-code-core';
|
|
17
|
+
import { FolderTrustChoice, buildTrustOptions } from '../trustDialogHelpers.js';
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
TRUST_FOLDER = 'trust_folder',
|
|
21
|
-
TRUST_PARENT = 'trust_parent',
|
|
22
|
-
DO_NOT_TRUST = 'do_not_trust',
|
|
23
|
-
}
|
|
19
|
+
const debug = DebugLogger.getLogger('llxprt:ui:folder-trust-dialog');
|
|
24
20
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
21
|
+
function isFolderTrustChoice(value: unknown): value is FolderTrustChoice {
|
|
22
|
+
return (
|
|
23
|
+
typeof value === 'string' &&
|
|
24
|
+
Object.values(FolderTrustChoice).includes(value as FolderTrustChoice)
|
|
25
|
+
);
|
|
28
26
|
}
|
|
29
27
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
{
|
|
36
|
-
label: 'Trust folder',
|
|
37
|
-
value: FolderTrustChoice.TRUST_FOLDER,
|
|
38
|
-
key: `Trust folder (${currentFolder})`,
|
|
39
|
-
},
|
|
40
|
-
{
|
|
41
|
-
label: `Trust parent folder (${parentFolder})`,
|
|
42
|
-
value: FolderTrustChoice.TRUST_PARENT,
|
|
43
|
-
key: `Trust parent folder (${parentFolder})`,
|
|
44
|
-
},
|
|
45
|
-
{
|
|
46
|
-
label: "Don't trust",
|
|
47
|
-
value: FolderTrustChoice.DO_NOT_TRUST,
|
|
48
|
-
key: "Don't trust",
|
|
49
|
-
},
|
|
50
|
-
];
|
|
28
|
+
export { FolderTrustChoice };
|
|
29
|
+
|
|
30
|
+
interface FolderTrustDialogProps {
|
|
31
|
+
workingDirectory: string;
|
|
32
|
+
onSelect: (choice: FolderTrustChoice) => void | Promise<void>;
|
|
51
33
|
}
|
|
52
34
|
|
|
53
35
|
const TrustDialogHeader: React.FC = () => (
|
|
@@ -62,11 +44,11 @@ const TrustDialogHeader: React.FC = () => (
|
|
|
62
44
|
</Box>
|
|
63
45
|
);
|
|
64
46
|
|
|
65
|
-
interface
|
|
47
|
+
interface ExitMessageProps {
|
|
66
48
|
exiting: boolean;
|
|
67
49
|
}
|
|
68
50
|
|
|
69
|
-
const
|
|
51
|
+
const ExitMessage: React.FC<ExitMessageProps> = ({ exiting }) => {
|
|
70
52
|
if (!exiting) {
|
|
71
53
|
return null;
|
|
72
54
|
}
|
|
@@ -80,37 +62,74 @@ const RestartingMessage: React.FC<RestartingMessageProps> = ({ exiting }) => {
|
|
|
80
62
|
);
|
|
81
63
|
};
|
|
82
64
|
|
|
65
|
+
function useMountedRef(): React.MutableRefObject<boolean> {
|
|
66
|
+
const mountedRef = useRef(true);
|
|
67
|
+
useEffect(() => {
|
|
68
|
+
mountedRef.current = true;
|
|
69
|
+
return () => {
|
|
70
|
+
mountedRef.current = false;
|
|
71
|
+
};
|
|
72
|
+
}, []);
|
|
73
|
+
return mountedRef;
|
|
74
|
+
}
|
|
75
|
+
|
|
83
76
|
export const FolderTrustDialog: React.FC<FolderTrustDialogProps> = ({
|
|
77
|
+
workingDirectory,
|
|
84
78
|
onSelect,
|
|
85
|
-
isRestarting,
|
|
86
79
|
}) => {
|
|
87
80
|
const [exiting, setExiting] = useState(false);
|
|
88
|
-
|
|
81
|
+
const [isCommitting, setIsCommitting] = useState(false);
|
|
82
|
+
const [errorMessage, setErrorMessage] = useState<string | null>(null);
|
|
83
|
+
const committingRef = useRef(false);
|
|
84
|
+
const exitingRef = useRef(false);
|
|
85
|
+
const exitTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(
|
|
86
|
+
undefined,
|
|
87
|
+
);
|
|
88
|
+
const mountedRef = useMountedRef();
|
|
89
|
+
useEffect(() => () => clearTimeout(exitTimerRef.current), []);
|
|
89
90
|
useKeypress(
|
|
90
91
|
(key) => {
|
|
92
|
+
if (committingRef.current || exitingRef.current) return;
|
|
91
93
|
if (key.name === 'escape') {
|
|
94
|
+
exitingRef.current = true;
|
|
92
95
|
setExiting(true);
|
|
93
|
-
setTimeout(() => {
|
|
96
|
+
exitTimerRef.current = setTimeout(() => {
|
|
94
97
|
process.exit(ExitCodes.FATAL_CONFIG_ERROR);
|
|
95
98
|
}, 100);
|
|
96
99
|
}
|
|
97
100
|
},
|
|
98
|
-
{ isActive:
|
|
101
|
+
{ isActive: true },
|
|
99
102
|
);
|
|
100
103
|
|
|
101
|
-
|
|
102
|
-
(
|
|
103
|
-
if (
|
|
104
|
-
|
|
104
|
+
const handleSelect = useCallback(
|
|
105
|
+
(choice: FolderTrustChoice) => {
|
|
106
|
+
if (!isFolderTrustChoice(choice) || committingRef.current) {
|
|
107
|
+
return;
|
|
105
108
|
}
|
|
109
|
+
committingRef.current = true;
|
|
110
|
+
setIsCommitting(true);
|
|
111
|
+
setErrorMessage(null);
|
|
112
|
+
void Promise.resolve()
|
|
113
|
+
.then(() => onSelect(choice))
|
|
114
|
+
.catch((error: unknown) => {
|
|
115
|
+
debug.error('Folder trust selection failed', error);
|
|
116
|
+
if (!mountedRef.current) return;
|
|
117
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
118
|
+
setErrorMessage(`Failed to apply folder trust selection: ${detail}`);
|
|
119
|
+
})
|
|
120
|
+
.finally(() => {
|
|
121
|
+
committingRef.current = false;
|
|
122
|
+
if (mountedRef.current) {
|
|
123
|
+
setIsCommitting(false);
|
|
124
|
+
}
|
|
125
|
+
});
|
|
106
126
|
},
|
|
107
|
-
|
|
127
|
+
[mountedRef, onSelect],
|
|
128
|
+
);
|
|
129
|
+
const options = buildTrustOptions(
|
|
130
|
+
path.basename(workingDirectory),
|
|
131
|
+
path.basename(path.dirname(workingDirectory)),
|
|
108
132
|
);
|
|
109
|
-
|
|
110
|
-
const currentFolder = path.basename(process.cwd());
|
|
111
|
-
const parentFolder = path.basename(path.dirname(process.cwd()));
|
|
112
|
-
const options = buildTrustOptions(currentFolder, parentFolder);
|
|
113
|
-
|
|
114
133
|
return (
|
|
115
134
|
<Box flexDirection="column" width="100%">
|
|
116
135
|
<Box
|
|
@@ -122,22 +141,14 @@ export const FolderTrustDialog: React.FC<FolderTrustDialogProps> = ({
|
|
|
122
141
|
marginRight={1}
|
|
123
142
|
>
|
|
124
143
|
<TrustDialogHeader />
|
|
125
|
-
|
|
126
144
|
<RadioButtonSelect
|
|
127
145
|
items={options}
|
|
128
|
-
onSelect={
|
|
129
|
-
isFocused={
|
|
146
|
+
onSelect={handleSelect}
|
|
147
|
+
isFocused={!isCommitting}
|
|
130
148
|
/>
|
|
149
|
+
{errorMessage && <Text color={theme.status.error}>{errorMessage}</Text>}
|
|
131
150
|
</Box>
|
|
132
|
-
{
|
|
133
|
-
<Box marginLeft={1} marginTop={1}>
|
|
134
|
-
<Text color={Colors.AccentYellow}>
|
|
135
|
-
To see changes, llxprt must be restarted. Press r to exit and apply
|
|
136
|
-
changes now.
|
|
137
|
-
</Text>
|
|
138
|
-
</Box>
|
|
139
|
-
)}
|
|
140
|
-
<RestartingMessage exiting={exiting} />
|
|
151
|
+
<ExitMessage exiting={exiting} />
|
|
141
152
|
</Box>
|
|
142
153
|
);
|
|
143
154
|
};
|