@vybestack/llxprt-code 0.10.0 → 0.11.0-nightly.260727.c4abf5792

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 (108) 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/interactiveContext.ts +2 -1
  8. package/src/config/intermediateConfig.ts +4 -0
  9. package/src/config/keyBindings.ts +29 -3
  10. package/src/config/policy.ts +7 -1
  11. package/src/config/postConfigRuntime.ts +20 -14
  12. package/src/config/settings-schema/schema-ui.ts +9 -0
  13. package/src/config/settingsLoader.ts +21 -17
  14. package/src/config/settingsSchema.ts +2 -2
  15. package/src/config/trustedFolders.ts +275 -58
  16. package/src/config/yargsOptions.ts +7 -0
  17. package/src/generated/git-commit.json +1 -1
  18. package/src/nonInteractiveCli.ts +1 -0
  19. package/src/nonInteractiveCliSupport.ts +171 -51
  20. package/src/services/BuiltinCommandLoader.ts +33 -25
  21. package/src/services/FileCommandLoader.ts +34 -7
  22. package/src/test-utils/async.ts +20 -0
  23. package/src/test-utils/render.tsx +10 -1
  24. package/src/ui/App.tsx +17 -10
  25. package/src/ui/AppContainerRuntime.tsx +7 -2
  26. package/src/ui/cliUiRuntime.ts +28 -0
  27. package/src/ui/commands/authCommand.ts +224 -3
  28. package/src/ui/commands/directoryCommand.tsx +1 -1
  29. package/src/ui/commands/permissionsCommand.ts +77 -20
  30. package/src/ui/commands/policiesCommand.ts +6 -1
  31. package/src/ui/commands/quotaCommand.ts +501 -0
  32. package/src/ui/commands/subagentCommand.ts +59 -27
  33. package/src/ui/components/Composer.tsx +1 -0
  34. package/src/ui/components/DialogManager.tsx +9 -2
  35. package/src/ui/components/FolderTrustDialog.tsx +71 -60
  36. package/src/ui/components/PermissionsModifyTrustDialog.tsx +211 -146
  37. package/src/ui/components/QueuedMessagesPanel.tsx +388 -0
  38. package/src/ui/components/inputPromptHooks.ts +2 -0
  39. package/src/ui/components/inputPromptKeyHandlers.ts +14 -0
  40. package/src/ui/components/inputPromptTypes.ts +6 -0
  41. package/src/ui/components/messages/AiMessage.tsx +24 -12
  42. package/src/ui/components/messages/ToolMessage.tsx +26 -40
  43. package/src/ui/containers/AppContainer/builders/buildUIActions.ts +3 -1
  44. package/src/ui/containers/AppContainer/builders/buildUIState.ts +5 -4
  45. package/src/ui/containers/AppContainer/hooks/useAppDialogs.ts +2 -14
  46. package/src/ui/containers/AppContainer/hooks/useAppInput.ts +19 -1
  47. package/src/ui/containers/AppContainer/hooks/useAppLayout.ts +90 -38
  48. package/src/ui/containers/AppContainer/hooks/useDisplayPreferences.ts +10 -0
  49. package/src/ui/containers/AppContainer/hooks/useInputHandling.ts +3 -1
  50. package/src/ui/containers/AppContainer/hooks/useKeybindings.ts +51 -38
  51. package/src/ui/containers/AppContainer/hooks/useSteer.ts +51 -0
  52. package/src/ui/contexts/KeypressContext.tsx +13 -2
  53. package/src/ui/contexts/ShellCommandDisplayContext.tsx +103 -0
  54. package/src/ui/contexts/UIActionsContext.tsx +2 -1
  55. package/src/ui/contexts/UIStateContext.tsx +3 -2
  56. package/src/ui/hooks/agentStream/streamUtils.ts +0 -24
  57. package/src/ui/hooks/agentStream/thoughtState.ts +110 -30
  58. package/src/ui/hooks/agentStream/types.ts +1 -0
  59. package/src/ui/hooks/agentStream/useAgentStream.ts +2 -0
  60. package/src/ui/hooks/agentStream/useAgentStreamLifecycle.ts +4 -5
  61. package/src/ui/hooks/agentStream/useAgentStreamOrchestration.ts +10 -1
  62. package/src/ui/hooks/agentStream/useQueuedSubmissions.ts +99 -0
  63. package/src/ui/hooks/agentStream/useStreamEventHandlers.ts +4 -13
  64. package/src/ui/hooks/agentStream/useStreamState.ts +60 -41
  65. package/src/ui/hooks/agentStream/useSubmitQuery.ts +284 -59
  66. package/src/ui/hooks/slashCommandProcessorSupport.ts +4 -0
  67. package/src/ui/hooks/useAgentStream-test-helpers.ts +1 -0
  68. package/src/ui/hooks/useAutoAcceptIndicator.ts +13 -0
  69. package/src/ui/hooks/useFolderTrust.ts +118 -81
  70. package/src/ui/hooks/useGitBranchName.ts +79 -33
  71. package/src/ui/hooks/useIdeTrustListener.ts +5 -19
  72. package/src/ui/hooks/usePermissionsModifyTrust.ts +223 -85
  73. package/src/ui/layouts/DefaultAppLayout.tsx +2 -0
  74. package/src/ui/layouts/DefaultAppLayoutHelpers.tsx +37 -162
  75. package/src/ui/layouts/InlineContent.tsx +198 -0
  76. package/src/ui/trustDialogHelpers.ts +190 -0
  77. package/src/utils/cleanup.ts +11 -0
  78. package/src/utils/sandbox-containers.ts +183 -53
  79. package/src/utils/sandbox-exec.ts +9 -3
  80. package/src/zed-integration/acp-terminal-shell-host.ts +112 -0
  81. package/src/zed-integration/acp-types.ts +35 -0
  82. package/src/zed-integration/fileSystemService.ts +1 -1
  83. package/src/zed-integration/runZedIntegration.ts +142 -0
  84. package/src/zed-integration/zed-agent-event-handler.ts +179 -0
  85. package/src/zed-integration/zed-agent-setup.ts +43 -0
  86. package/src/zed-integration/zed-command-registry.ts +167 -0
  87. package/src/zed-integration/zed-config-options.ts +280 -0
  88. package/src/zed-integration/zed-content-utils.ts +2 -2
  89. package/src/zed-integration/zed-helpers.ts +132 -0
  90. package/src/zed-integration/zed-initialize.ts +64 -0
  91. package/src/zed-integration/zed-plan-update.ts +20 -0
  92. package/src/zed-integration/zed-prompt-command.ts +77 -0
  93. package/src/zed-integration/zed-session-config.ts +119 -0
  94. package/src/zed-integration/zed-session-errors.ts +337 -0
  95. package/src/zed-integration/zed-session-events.ts +216 -0
  96. package/src/zed-integration/zed-session-info.ts +255 -0
  97. package/src/zed-integration/zed-session-lifecycle.ts +186 -0
  98. package/src/zed-integration/zed-session-listing.ts +153 -0
  99. package/src/zed-integration/zed-session-loader.ts +193 -0
  100. package/src/zed-integration/zed-session-pagination.ts +240 -0
  101. package/src/zed-integration/zed-session-replay.ts +564 -0
  102. package/src/zed-integration/zed-stream-batcher.ts +236 -0
  103. package/src/zed-integration/zed-terminal-manager.ts +416 -0
  104. package/src/zed-integration/zed-terminal-setup.ts +72 -0
  105. package/src/zed-integration/zed-test-helpers.ts +349 -4
  106. package/src/zed-integration/zed-tool-handler.ts +47 -5
  107. package/src/zed-integration/zedIntegration.ts +538 -587
  108. package/src/ui/containers/AppContainer/hooks/useIdeRestartHotkey.ts +0 -33
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vybestack/llxprt-code",
3
- "version": "0.10.0",
3
+ "version": "0.11.0-nightly.260727.c4abf5792",
4
4
  "description": "LLxprt Code",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -44,24 +44,24 @@
44
44
  "!**/__snapshots__/**"
45
45
  ],
46
46
  "config": {
47
- "sandboxImageUri": "ghcr.io/vybestack/llxprt-code/sandbox:0.10.0"
47
+ "sandboxImageUri": "ghcr.io/vybestack/llxprt-code/sandbox:0.11.0-nightly.260727.c4abf5792"
48
48
  },
49
49
  "dependencies": {
50
- "@vybestack/llxprt-code-storage": "0.10.0",
51
- "@agentclientprotocol/sdk": "^0.14.1",
50
+ "@vybestack/llxprt-code-storage": "0.11.0-nightly.260727.c4abf5792",
51
+ "@agentclientprotocol/sdk": "^1.2.1",
52
52
  "@anthropic-ai/sdk": "^0.55.1",
53
53
  "@dqbd/tiktoken": "^1.0.21",
54
54
  "@iarna/toml": "^2.2.5",
55
55
  "@modelcontextprotocol/sdk": "^1.25.2",
56
- "@vybestack/llxprt-code-auth": "0.10.0",
57
- "@vybestack/llxprt-code-core": "0.10.0",
58
- "@vybestack/llxprt-code-ide-integration": "0.10.0",
59
- "@vybestack/llxprt-code-mcp": "0.10.0",
60
- "@vybestack/llxprt-code-providers": "0.10.0",
61
- "@vybestack/llxprt-code-agents": "0.10.0",
62
- "@vybestack/llxprt-code-settings": "0.10.0",
63
- "@vybestack/llxprt-code-telemetry": "0.10.0",
64
- "@vybestack/llxprt-code-tools": "0.10.0",
56
+ "@vybestack/llxprt-code-auth": "0.11.0-nightly.260727.c4abf5792",
57
+ "@vybestack/llxprt-code-core": "0.11.0-nightly.260727.c4abf5792",
58
+ "@vybestack/llxprt-code-ide-integration": "0.11.0-nightly.260727.c4abf5792",
59
+ "@vybestack/llxprt-code-mcp": "0.11.0-nightly.260727.c4abf5792",
60
+ "@vybestack/llxprt-code-providers": "0.11.0-nightly.260727.c4abf5792",
61
+ "@vybestack/llxprt-code-agents": "0.11.0-nightly.260727.c4abf5792",
62
+ "@vybestack/llxprt-code-settings": "0.11.0-nightly.260727.c4abf5792",
63
+ "@vybestack/llxprt-code-telemetry": "0.11.0-nightly.260727.c4abf5792",
64
+ "@vybestack/llxprt-code-tools": "0.11.0-nightly.260727.c4abf5792",
65
65
  "ansi-regex": "^6.2.2",
66
66
  "bun": "1.3.14",
67
67
  "chalk": "^5.3.0",
@@ -78,7 +78,7 @@ function parseEnvEntries(
78
78
 
79
79
  function createHttpServerConfig(
80
80
  commandOrUrl: string,
81
- type: 'sse' | 'http',
81
+ type: 'sse' | 'http' | 'streamable-http',
82
82
  headers: Record<string, string> | undefined,
83
83
  options: SharedServerOptions,
84
84
  ): Partial<MCPServerConfig> {
@@ -117,7 +117,11 @@ function createServerConfig(
117
117
  excludeTools: options.excludeTools,
118
118
  };
119
119
  const headers = parseHeaderEntries(options.header);
120
- if (options.transport === 'sse' || options.transport === 'http') {
120
+ if (
121
+ options.transport === 'sse' ||
122
+ options.transport === 'http' ||
123
+ options.transport === 'streamable-http'
124
+ ) {
121
125
  return createHttpServerConfig(
122
126
  commandOrUrl,
123
127
  options.transport,
@@ -216,10 +220,10 @@ export const addCommand: CommandModule = {
216
220
  })
217
221
  .option('transport', {
218
222
  alias: ['t', 'type'],
219
- describe: 'Transport type (stdio, sse, http)',
223
+ describe: 'Transport type (stdio, sse, http, streamable-http)',
220
224
  type: 'string',
221
225
  default: 'stdio',
222
- choices: ['stdio', 'sse', 'http'],
226
+ choices: ['stdio', 'sse', 'http', 'streamable-http'],
223
227
  })
224
228
  .option('env', {
225
229
  alias: 'e',
@@ -37,6 +37,7 @@ export interface CliArgs {
37
37
  prompt: string | undefined;
38
38
  promptInteractive: string | undefined;
39
39
  outputFormat: string | undefined;
40
+ quiet: boolean | undefined;
40
41
 
41
42
  showMemoryUsage: boolean | undefined;
42
43
  yolo: boolean | undefined;
@@ -161,6 +162,7 @@ function mapParsedArgsToCliArgs(result: Record<string, unknown>): CliArgs {
161
162
  ),
162
163
  promptInteractive: result['promptInteractive'] as string | undefined,
163
164
  outputFormat: result['outputFormat'] as string | undefined,
165
+ quiet: result['quiet'] as boolean | undefined,
164
166
  showMemoryUsage: result['showMemoryUsage'] as boolean | undefined,
165
167
  yolo: result['yolo'] as boolean | undefined,
166
168
  approvalMode: result['approvalMode'] as string | undefined,
@@ -63,6 +63,7 @@ type ConfigBuildPieces = {
63
63
  extensionsEnabled: boolean;
64
64
  adminSkillsEnabled: boolean;
65
65
  outputFormat: Parameters<typeof buildConfig>[0]['outputFormat'];
66
+ quiet: boolean;
66
67
  allowedTools: readonly string[];
67
68
  };
68
69
 
@@ -267,6 +268,7 @@ function buildLoadedConfig(
267
268
  extensionsEnabled: pieces.extensionsEnabled,
268
269
  adminSkillsEnabled: pieces.adminSkillsEnabled,
269
270
  outputFormat: pieces.outputFormat,
271
+ quiet: pieces.quiet,
270
272
  allowedTools: pieces.allowedTools,
271
273
  });
272
274
  }
@@ -72,6 +72,7 @@ export interface ConfigBuildInput {
72
72
  readonly extensionsEnabled: boolean;
73
73
  readonly adminSkillsEnabled: boolean;
74
74
  readonly outputFormat: OutputFormat;
75
+ readonly quiet: boolean;
75
76
  readonly allowedTools: readonly string[];
76
77
  }
77
78
 
@@ -194,6 +195,7 @@ function buildSessionBaseArgs(
194
195
  filePaths,
195
196
  screenReader,
196
197
  outputFormat,
198
+ quiet,
197
199
  question,
198
200
  extensionsEnabled,
199
201
  adminSkillsEnabled,
@@ -209,6 +211,7 @@ function buildSessionBaseArgs(
209
211
  context.resolvedLoadMemoryFromIncludeDirectories,
210
212
  debugMode: context.debugMode,
211
213
  outputFormat,
214
+ quiet,
212
215
  question,
213
216
  ...toolConfig,
214
217
  extensionsEnabled,
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @license
3
+ * Copyright 2025 Vybestack LLC
4
+ * SPDX-License-Identifier: Apache-2.0
5
+ */
6
+
7
+ export interface ConfigFileError {
8
+ readonly path: string;
9
+ readonly message: string;
10
+ }
11
+
12
+ export function formatConfigFileErrors(
13
+ errors: readonly ConfigFileError[],
14
+ fileDescription = 'configuration file(s)',
15
+ ): string {
16
+ const details = errors.map(
17
+ (error) => `Error in ${error.path}: ${error.message}`,
18
+ );
19
+ const instruction = `Please fix the ${fileDescription} and try again.`;
20
+ return details.length === 0
21
+ ? instruction
22
+ : `${details.join('\n')}\n${instruction}`;
23
+ }
@@ -92,7 +92,8 @@ function resolveTrustAndIdeContext(
92
92
 
93
93
  // Trust uses originalSettings (not profile-merged) — security critical
94
94
  const folderTrust = originalSettings.folderTrust ?? false;
95
- const trustedFolder = isWorkspaceTrusted(originalSettings) ?? false;
95
+ const trustedFolder =
96
+ isWorkspaceTrusted(originalSettings, input.cwd) ?? false;
96
97
 
97
98
  return { debugMode, memoryImportFormat, ideMode, folderTrust, trustedFolder };
98
99
  }
@@ -30,6 +30,7 @@ export interface IntermediateConfig {
30
30
  readonly profileSettingsWithTools: Settings;
31
31
  readonly policyEngineConfig: PolicyEngineConfig;
32
32
  readonly outputFormat: OutputFormat;
33
+ readonly quiet: boolean;
33
34
  readonly useRipgrepSetting: boolean | undefined;
34
35
  readonly mcpEnabled: boolean;
35
36
  readonly extensionsEnabled: boolean;
@@ -84,9 +85,11 @@ export async function resolveIntermediateConfig(
84
85
  const policyEngineConfig = await createPolicyEngineConfig(
85
86
  profileSettingsWithTools,
86
87
  approvalMode,
88
+ context.trustedFolder,
87
89
  );
88
90
 
89
91
  const outputFormat = resolveOutputFormat(argv);
92
+ const quiet = argv.quiet ?? false;
90
93
 
91
94
  const useRipgrepSetting = await resolveRipgrepSetting(profileMergedSettings);
92
95
 
@@ -116,6 +119,7 @@ export async function resolveIntermediateConfig(
116
119
  profileSettingsWithTools,
117
120
  policyEngineConfig,
118
121
  outputFormat,
122
+ quiet,
119
123
  useRipgrepSetting,
120
124
  mcpEnabled,
121
125
  extensionsEnabled,
@@ -65,6 +65,7 @@ export enum Command {
65
65
 
66
66
  // Text Input
67
67
  SUBMIT = 'submit',
68
+ STEER = 'steer', // LLXPRT-SPECIFIC: mid-turn steering (Ctrl+Enter while streaming)
68
69
  NEWLINE = 'newline',
69
70
  OPEN_EXTERNAL_EDITOR = 'openExternalEditor',
70
71
  PASTE_CLIPBOARD = 'pasteClipboard',
@@ -73,6 +74,7 @@ export enum Command {
73
74
  SHOW_ERROR_DETAILS = 'showErrorDetails',
74
75
  TOGGLE_TOOL_DESCRIPTIONS = 'toggleToolDescriptions', // LLXPRT-SPECIFIC
75
76
  TOGGLE_TODO_DIALOG = 'toggleTodoDialog', // LLXPRT-SPECIFIC
77
+ TOGGLE_QUEUED_MESSAGES = 'toggleQueuedMessages', // LLXPRT-SPECIFIC
76
78
  SHOW_IDE_CONTEXT_DETAIL = 'showIDEContextDetail',
77
79
  TOGGLE_MARKDOWN = 'toggleMarkdown',
78
80
  TOGGLE_COPY_MODE = 'toggleCopyMode',
@@ -223,7 +225,7 @@ export const defaultKeyBindings: KeyBindingConfig = {
223
225
  [Command.COLLAPSE_SUGGESTION]: [{ key: 'left' }],
224
226
 
225
227
  // Text Input
226
- // Must also exclude shift to allow shift+enter for newline
228
+ // Must also exclude shift to allow shift+enter for multi-line input
227
229
  [Command.SUBMIT]: [
228
230
  {
229
231
  key: 'return',
@@ -232,8 +234,11 @@ export const defaultKeyBindings: KeyBindingConfig = {
232
234
  shift: false,
233
235
  },
234
236
  ],
235
- // Split into multiple data-driven bindings
236
- // Now also includes shift+enter for multi-line input
237
+ // Mid-turn steering: Ctrl+Enter while the agent is streaming injects the
238
+ // typed text at the next tool-call boundary. When not streaming, Ctrl+Enter
239
+ // falls through to NEWLINE (both match the same key; the handler checks
240
+ // STEER first and only consumes it when streaming).
241
+ [Command.STEER]: [{ key: 'return', ctrl: true }],
237
242
  [Command.NEWLINE]: [
238
243
  { key: 'return', ctrl: true },
239
244
  { key: 'return', command: true },
@@ -250,6 +255,7 @@ export const defaultKeyBindings: KeyBindingConfig = {
250
255
  [Command.SHOW_ERROR_DETAILS]: [{ key: 'o', ctrl: true }],
251
256
  [Command.TOGGLE_TOOL_DESCRIPTIONS]: [{ key: 't', ctrl: true }],
252
257
  [Command.TOGGLE_TODO_DIALOG]: [{ key: 'q', ctrl: true }],
258
+ [Command.TOGGLE_QUEUED_MESSAGES]: [{ key: ']', ctrl: true }],
253
259
  [Command.SHOW_IDE_CONTEXT_DETAIL]: [{ key: 'g', ctrl: true }],
254
260
  [Command.TOGGLE_MARKDOWN]: [{ key: 'm', command: true }],
255
261
  [Command.TOGGLE_COPY_MODE]: [{ key: 's', ctrl: true }],
@@ -273,6 +279,17 @@ export const defaultKeyBindings: KeyBindingConfig = {
273
279
  ],
274
280
  };
275
281
 
282
+ export function getDefaultKeyBindingHint(command: Command): string {
283
+ const binding = defaultKeyBindings[command][0];
284
+ const modifiers = [
285
+ binding.ctrl === true ? 'Ctrl' : undefined,
286
+ binding.command === true ? 'Cmd' : undefined,
287
+ binding.shift === true ? 'Shift' : undefined,
288
+ ].filter((modifier): modifier is string => modifier !== undefined);
289
+ const key = binding.key ?? binding.sequence ?? '';
290
+ return [...modifiers, key].join('+');
291
+ }
292
+
276
293
  interface CommandCategory {
277
294
  readonly title: string;
278
295
  readonly commands: readonly Command[];
@@ -357,6 +374,7 @@ export const commandCategories: readonly CommandCategory[] = [
357
374
  title: 'Text Input',
358
375
  commands: [
359
376
  Command.SUBMIT,
377
+ Command.STEER,
360
378
  Command.NEWLINE,
361
379
  Command.OPEN_EXTERNAL_EDITOR,
362
380
  Command.PASTE_CLIPBOARD,
@@ -383,6 +401,10 @@ export const commandCategories: readonly CommandCategory[] = [
383
401
  title: 'Todo Dialog',
384
402
  commands: [Command.TOGGLE_TODO_DIALOG, Command.TOGGLE_TOOL_DESCRIPTIONS],
385
403
  },
404
+ {
405
+ title: 'Queued Messages',
406
+ commands: [Command.TOGGLE_QUEUED_MESSAGES],
407
+ },
386
408
  {
387
409
  title: 'Mouse',
388
410
  commands: [Command.TOGGLE_MOUSE_EVENTS],
@@ -452,6 +474,8 @@ export const commandDescriptions: Readonly<Record<Command, string>> = {
452
474
 
453
475
  // Text Input
454
476
  [Command.SUBMIT]: 'Submit the current prompt.',
477
+ [Command.STEER]:
478
+ 'Steer the active agent mid-turn by injecting input at the next tool-call boundary (only during streaming).',
455
479
  [Command.NEWLINE]: 'Insert a newline without submitting.',
456
480
  [Command.OPEN_EXTERNAL_EDITOR]:
457
481
  'Open the current prompt in an external editor.',
@@ -462,6 +486,8 @@ export const commandDescriptions: Readonly<Record<Command, string>> = {
462
486
  [Command.SHOW_ERROR_DETAILS]: 'Toggle detailed error information.',
463
487
  [Command.TOGGLE_TOOL_DESCRIPTIONS]: 'Toggle tool descriptions display.',
464
488
  [Command.TOGGLE_TODO_DIALOG]: 'Toggle the TODO dialog visibility.',
489
+ [Command.TOGGLE_QUEUED_MESSAGES]:
490
+ 'Toggle the queued messages panel visibility.',
465
491
  [Command.SHOW_IDE_CONTEXT_DETAIL]: 'Show IDE context details.',
466
492
  [Command.TOGGLE_MARKDOWN]: 'Toggle Markdown rendering.',
467
493
  [Command.TOGGLE_COPY_MODE]: 'Toggle copy mode when in alternate buffer mode.',
@@ -18,6 +18,7 @@ import { type Settings } from './settings.js';
18
18
  export async function createPolicyEngineConfig(
19
19
  settings: Settings,
20
20
  approvalMode: ApprovalMode,
21
+ trustedFolder = true,
21
22
  ): Promise<PolicyEngineConfig> {
22
23
  // Explicitly construct PolicySettings from Settings to ensure type safety
23
24
  // and avoid accidental leakage of other settings properties.
@@ -38,7 +39,12 @@ export async function createPolicyEngineConfig(
38
39
  mcpServers: settings.mcpServers,
39
40
  };
40
41
 
41
- return createCorePolicyEngineConfig(policySettings, approvalMode);
42
+ return createCorePolicyEngineConfig(
43
+ policySettings,
44
+ approvalMode,
45
+ undefined,
46
+ trustedFolder,
47
+ );
42
48
  }
43
49
 
44
50
  export function createPolicyUpdater(
@@ -14,7 +14,10 @@ import {
14
14
  } from '@vybestack/llxprt-code-core';
15
15
  import { DebugLogger } from '@vybestack/llxprt-code-telemetry';
16
16
  import { ProfileManager } from '@vybestack/llxprt-code-settings';
17
- import type { SettingsService } from '@vybestack/llxprt-code-settings';
17
+ import type {
18
+ EphemeralSettings,
19
+ SettingsService,
20
+ } from '@vybestack/llxprt-code-settings';
18
21
  import {
19
22
  getCliRuntimeContext,
20
23
  setCliRuntimeContext,
@@ -51,7 +54,7 @@ export interface PostConfigInput {
51
54
  readonly bootstrapArgs: BootstrapProfileArgs;
52
55
  readonly argv: CliArgs;
53
56
  readonly settings: Settings;
54
- readonly profileSettingsWithTools: Settings;
57
+ readonly profileSettingsWithTools: Settings & EphemeralSettings;
55
58
  readonly profileLoadResult: ProfileLoadResult;
56
59
  readonly providerModelResult: ProviderModelResult;
57
60
  readonly defaultDisabledTools: readonly string[];
@@ -152,7 +155,11 @@ interface ProfileEphemeralSettingsInput {
152
155
  readonly bootstrapArgs: Pick<BootstrapProfileArgs, 'profileJson'>;
153
156
  readonly argv: Pick<CliArgs, 'provider'>;
154
157
  readonly settings: StreamTimeoutSettingsInput;
155
- readonly profileSettingsWithTools: StreamTimeoutSettingsInput;
158
+ // profileSettingsWithTools carries both the public JSON settings and the
159
+ // ephemeral tool-governance keys (e.g. 'tools.allowed') that
160
+ // applyGlobalAndProfileEphemeralSettings forwards to applyToolPolicies.
161
+ readonly profileSettingsWithTools: StreamTimeoutSettingsInput &
162
+ EphemeralSettings;
156
163
  readonly profileLoadResult: Pick<ProfileLoadResult, 'profileToLoad'>;
157
164
  }
158
165
 
@@ -472,9 +479,9 @@ function applyToolPolicies(input: ApplyToolPoliciesInput): void {
472
479
  : (profileSettingsWithTools.allowedTools ?? []),
473
480
  );
474
481
 
475
- const profileAllowedTools = buildNormalizedToolSet(
476
- config.getEphemeralSetting('tools.allowed'),
477
- );
482
+ const rawProfileAllowedTools = profileSettingsWithTools['tools.allowed'];
483
+ const profileAllowedExplicit = Array.isArray(rawProfileAllowedTools);
484
+ const profileAllowedTools = buildNormalizedToolSet(rawProfileAllowedTools);
478
485
 
479
486
  const applyPolicy = (allowedSet: Set<string> | undefined): void => {
480
487
  if (allowedSet === undefined) {
@@ -491,7 +498,7 @@ function applyToolPolicies(input: ApplyToolPoliciesInput): void {
491
498
 
492
499
  if (interactive !== true && experimentalAcp !== true) {
493
500
  if (approvalMode === ApprovalMode.YOLO) {
494
- if (profileAllowedTools.size > 0 || explicitAllowedTools.size > 0) {
501
+ if (profileAllowedExplicit || explicitAllowedTools.size > 0) {
495
502
  const finalAllowed = new Set(profileAllowedTools);
496
503
  explicitAllowedTools.forEach((tool) => finalAllowed.add(tool));
497
504
  applyPolicy(finalAllowed);
@@ -507,16 +514,15 @@ function applyToolPolicies(input: ApplyToolPoliciesInput): void {
507
514
  baseAllowed.add(EDIT_TOOL_NAME);
508
515
  }
509
516
 
510
- const finalAllowed =
511
- profileAllowedTools.size > 0
512
- ? new Set(
513
- [...baseAllowed].filter((tool) => profileAllowedTools.has(tool)),
514
- )
515
- : baseAllowed;
517
+ const finalAllowed = profileAllowedExplicit
518
+ ? new Set(
519
+ [...baseAllowed].filter((tool) => profileAllowedTools.has(tool)),
520
+ )
521
+ : baseAllowed;
516
522
 
517
523
  applyPolicy(finalAllowed);
518
524
  }
519
- } else if (profileAllowedTools.size > 0 || explicitAllowedTools.size > 0) {
525
+ } else if (profileAllowedExplicit || explicitAllowedTools.size > 0) {
520
526
  const finalAllowed = new Set(profileAllowedTools);
521
527
  explicitAllowedTools.forEach((tool) => finalAllowed.add(tool));
522
528
  applyPolicy(finalAllowed);
@@ -192,6 +192,15 @@ export const UI_SETTINGS_SCHEMA = {
192
192
  description: 'Display memory usage information in the UI',
193
193
  showInDialog: true,
194
194
  },
195
+ alwaysDisplayFullShellCommand: {
196
+ type: 'boolean',
197
+ label: 'Always Display Full Shell Command',
198
+ category: 'UI',
199
+ requiresRestart: false,
200
+ default: true,
201
+ description: 'Display complete shell commands without truncation.',
202
+ showInDialog: true,
203
+ },
195
204
  showLineNumbers: {
196
205
  type: 'boolean',
197
206
  label: 'Show Line Numbers',
@@ -11,6 +11,7 @@ import type { Settings } from './settingsSchema.js';
11
11
  import { resolveEnvVarsInObject } from '../utils/envVarResolver.js';
12
12
  import { USER_SETTINGS_PATH } from './paths.js';
13
13
  import { mergeSettings } from './settingsMerge.js';
14
+ import { formatConfigFileErrors } from './configError.js';
14
15
  import {
15
16
  migrateHooksConfig,
16
17
  migrateLegacyInteractiveShellSetting,
@@ -100,12 +101,11 @@ function loadOptionalSettingsFile(
100
101
  }
101
102
  }
102
103
 
103
- function resolveRealWorkspaceDir(workspaceDir: string): string {
104
- const resolvedWorkspaceDir = path.resolve(workspaceDir);
104
+ function resolveRealWorkspaceDir(workspaceDir: string): string | undefined {
105
105
  try {
106
- return fs.realpathSync(resolvedWorkspaceDir);
106
+ return fs.realpathSync(path.resolve(workspaceDir));
107
107
  } catch {
108
- return resolvedWorkspaceDir;
108
+ return undefined;
109
109
  }
110
110
  }
111
111
 
@@ -115,7 +115,7 @@ function loadSettingsFiles(
115
115
  ): {
116
116
  settings: SettingsState;
117
117
  errors: SettingsError[];
118
- realWorkspaceDir: string;
118
+ realWorkspaceDir: string | undefined;
119
119
  realHomeDir: string;
120
120
  } {
121
121
  const errors: SettingsError[] = [];
@@ -133,7 +133,7 @@ function loadSettingsFiles(
133
133
  legacyTheme: true,
134
134
  });
135
135
  const workspace =
136
- realWorkspaceDir === realHomeDir
136
+ realWorkspaceDir === undefined || realWorkspaceDir === realHomeDir
137
137
  ? {}
138
138
  : loadOptionalSettingsFile(paths.workspace, errors, {
139
139
  legacyTheme: true,
@@ -156,7 +156,10 @@ function shouldCheckFolderTrust(settings: SettingsState): boolean {
156
156
  return folderTrustFeature && folderTrustEnabled;
157
157
  }
158
158
 
159
- function resolveTrustedState(settings: SettingsState): boolean {
159
+ function resolveTrustedState(
160
+ settings: SettingsState,
161
+ workspaceDir: string | undefined,
162
+ ): boolean {
160
163
  const tempSettingsForTrust = mergeSettings(
161
164
  settings.system,
162
165
  settings.systemDefaults,
@@ -164,9 +167,12 @@ function resolveTrustedState(settings: SettingsState): boolean {
164
167
  settings.workspace,
165
168
  true,
166
169
  );
167
- return shouldCheckFolderTrust(settings)
168
- ? (isWorkspaceTrusted(tempSettingsForTrust) ?? true)
169
- : true;
170
+ if (!shouldCheckFolderTrust(settings)) {
171
+ return true;
172
+ }
173
+ return workspaceDir === undefined
174
+ ? false
175
+ : (isWorkspaceTrusted(tempSettingsForTrust, workspaceDir) ?? false);
170
176
  }
171
177
 
172
178
  function loadEnvironmentAndResolveSettings(
@@ -193,12 +199,7 @@ function throwSettingsErrors(errors: SettingsError[]): void {
193
199
  if (errors.length === 0) {
194
200
  return;
195
201
  }
196
- const errorMessages = errors.map(
197
- (error) => `Error in ${error.path}: ${error.message}`,
198
- );
199
- throw new FatalConfigError(
200
- `${errorMessages.join('\n')}\nPlease fix the configuration file(s) and try again.`,
201
- );
202
+ throw new FatalConfigError(formatConfigFileErrors(errors));
202
203
  }
203
204
 
204
205
  function migrateLoadedSettings(settings: SettingsState): void {
@@ -237,7 +238,10 @@ export function loadSettings(
237
238
  workspace: new Storage(workspaceDir).getWorkspaceSettingsPath(),
238
239
  };
239
240
  const loaded = loadSettingsFiles(workspaceDir, paths);
240
- const isTrusted = resolveTrustedState(loaded.settings);
241
+ const isTrusted = resolveTrustedState(
242
+ loaded.settings,
243
+ loaded.realWorkspaceDir,
244
+ );
241
245
  const settings = loadEnvironmentAndResolveSettings(
242
246
  loaded.settings,
243
247
  isTrusted,
@@ -76,8 +76,8 @@ export const SETTINGS_SCHEMA_DEFINITIONS: Record<
76
76
  type: {
77
77
  type: 'string',
78
78
  description:
79
- 'Transport type. Use "stdio" for local command, "sse" for Server-Sent Events, or "http" for Streamable HTTP.',
80
- enum: ['stdio', 'sse', 'http'],
79
+ 'Transport type. Use "stdio" for local command, "sse" for Server-Sent Events, "http" for Streamable HTTP, or "streamable-http" as an alias for "http".',
80
+ enum: ['stdio', 'sse', 'http', 'streamable-http'],
81
81
  },
82
82
  timeout: {
83
83
  type: 'number',