@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.
Files changed (126) hide show
  1. package/package.json +13 -13
  2. package/src/commands/mcp/add.ts +8 -4
  3. package/src/config/cliArgParser.ts +2 -0
  4. package/src/config/config.ts +2 -0
  5. package/src/config/configBuilder.ts +3 -0
  6. package/src/config/configError.ts +23 -0
  7. package/src/config/extensions/extensionEnablement.ts +62 -1
  8. package/src/config/interactiveContext.ts +2 -1
  9. package/src/config/intermediateConfig.ts +4 -0
  10. package/src/config/keyBindings.ts +29 -3
  11. package/src/config/policy.ts +7 -1
  12. package/src/config/postConfigRuntime.ts +20 -14
  13. package/src/config/settings-schema/schema-ui.ts +9 -0
  14. package/src/config/settingsLoader.ts +21 -17
  15. package/src/config/settingsSchema.ts +2 -2
  16. package/src/config/trustedFolders.ts +275 -58
  17. package/src/config/yargsOptions.ts +7 -0
  18. package/src/generated/git-commit.json +1 -1
  19. package/src/nonInteractiveCli.ts +1 -0
  20. package/src/nonInteractiveCliSupport.ts +171 -51
  21. package/src/runtime/interactiveToolScheduler.ts +6 -6
  22. package/src/services/BuiltinCommandLoader.ts +33 -25
  23. package/src/services/FileCommandLoader.ts +34 -7
  24. package/src/test-utils/async.ts +20 -0
  25. package/src/test-utils/render.tsx +10 -1
  26. package/src/ui/App.tsx +17 -10
  27. package/src/ui/AppContainerRuntime.tsx +7 -9
  28. package/src/ui/cliUiRuntime.ts +28 -0
  29. package/src/ui/commands/authCommand.ts +240 -3
  30. package/src/ui/commands/compressCommand.ts +9 -1
  31. package/src/ui/commands/directoryCommand.tsx +1 -1
  32. package/src/ui/commands/logoutCommand.ts +2 -2
  33. package/src/ui/commands/permissionsCommand.ts +77 -20
  34. package/src/ui/commands/policiesCommand.ts +6 -1
  35. package/src/ui/commands/quotaCommand.ts +501 -0
  36. package/src/ui/commands/statsCommand.ts +2 -2
  37. package/src/ui/commands/statsQuota.ts +1 -1
  38. package/src/ui/commands/subagentCommand.ts +59 -27
  39. package/src/ui/components/AuthDialog.tsx +3 -3
  40. package/src/ui/components/Composer.tsx +1 -0
  41. package/src/ui/components/DialogManager.tsx +9 -2
  42. package/src/ui/components/FolderTrustDialog.tsx +71 -60
  43. package/src/ui/components/PermissionsModifyTrustDialog.tsx +211 -146
  44. package/src/ui/components/ProfileCreateWizard/constants.ts +13 -1
  45. package/src/ui/components/QueuedMessagesPanel.tsx +388 -0
  46. package/src/ui/components/inputPromptHooks.ts +2 -0
  47. package/src/ui/components/inputPromptKeyHandlers.ts +14 -0
  48. package/src/ui/components/inputPromptTypes.ts +6 -0
  49. package/src/ui/components/messages/AiMessage.tsx +24 -12
  50. package/src/ui/components/messages/ToolMessage.tsx +26 -40
  51. package/src/ui/containers/AppContainer/builders/buildUIActions.ts +3 -1
  52. package/src/ui/containers/AppContainer/builders/buildUIState.ts +5 -4
  53. package/src/ui/containers/AppContainer/hooks/useAppBootstrap.ts +3 -33
  54. package/src/ui/containers/AppContainer/hooks/useAppDialogs.ts +2 -14
  55. package/src/ui/containers/AppContainer/hooks/useAppInput.ts +31 -25
  56. package/src/ui/containers/AppContainer/hooks/useAppLayout.ts +90 -60
  57. package/src/ui/containers/AppContainer/hooks/useDisplayPreferences.ts +10 -0
  58. package/src/ui/containers/AppContainer/hooks/useInputHandling.ts +3 -17
  59. package/src/ui/containers/AppContainer/hooks/useKeybindings.ts +51 -38
  60. package/src/ui/containers/AppContainer/hooks/useSteer.ts +51 -0
  61. package/src/ui/contexts/KeypressContext.tsx +13 -2
  62. package/src/ui/contexts/ShellCommandDisplayContext.tsx +103 -0
  63. package/src/ui/contexts/TodoContext.tsx +0 -13
  64. package/src/ui/contexts/TodoProvider.tsx +1 -34
  65. package/src/ui/contexts/UIActionsContext.tsx +2 -1
  66. package/src/ui/contexts/UIStateContext.tsx +3 -2
  67. package/src/ui/hooks/agentStream/streamUtils.ts +0 -24
  68. package/src/ui/hooks/agentStream/thoughtState.ts +110 -30
  69. package/src/ui/hooks/agentStream/types.ts +1 -0
  70. package/src/ui/hooks/agentStream/useAgentEventStream.ts +8 -17
  71. package/src/ui/hooks/agentStream/useAgentStream.ts +2 -2
  72. package/src/ui/hooks/agentStream/useAgentStreamLifecycle.ts +4 -5
  73. package/src/ui/hooks/agentStream/useAgentStreamOrchestration.ts +12 -5
  74. package/src/ui/hooks/agentStream/useQueuedSubmissions.ts +99 -0
  75. package/src/ui/hooks/agentStream/useStreamEventHandlers.ts +4 -13
  76. package/src/ui/hooks/agentStream/useStreamState.ts +60 -41
  77. package/src/ui/hooks/agentStream/useSubmitQuery.ts +284 -59
  78. package/src/ui/hooks/slashCommandProcessorSupport.ts +4 -0
  79. package/src/ui/hooks/useAgentStream-test-helpers.ts +1 -0
  80. package/src/ui/hooks/useAutoAcceptIndicator.ts +13 -0
  81. package/src/ui/hooks/useFolderTrust.ts +118 -81
  82. package/src/ui/hooks/useGitBranchName.ts +79 -33
  83. package/src/ui/hooks/useIdeTrustListener.ts +5 -19
  84. package/src/ui/hooks/usePermissionsModifyTrust.ts +223 -85
  85. package/src/ui/hooks/useReactToolScheduler.ts +13 -17
  86. package/src/ui/hooks/useTodoPausePreserver.ts +0 -55
  87. package/src/ui/layouts/DefaultAppLayout.tsx +2 -0
  88. package/src/ui/layouts/DefaultAppLayoutHelpers.tsx +37 -162
  89. package/src/ui/layouts/InlineContent.tsx +198 -0
  90. package/src/ui/trustDialogHelpers.ts +190 -0
  91. package/src/utils/cleanup-state.ts +115 -0
  92. package/src/utils/cleanup.ts +32 -34
  93. package/src/utils/sandbox-containers.ts +183 -53
  94. package/src/utils/sandbox-exec.ts +9 -3
  95. package/src/zed-integration/acp-terminal-shell-host.ts +112 -0
  96. package/src/zed-integration/acp-types.ts +35 -0
  97. package/src/zed-integration/fileSystemService.ts +1 -1
  98. package/src/zed-integration/runZedIntegration.ts +142 -0
  99. package/src/zed-integration/zed-agent-event-handler.ts +179 -0
  100. package/src/zed-integration/zed-agent-setup.ts +43 -0
  101. package/src/zed-integration/zed-command-registry.ts +167 -0
  102. package/src/zed-integration/zed-config-options.ts +280 -0
  103. package/src/zed-integration/zed-content-utils.ts +2 -2
  104. package/src/zed-integration/zed-helpers.ts +132 -0
  105. package/src/zed-integration/zed-initialize.ts +64 -0
  106. package/src/zed-integration/zed-plan-update.ts +20 -0
  107. package/src/zed-integration/zed-prompt-command.ts +77 -0
  108. package/src/zed-integration/zed-session-config.ts +119 -0
  109. package/src/zed-integration/zed-session-errors.ts +337 -0
  110. package/src/zed-integration/zed-session-events.ts +216 -0
  111. package/src/zed-integration/zed-session-info.ts +255 -0
  112. package/src/zed-integration/zed-session-lifecycle.ts +186 -0
  113. package/src/zed-integration/zed-session-listing.ts +153 -0
  114. package/src/zed-integration/zed-session-loader.ts +193 -0
  115. package/src/zed-integration/zed-session-pagination.ts +240 -0
  116. package/src/zed-integration/zed-session-replay.ts +564 -0
  117. package/src/zed-integration/zed-stream-batcher.ts +236 -0
  118. package/src/zed-integration/zed-terminal-manager.ts +416 -0
  119. package/src/zed-integration/zed-terminal-setup.ts +72 -0
  120. package/src/zed-integration/zed-test-helpers.ts +349 -4
  121. package/src/zed-integration/zed-tool-handler.ts +47 -5
  122. package/src/zed-integration/zedIntegration.ts +538 -587
  123. package/src/services/todo-continuation/todoContinuationService.ts +0 -610
  124. package/src/ui/containers/AppContainer/hooks/useIdeRestartHotkey.ts +0 -33
  125. package/src/ui/containers/AppContainer/hooks/useTodoContinuationFlow.ts +0 -160
  126. package/src/ui/hooks/useTodoContinuation.ts +0 -299
@@ -5,22 +5,25 @@
5
5
  */
6
6
 
7
7
  import React from 'react';
8
- import { Box, Text } from 'ink';
8
+ import { Box } from 'ink';
9
9
  import type {
10
10
  MessageBus,
11
11
  IdeContext,
12
12
  ThoughtSummary,
13
+ ApprovalMode,
13
14
  } from '@vybestack/llxprt-code-core';
14
- import { ApprovalMode } from '@vybestack/llxprt-code-core';
15
- import { StreamingState } from '../types.js';
15
+ import type {
16
+ StreamingState,
17
+ HistoryItem,
18
+ ConsoleMessageItem,
19
+ } from '../types.js';
16
20
  import type { SlashCommandRuntime, UiRuntime } from '../cliUiRuntime.js';
17
- import type { HistoryItem, ConsoleMessageItem } from '../types.js';
21
+ import type { QueuedSubmission } from '../hooks/agentStream/types.js';
18
22
  import type { LoadedSettings } from '../../config/settings.js';
19
23
  import type { UpdateObject } from '../utils/updateCheck.js';
20
24
  import type { UIState } from '../contexts/UIStateContext.js';
21
25
  import type { UIActions } from '../contexts/UIActionsContext.js';
22
26
  import { OverflowProvider } from '../contexts/OverflowContext.js';
23
- import { Colors } from '../colors.js';
24
27
  import { getCliRuntimeContext } from '@vybestack/llxprt-code-providers/runtime.js';
25
28
  import { themeManager } from '../themes/theme-manager.js';
26
29
  import type { SlashCommand } from '../commands/types.js';
@@ -30,15 +33,11 @@ import { HistoryItemDisplay } from '../components/HistoryItemDisplay.js';
30
33
  import { ShowMoreLines } from '../components/ShowMoreLines.js';
31
34
  import { Notifications } from '../components/Notifications.js';
32
35
  import { TodoPanel } from '../components/TodoPanel.js';
36
+ import { QueuedMessagesPanel } from '../components/QueuedMessagesPanel.js';
33
37
  import { Footer } from '../components/Footer.js';
34
38
  import { DialogManager } from '../components/DialogManager.js';
35
39
  import { BucketAuthConfirmation } from '../components/BucketAuthConfirmation.js';
36
- import { Composer } from '../components/Composer.js';
37
- import { LoadingIndicator } from '../components/LoadingIndicator.js';
38
- import { AutoAcceptIndicator } from '../components/AutoAcceptIndicator.js';
39
- import { ShellModeIndicator } from '../components/ShellModeIndicator.js';
40
- import { ContextSummaryDisplay } from '../components/ContextSummaryDisplay.js';
41
- import { DetailedMessagesDisplay } from '../components/DetailedMessagesDisplay.js';
40
+ import { InlineContent } from './InlineContent.js';
42
41
 
43
42
  export type { ScrollableMainContentItem } from './scrollableMainContent.js';
44
43
  export {
@@ -52,7 +51,6 @@ export function hasActiveDialog(uiState: UIState): boolean {
52
51
  const dialogFlags = [
53
52
  uiState.showWorkspaceMigrationDialog,
54
53
  uiState.shouldShowIdePrompt,
55
- uiState.showIdeRestartPrompt,
56
54
  uiState.isFolderTrustDialogOpen,
57
55
  uiState.isWelcomeDialogOpen,
58
56
  uiState.isPermissionsDialogOpen,
@@ -516,6 +514,8 @@ export interface MainControlsProps {
516
514
  history: HistoryItem[];
517
515
  inputWidth: number;
518
516
  isTodoPanelCollapsed: boolean;
517
+ isQueuedMessagesPanelCollapsed: boolean;
518
+ queuedSubmissions: readonly QueuedSubmission[];
519
519
  showTodoPanelSetting: boolean;
520
520
  dialogsVisible: boolean;
521
521
  hideContextSummary: boolean;
@@ -575,6 +575,11 @@ export function MainControls(props: MainControlsProps) {
575
575
  inputWidth={props.inputWidth}
576
576
  isTodoPanelCollapsed={props.isTodoPanelCollapsed}
577
577
  />
578
+ <QueuedMessagesPanelSection
579
+ inputWidth={props.inputWidth}
580
+ isQueuedMessagesPanelCollapsed={props.isQueuedMessagesPanelCollapsed}
581
+ queuedSubmissions={props.queuedSubmissions}
582
+ />
578
583
  <BucketAuthSection dialogsVisible={dialogsVisible} />
579
584
  {dialogsVisible ? (
580
585
  <DialogManager
@@ -634,164 +639,34 @@ function TodoPanelSection({
634
639
  return <TodoPanel width={inputWidth} collapsed={isTodoPanelCollapsed} />;
635
640
  }
636
641
 
637
- function BucketAuthSection({ dialogsVisible }: { dialogsVisible: boolean }) {
638
- return (
639
- <BucketAuthConfirmation
640
- messageBus={
641
- (getCliRuntimeContext() as { messageBus?: MessageBus }).messageBus
642
- }
643
- isFocused={!dialogsVisible}
644
- />
645
- );
646
- }
647
-
648
- export interface InlineContentProps {
649
- streamingState: StreamingState;
650
- disableLoadingPhrases: boolean;
651
- thought: ThoughtSummary | null;
652
- currentLoadingPhrase: string | undefined;
653
- elapsedTime: number;
654
- hideContextSummary: boolean;
655
- isNarrow: boolean;
656
- ctrlCPressedOnce: boolean;
657
- ctrlDPressedOnce: boolean;
658
- showEscapePrompt: boolean;
659
- ideContextState: IdeContext | undefined;
660
- llxprtMdFileCount: number;
661
- coreMemoryFileCount: number;
662
- contextFileNames: string[];
663
- config: SlashCommandRuntime;
664
- showToolDescriptions: boolean;
665
- showAutoAcceptIndicator: ApprovalMode;
666
- shellModeActive: boolean;
667
- showErrorDetails: boolean;
668
- consoleMessages: ConsoleMessageItem[];
669
- constrainHeight: boolean;
670
- debugConsoleMaxHeight: number;
642
+ function QueuedMessagesPanelSection({
643
+ inputWidth,
644
+ isQueuedMessagesPanelCollapsed,
645
+ queuedSubmissions,
646
+ }: {
671
647
  inputWidth: number;
672
- isInputActive: boolean;
673
- settings: LoadedSettings;
674
- onSuggestionsVisibilityChange: (visible: boolean) => void;
675
- }
676
-
677
- export function InlineContent(props: InlineContentProps) {
678
- return (
679
- <>
680
- <LoadingIndicator
681
- thought={
682
- props.streamingState === StreamingState.WaitingForConfirmation ||
683
- props.disableLoadingPhrases
684
- ? undefined
685
- : props.thought
686
- }
687
- currentLoadingPhrase={
688
- props.disableLoadingPhrases ? undefined : props.currentLoadingPhrase
689
- }
690
- elapsedTime={props.elapsedTime}
691
- />
692
- <StatusBar {...props} />
693
- <ErrorConsoleSection {...props} />
694
- <ComposerSection {...props} />
695
- </>
696
- );
697
- }
698
-
699
- function StatusBar(props: InlineContentProps) {
700
- return (
701
- <Box
702
- marginTop={1}
703
- display="flex"
704
- justifyContent={props.hideContextSummary ? 'flex-start' : 'space-between'}
705
- width="100%"
706
- >
707
- <StatusBarLeft {...props} />
708
- <StatusBarRight {...props} />
709
- </Box>
710
- );
711
- }
712
-
713
- function StatusBarLeftPrompt(props: InlineContentProps) {
714
- const transientPrompt = [
715
- { active: props.ctrlCPressedOnce, text: 'Press Ctrl+C again to exit.' },
716
- { active: props.ctrlDPressedOnce, text: 'Press Ctrl+D again to exit.' },
717
- ].find((entry) => entry.active);
718
- if (transientPrompt) {
719
- return <Text color={Colors.AccentYellow}>{transientPrompt.text}</Text>;
720
- }
721
- if (props.showEscapePrompt) {
722
- return <Text color={Colors.Gray}>Press Esc again to clear.</Text>;
723
- }
724
- if (!props.hideContextSummary) {
725
- return (
726
- <ContextSummaryDisplay
727
- ideContext={props.ideContextState}
728
- llxprtMdFileCount={props.llxprtMdFileCount}
729
- coreMemoryFileCount={props.coreMemoryFileCount}
730
- contextFileNames={props.contextFileNames}
731
- mcpServers={props.config.getMcpServers()}
732
- blockedMcpServers={props.config.getBlockedMcpServers()}
733
- showToolDescriptions={props.showToolDescriptions}
734
- />
735
- );
736
- }
737
- return null;
738
- }
739
-
740
- function StatusBarLeft(props: InlineContentProps) {
741
- return (
742
- <Box>
743
- {process.env.GEMINI_SYSTEM_MD && (
744
- <Text color={Colors.AccentRed}>|&#x2310;&#x25A0;_&#x25A0;| </Text>
745
- )}
746
- <StatusBarLeftPrompt {...props} />
747
- </Box>
748
- );
749
- }
750
-
751
- function StatusBarRight(props: InlineContentProps) {
752
- return (
753
- <Box
754
- paddingTop={props.isNarrow ? 1 : 0}
755
- marginLeft={props.hideContextSummary ? 1 : 2}
756
- >
757
- {props.showAutoAcceptIndicator !== ApprovalMode.DEFAULT &&
758
- !props.shellModeActive && (
759
- <AutoAcceptIndicator approvalMode={props.showAutoAcceptIndicator} />
760
- )}
761
- {props.shellModeActive && <ShellModeIndicator />}
762
- </Box>
763
- );
764
- }
765
-
766
- function ErrorConsoleSection(props: InlineContentProps) {
767
- if (!props.showErrorDetails) {
648
+ isQueuedMessagesPanelCollapsed: boolean;
649
+ queuedSubmissions: readonly QueuedSubmission[];
650
+ }) {
651
+ if (queuedSubmissions.length === 0) {
768
652
  return null;
769
653
  }
770
654
  return (
771
- <OverflowProvider>
772
- <Box flexDirection="column">
773
- <DetailedMessagesDisplay
774
- messages={props.consoleMessages}
775
- maxHeight={
776
- props.constrainHeight ? props.debugConsoleMaxHeight : undefined
777
- }
778
- width={props.inputWidth}
779
- />
780
- <ShowMoreLines constrainHeight={props.constrainHeight} />
781
- </Box>
782
- </OverflowProvider>
655
+ <QueuedMessagesPanel
656
+ width={inputWidth}
657
+ collapsed={isQueuedMessagesPanelCollapsed}
658
+ messages={queuedSubmissions}
659
+ />
783
660
  );
784
661
  }
785
662
 
786
- function ComposerSection(props: InlineContentProps) {
787
- if (!props.isInputActive) {
788
- return null;
789
- }
663
+ function BucketAuthSection({ dialogsVisible }: { dialogsVisible: boolean }) {
790
664
  return (
791
- <Composer
792
- config={props.config}
793
- settings={props.settings}
794
- onSuggestionsVisibilityChange={props.onSuggestionsVisibilityChange}
665
+ <BucketAuthConfirmation
666
+ messageBus={
667
+ (getCliRuntimeContext() as { messageBus?: MessageBus }).messageBus
668
+ }
669
+ isFocused={!dialogsVisible}
795
670
  />
796
671
  );
797
672
  }
@@ -0,0 +1,198 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Vybestack LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { Box, Text } from 'ink';
8
+ import type { IdeContext, ThoughtSummary } from '@vybestack/llxprt-code-core';
9
+ import { ApprovalMode } from '@vybestack/llxprt-code-core';
10
+ import { StreamingState } from '../types.js';
11
+ import type { ConsoleMessageItem } from '../types.js';
12
+ import type { LoadedSettings } from '../../config/settings.js';
13
+ import type { SlashCommandRuntime } from '../cliUiRuntime.js';
14
+ import { OverflowProvider } from '../contexts/OverflowContext.js';
15
+ import { Colors } from '../colors.js';
16
+ import { ShowMoreLines } from '../components/ShowMoreLines.js';
17
+ import { LoadingIndicator } from '../components/LoadingIndicator.js';
18
+ import { AutoAcceptIndicator } from '../components/AutoAcceptIndicator.js';
19
+ import { ShellModeIndicator } from '../components/ShellModeIndicator.js';
20
+ import { ContextSummaryDisplay } from '../components/ContextSummaryDisplay.js';
21
+ import { DetailedMessagesDisplay } from '../components/DetailedMessagesDisplay.js';
22
+ import { Composer } from '../components/Composer.js';
23
+
24
+ const CTRL_C_EXIT_PROMPT = 'Press Ctrl+C again to exit.';
25
+ const CTRL_D_EXIT_PROMPT = 'Press Ctrl+D again to exit.';
26
+ const ESCAPE_CLEAR_PROMPT = 'Press Esc again to clear.';
27
+ const SYSTEM_MD_ENVIRONMENT_VARIABLE = 'GEMINI_SYSTEM_MD';
28
+
29
+ function isSystemMdEnabled(): boolean {
30
+ return Boolean(process.env[SYSTEM_MD_ENVIRONMENT_VARIABLE]);
31
+ }
32
+
33
+ export interface InlineContentProps {
34
+ streamingState: StreamingState;
35
+ disableLoadingPhrases: boolean;
36
+ thought: ThoughtSummary | null;
37
+ currentLoadingPhrase: string | undefined;
38
+ elapsedTime: number;
39
+ hideContextSummary: boolean;
40
+ isNarrow: boolean;
41
+ ctrlCPressedOnce: boolean;
42
+ ctrlDPressedOnce: boolean;
43
+ showEscapePrompt: boolean;
44
+ ideContextState: IdeContext | undefined;
45
+ llxprtMdFileCount: number;
46
+ coreMemoryFileCount: number;
47
+ contextFileNames: string[];
48
+ config: SlashCommandRuntime;
49
+ showToolDescriptions: boolean;
50
+ showAutoAcceptIndicator: ApprovalMode;
51
+ shellModeActive: boolean;
52
+ showErrorDetails: boolean;
53
+ consoleMessages: ConsoleMessageItem[];
54
+ constrainHeight: boolean;
55
+ debugConsoleMaxHeight: number;
56
+ inputWidth: number;
57
+ isInputActive: boolean;
58
+ settings: LoadedSettings;
59
+ onSuggestionsVisibilityChange: (visible: boolean) => void;
60
+ }
61
+
62
+ export function InlineContent(props: InlineContentProps) {
63
+ const shouldHideThought =
64
+ props.streamingState === StreamingState.WaitingForConfirmation ||
65
+ props.disableLoadingPhrases;
66
+
67
+ return (
68
+ <>
69
+ <LoadingIndicator
70
+ thought={shouldHideThought ? undefined : props.thought}
71
+ currentLoadingPhrase={
72
+ props.disableLoadingPhrases ? undefined : props.currentLoadingPhrase
73
+ }
74
+ elapsedTime={props.elapsedTime}
75
+ />
76
+ <StatusBar {...props} />
77
+ <ErrorConsoleSection {...props} />
78
+ <ComposerSection {...props} />
79
+ </>
80
+ );
81
+ }
82
+
83
+ function StatusBar(props: InlineContentProps) {
84
+ return (
85
+ <Box
86
+ marginTop={1}
87
+ display="flex"
88
+ justifyContent={props.hideContextSummary ? 'flex-start' : 'space-between'}
89
+ width="100%"
90
+ >
91
+ <StatusBarLeft {...props} />
92
+ <StatusBarRight {...props} />
93
+ </Box>
94
+ );
95
+ }
96
+
97
+ function StatusBarLeftPrompt(props: InlineContentProps) {
98
+ // Exit confirmations take precedence over clearing feedback and context status.
99
+ if (props.ctrlCPressedOnce) {
100
+ return <Text color={Colors.AccentYellow}>{CTRL_C_EXIT_PROMPT}</Text>;
101
+ }
102
+ if (props.ctrlDPressedOnce) {
103
+ return <Text color={Colors.AccentYellow}>{CTRL_D_EXIT_PROMPT}</Text>;
104
+ }
105
+ if (props.showEscapePrompt) {
106
+ return <Text color={Colors.Gray}>{ESCAPE_CLEAR_PROMPT}</Text>;
107
+ }
108
+ if (!props.hideContextSummary) {
109
+ return (
110
+ <ContextSummaryDisplay
111
+ ideContext={props.ideContextState}
112
+ llxprtMdFileCount={props.llxprtMdFileCount}
113
+ coreMemoryFileCount={props.coreMemoryFileCount}
114
+ contextFileNames={props.contextFileNames}
115
+ mcpServers={props.config.getMcpServers()}
116
+ blockedMcpServers={props.config.getBlockedMcpServers()}
117
+ showToolDescriptions={props.showToolDescriptions}
118
+ />
119
+ );
120
+ }
121
+ return null;
122
+ }
123
+
124
+ function StatusBarLeft(props: InlineContentProps) {
125
+ const showSystemMdIndicator = isSystemMdEnabled();
126
+ const showPrompt =
127
+ props.ctrlCPressedOnce ||
128
+ props.ctrlDPressedOnce ||
129
+ props.showEscapePrompt ||
130
+ !props.hideContextSummary;
131
+ if (!showSystemMdIndicator && !showPrompt) {
132
+ return null;
133
+ }
134
+
135
+ return (
136
+ <Box>
137
+ {showSystemMdIndicator && (
138
+ <Text color={Colors.AccentRed}>|&#x2310;&#x25A0;_&#x25A0;| </Text>
139
+ )}
140
+ <StatusBarLeftPrompt {...props} />
141
+ </Box>
142
+ );
143
+ }
144
+
145
+ function StatusBarRight(props: InlineContentProps) {
146
+ if (
147
+ props.showAutoAcceptIndicator === ApprovalMode.DEFAULT &&
148
+ !props.shellModeActive
149
+ ) {
150
+ return null;
151
+ }
152
+ const shouldShowAutoAcceptIndicator = !props.shellModeActive;
153
+
154
+ return (
155
+ <Box
156
+ paddingTop={props.isNarrow ? 1 : 0}
157
+ marginLeft={props.hideContextSummary ? 1 : 2}
158
+ >
159
+ {shouldShowAutoAcceptIndicator && (
160
+ <AutoAcceptIndicator approvalMode={props.showAutoAcceptIndicator} />
161
+ )}
162
+ {props.shellModeActive && <ShellModeIndicator />}
163
+ </Box>
164
+ );
165
+ }
166
+
167
+ function ErrorConsoleSection(props: InlineContentProps) {
168
+ if (!props.showErrorDetails) {
169
+ return null;
170
+ }
171
+ return (
172
+ <OverflowProvider>
173
+ <Box flexDirection="column">
174
+ <DetailedMessagesDisplay
175
+ messages={props.consoleMessages}
176
+ maxHeight={
177
+ props.constrainHeight ? props.debugConsoleMaxHeight : undefined
178
+ }
179
+ width={props.inputWidth}
180
+ />
181
+ <ShowMoreLines constrainHeight={props.constrainHeight} />
182
+ </Box>
183
+ </OverflowProvider>
184
+ );
185
+ }
186
+
187
+ function ComposerSection(props: InlineContentProps) {
188
+ if (!props.isInputActive) {
189
+ return null;
190
+ }
191
+ return (
192
+ <Composer
193
+ config={props.config}
194
+ settings={props.settings}
195
+ onSuggestionsVisibilityChange={props.onSuggestionsVisibilityChange}
196
+ />
197
+ );
198
+ }
@@ -0,0 +1,190 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Vybestack LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ import { TrustLevel } from '../config/trustedFolders.js';
8
+ import type { RadioSelectItem } from './components/shared/RadioButtonSelect.js';
9
+
10
+ export enum FolderTrustChoice {
11
+ TRUST_FOLDER = 'trust_folder',
12
+ TRUST_PARENT = 'trust_parent',
13
+ DO_NOT_TRUST = 'do_not_trust',
14
+ }
15
+
16
+ function buildTrustRadioOptions<T extends string>(
17
+ currentFolder: string,
18
+ parentFolder: string,
19
+ values: {
20
+ readonly trustFolder: T;
21
+ readonly trustParent: T;
22
+ readonly doNotTrust: T;
23
+ },
24
+ ): Array<RadioSelectItem<T>> {
25
+ return [
26
+ {
27
+ label: `Trust folder (${currentFolder})`,
28
+ value: values.trustFolder,
29
+ key: values.trustFolder,
30
+ },
31
+ {
32
+ label: `Trust parent folder (${parentFolder})`,
33
+ value: values.trustParent,
34
+ key: values.trustParent,
35
+ },
36
+ {
37
+ label: "Don't trust",
38
+ value: values.doNotTrust,
39
+ key: values.doNotTrust,
40
+ },
41
+ ];
42
+ }
43
+
44
+ export function buildTrustOptions(
45
+ currentFolder: string,
46
+ parentFolder: string,
47
+ ): Array<RadioSelectItem<FolderTrustChoice>> {
48
+ return buildTrustRadioOptions(currentFolder, parentFolder, {
49
+ trustFolder: FolderTrustChoice.TRUST_FOLDER,
50
+ trustParent: FolderTrustChoice.TRUST_PARENT,
51
+ doNotTrust: FolderTrustChoice.DO_NOT_TRUST,
52
+ });
53
+ }
54
+
55
+ export function getLocalTrustLevelDisplay(
56
+ level: TrustLevel | undefined,
57
+ ): string {
58
+ switch (level) {
59
+ case TrustLevel.TRUST_FOLDER:
60
+ return 'Trusted';
61
+ case TrustLevel.TRUST_PARENT:
62
+ return 'Trust parent';
63
+ case TrustLevel.DO_NOT_TRUST:
64
+ return 'Not trusted';
65
+ default:
66
+ return 'Not set';
67
+ }
68
+ }
69
+
70
+ export function getTrustLevelDisplay(
71
+ level: TrustLevel | undefined,
72
+ isIdeTrusted: boolean | undefined,
73
+ isParentTrusted: boolean | undefined,
74
+ ): string {
75
+ if (isIdeTrusted !== undefined) {
76
+ return isIdeTrusted ? 'Trusted (via IDE)' : 'Not trusted (via IDE)';
77
+ }
78
+ const localDisplay = getLocalTrustLevelDisplay(level);
79
+ if (isParentTrusted === true) {
80
+ return level === undefined
81
+ ? 'Trusted (via parent folder)'
82
+ : `${localDisplay} (via parent folder)`;
83
+ }
84
+ return localDisplay;
85
+ }
86
+
87
+ export function getWarningMessage(
88
+ isIdeTrusted: boolean | undefined,
89
+ isParentTrusted: boolean | undefined,
90
+ currentTrustLevel: TrustLevel | undefined,
91
+ ): string | null {
92
+ if (isIdeTrusted !== undefined) {
93
+ const status = isIdeTrusted ? 'trusted' : 'not trusted';
94
+ return `This folder is ${status} via your IDE settings. Changes here save a local fallback for use without the IDE.`;
95
+ }
96
+ if (isParentTrusted === true) {
97
+ if (currentTrustLevel === TrustLevel.DO_NOT_TRUST) {
98
+ return 'This folder is not trusted because a parent folder rule denies trust.';
99
+ }
100
+ return 'This folder is trusted via a parent folder setting. You can override it with a more specific rule.';
101
+ }
102
+ return null;
103
+ }
104
+
105
+ export function getTrustUpdateDisplay(
106
+ committedTrustLevel: TrustLevel | undefined,
107
+ effectiveTrust: boolean | undefined,
108
+ isIdeTrusted: boolean | undefined,
109
+ isParentTrusted: boolean | undefined,
110
+ ): { savedLocalFallback: string; effectiveNow: string } {
111
+ let effectiveTrustLevel: TrustLevel | undefined;
112
+ if (effectiveTrust !== undefined) {
113
+ effectiveTrustLevel = effectiveTrust
114
+ ? TrustLevel.TRUST_FOLDER
115
+ : TrustLevel.DO_NOT_TRUST;
116
+ }
117
+ return {
118
+ savedLocalFallback: getLocalTrustLevelDisplay(committedTrustLevel),
119
+ effectiveNow: getTrustLevelDisplay(
120
+ effectiveTrustLevel,
121
+ isIdeTrusted,
122
+ isParentTrusted,
123
+ ),
124
+ };
125
+ }
126
+
127
+ function flattenErrorDetails(error: unknown): string[] {
128
+ if (error instanceof AggregateError) {
129
+ return error.errors.flatMap(flattenErrorDetails);
130
+ }
131
+ return [error instanceof Error ? error.message : String(error)];
132
+ }
133
+
134
+ export function combineTrustUpdateFailure(
135
+ error: unknown,
136
+ rollbackFailures: readonly unknown[],
137
+ aggregateMessage: string,
138
+ ): { error: unknown; rollbackSucceeded: boolean } {
139
+ if (rollbackFailures.length === 0) {
140
+ return { error, rollbackSucceeded: true };
141
+ }
142
+ return {
143
+ error: new AggregateError([error, ...rollbackFailures], aggregateMessage),
144
+ rollbackSucceeded: false,
145
+ };
146
+ }
147
+
148
+ export function getTrustCommitErrorMessage(
149
+ phase: 'persistence' | 'live',
150
+ error: unknown,
151
+ rollbackSucceeded = true,
152
+ ): string {
153
+ const detail = flattenErrorDetails(error).join('; ');
154
+ if (phase === 'persistence') {
155
+ return rollbackSucceeded
156
+ ? `Failed to save trust settings: ${detail}`
157
+ : `Failed to save trust settings and rollback was incomplete: ${detail}`;
158
+ }
159
+ return rollbackSucceeded
160
+ ? `Trust settings could not be applied live, so the saved setting was restored: ${detail}`
161
+ : `Trust settings could not be applied live and rollback was incomplete: ${detail}`;
162
+ }
163
+
164
+ export function shouldDismissTrustDialog(
165
+ showUpdatedPrompt: boolean,
166
+ keyName: string,
167
+ ): boolean {
168
+ return keyName === 'escape' || (showUpdatedPrompt && keyName === 'return');
169
+ }
170
+
171
+ export function buildTrustLevelOptions(
172
+ folderName: string,
173
+ parentFolderName: string,
174
+ ): Array<RadioSelectItem<TrustLevel>> {
175
+ return buildTrustRadioOptions(folderName, parentFolderName, {
176
+ trustFolder: TrustLevel.TRUST_FOLDER,
177
+ trustParent: TrustLevel.TRUST_PARENT,
178
+ doNotTrust: TrustLevel.DO_NOT_TRUST,
179
+ });
180
+ }
181
+
182
+ export function findInitialTrustOptionIndex(
183
+ options: Array<RadioSelectItem<TrustLevel>>,
184
+ currentTrustLevel: TrustLevel | undefined,
185
+ ): number {
186
+ const index = options.findIndex(
187
+ (option) => option.value === currentTrustLevel,
188
+ );
189
+ return index >= 0 ? index : 0;
190
+ }