@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
@@ -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: withFuzzyFilter(async (ctx: CommandContext) => {
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: 'oauth_anthropic',
104
- label: `Anthropic Claude (OAuth) ${enabledProviders.has('oauth_anthropic') ? '[ON]' : '[OFF]'}${getStatusLabel('anthropic', authStatuses)}`,
105
- value: 'oauth_anthropic',
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(uiState, uiActions, terminalWidth);
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
- export enum FolderTrustChoice {
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
- interface FolderTrustDialogProps {
26
- onSelect: (choice: FolderTrustChoice) => void;
27
- isRestarting?: boolean;
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
- function buildTrustOptions(
31
- currentFolder: string,
32
- parentFolder: string,
33
- ): Array<RadioSelectItem<FolderTrustChoice>> {
34
- return [
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 RestartingMessageProps {
47
+ interface ExitMessageProps {
66
48
  exiting: boolean;
67
49
  }
68
50
 
69
- const RestartingMessage: React.FC<RestartingMessageProps> = ({ exiting }) => {
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: isRestarting !== true },
101
+ { isActive: true },
99
102
  );
100
103
 
101
- useKeypress(
102
- (key) => {
103
- if (key.name === 'r') {
104
- process.exit(ExitCodes.SUCCESS);
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
- { isActive: isRestarting === true },
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={onSelect}
129
- isFocused={isRestarting !== true}
146
+ onSelect={handleSelect}
147
+ isFocused={!isCommitting}
130
148
  />
149
+ {errorMessage && <Text color={theme.status.error}>{errorMessage}</Text>}
131
150
  </Box>
132
- {isRestarting === true && (
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
  };