@vybestack/llxprt-code 0.1.14-nightly.250729.2076f7c6 → 0.1.15
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/README.md +53 -0
- package/dist/package.json +4 -5
- package/dist/src/config/extension.d.ts +1 -0
- package/dist/src/config/extension.js +4 -0
- package/dist/src/config/extension.js.map +1 -1
- package/dist/src/config/settings.d.ts +2 -1
- package/dist/src/config/settings.js.map +1 -1
- package/dist/src/gemini.d.ts +1 -0
- package/dist/src/gemini.js +35 -15
- package/dist/src/gemini.js.map +1 -1
- package/dist/src/generated/git-commit.d.ts +1 -1
- package/dist/src/generated/git-commit.js +1 -1
- package/dist/src/services/BuiltinCommandLoader.js +2 -0
- package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
- package/dist/src/services/CommandService.d.ts +8 -4
- package/dist/src/services/CommandService.js +24 -8
- package/dist/src/services/CommandService.js.map +1 -1
- package/dist/src/services/FileCommandLoader.d.ts +15 -3
- package/dist/src/services/FileCommandLoader.js +94 -42
- package/dist/src/services/FileCommandLoader.js.map +1 -1
- package/dist/src/services/McpPromptLoader.d.ts +25 -0
- package/dist/src/services/McpPromptLoader.js +192 -0
- package/dist/src/services/McpPromptLoader.js.map +1 -0
- package/dist/src/services/prompt-processors/shellProcessor.d.ts +32 -0
- package/dist/src/services/prompt-processors/shellProcessor.js +77 -0
- package/dist/src/services/prompt-processors/shellProcessor.js.map +1 -0
- package/dist/src/services/prompt-processors/types.d.ts +4 -0
- package/dist/src/services/prompt-processors/types.js +4 -0
- package/dist/src/services/prompt-processors/types.js.map +1 -1
- package/dist/src/ui/App.js +312 -195
- package/dist/src/ui/App.js.map +1 -1
- package/dist/src/ui/commands/chatCommand.js +39 -1
- package/dist/src/ui/commands/chatCommand.js.map +1 -1
- package/dist/src/ui/commands/initCommand.d.ts +7 -0
- package/dist/src/ui/commands/initCommand.js +76 -0
- package/dist/src/ui/commands/initCommand.js.map +1 -0
- package/dist/src/ui/commands/mcpCommand.js +53 -8
- package/dist/src/ui/commands/mcpCommand.js.map +1 -1
- package/dist/src/ui/commands/types.d.ts +22 -3
- package/dist/src/ui/commands/types.js +1 -0
- package/dist/src/ui/commands/types.js.map +1 -1
- package/dist/src/ui/commands/vimCommand.js +0 -7
- package/dist/src/ui/commands/vimCommand.js.map +1 -1
- package/dist/src/ui/components/ContextSummaryDisplay.d.ts +3 -3
- package/dist/src/ui/components/ContextSummaryDisplay.js +8 -8
- package/dist/src/ui/components/ContextSummaryDisplay.js.map +1 -1
- package/dist/src/ui/components/Footer.d.ts +1 -0
- package/dist/src/ui/components/Footer.js +2 -2
- package/dist/src/ui/components/Footer.js.map +1 -1
- package/dist/src/ui/components/Header.js +1 -1
- package/dist/src/ui/components/Header.js.map +1 -1
- package/dist/src/ui/components/Help.js +2 -2
- package/dist/src/ui/components/Help.js.map +1 -1
- package/dist/src/ui/components/IDEContextDetailDisplay.d.ts +4 -4
- package/dist/src/ui/components/IDEContextDetailDisplay.js +5 -7
- package/dist/src/ui/components/IDEContextDetailDisplay.js.map +1 -1
- package/dist/src/ui/components/InputPrompt.d.ts +2 -0
- package/dist/src/ui/components/InputPrompt.js +5 -1
- package/dist/src/ui/components/InputPrompt.js.map +1 -1
- package/dist/src/ui/components/ShellConfirmationDialog.d.ts +15 -0
- package/dist/src/ui/components/ShellConfirmationDialog.js +45 -0
- package/dist/src/ui/components/ShellConfirmationDialog.js.map +1 -0
- package/dist/src/ui/components/Tips.js +1 -1
- package/dist/src/ui/components/Tips.js.map +1 -1
- package/dist/src/ui/components/shared/text-buffer.d.ts +270 -2
- package/dist/src/ui/components/shared/text-buffer.js +415 -70
- package/dist/src/ui/components/shared/text-buffer.js.map +1 -1
- package/dist/src/ui/components/shared/vim-buffer-actions.d.ts +72 -0
- package/dist/src/ui/components/shared/vim-buffer-actions.js +565 -0
- package/dist/src/ui/components/shared/vim-buffer-actions.js.map +1 -0
- package/dist/src/ui/contexts/VimModeContext.js +2 -2
- package/dist/src/ui/contexts/VimModeContext.js.map +1 -1
- package/dist/src/ui/hooks/shellCommandProcessor.d.ts +1 -0
- package/dist/src/ui/hooks/shellCommandProcessor.js +139 -200
- package/dist/src/ui/hooks/shellCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/slashCommandProcessor.d.ts +7 -3
- package/dist/src/ui/hooks/slashCommandProcessor.js +208 -129
- package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/useCompletion.js +7 -2
- package/dist/src/ui/hooks/useCompletion.js.map +1 -1
- package/dist/src/ui/hooks/useConsoleMessages.js +53 -37
- package/dist/src/ui/hooks/useConsoleMessages.js.map +1 -1
- package/dist/src/ui/hooks/useGeminiStream.js +14 -2
- package/dist/src/ui/hooks/useGeminiStream.js.map +1 -1
- package/dist/src/ui/hooks/useKeypress.js +5 -2
- package/dist/src/ui/hooks/useKeypress.js.map +1 -1
- package/dist/src/ui/hooks/useReactToolScheduler.js +0 -1
- package/dist/src/ui/hooks/useReactToolScheduler.js.map +1 -1
- package/dist/src/ui/hooks/vim.d.ts +28 -0
- package/dist/src/ui/hooks/vim.js +630 -0
- package/dist/src/ui/hooks/vim.js.map +1 -0
- package/dist/src/ui/themes/theme-manager.js +10 -1
- package/dist/src/ui/themes/theme-manager.js.map +1 -1
- package/dist/src/ui/themes/theme.d.ts +1 -0
- package/dist/src/ui/themes/theme.js +19 -4
- package/dist/src/ui/themes/theme.js.map +1 -1
- package/dist/src/ui/utils/textUtils.d.ts +0 -8
- package/dist/src/ui/utils/textUtils.js +0 -22
- package/dist/src/ui/utils/textUtils.js.map +1 -1
- package/dist/src/ui/utils/updateCheck.d.ts +7 -1
- package/dist/src/ui/utils/updateCheck.js +17 -28
- package/dist/src/ui/utils/updateCheck.js.map +1 -1
- package/dist/src/utils/events.d.ts +11 -0
- package/dist/src/utils/events.js +13 -0
- package/dist/src/utils/events.js.map +1 -0
- package/dist/src/utils/handleAutoUpdate.d.ts +10 -0
- package/dist/src/utils/handleAutoUpdate.js +97 -0
- package/dist/src/utils/handleAutoUpdate.js.map +1 -0
- package/dist/src/utils/installationInfo.d.ts +23 -0
- package/dist/src/utils/installationInfo.js +154 -0
- package/dist/src/utils/installationInfo.js.map +1 -0
- package/dist/src/utils/updateEventEmitter.d.ts +11 -0
- package/dist/src/utils/updateEventEmitter.js +12 -0
- package/dist/src/utils/updateEventEmitter.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -5
@@ -3,148 +3,17 @@
|
|
3
3
|
* Copyright 2025 Google LLC
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
5
5
|
*/
|
6
|
-
import { spawn } from 'child_process';
|
7
|
-
import { TextDecoder } from 'util';
|
8
6
|
import { ToolCallStatus, } from '../types.js';
|
9
7
|
import { useCallback } from 'react';
|
10
|
-
import {
|
11
|
-
import { formatMemoryUsage } from '../utils/formatters.js';
|
12
|
-
import { isBinary } from '../utils/textUtils.js';
|
8
|
+
import { isBinary, ShellExecutionService, } from '@vybestack/llxprt-code-core';
|
13
9
|
import { SHELL_COMMAND_NAME } from '../constants.js';
|
10
|
+
import { formatMemoryUsage } from '../utils/formatters.js';
|
14
11
|
import crypto from 'crypto';
|
15
12
|
import path from 'path';
|
16
13
|
import os from 'os';
|
17
14
|
import fs from 'fs';
|
18
|
-
|
19
|
-
const OUTPUT_UPDATE_INTERVAL_MS = 1000;
|
15
|
+
export const OUTPUT_UPDATE_INTERVAL_MS = 1000;
|
20
16
|
const MAX_OUTPUT_LENGTH = 10000;
|
21
|
-
/**
|
22
|
-
* Executes a shell command using `spawn`, capturing all output and lifecycle events.
|
23
|
-
* This is the single, unified implementation for shell execution.
|
24
|
-
*
|
25
|
-
* @param commandToExecute The exact command string to run.
|
26
|
-
* @param cwd The working directory to execute the command in.
|
27
|
-
* @param abortSignal An AbortSignal to terminate the process.
|
28
|
-
* @param onOutputChunk A callback for streaming real-time output.
|
29
|
-
* @param onDebugMessage A callback for logging debug information.
|
30
|
-
* @returns A promise that resolves with the complete execution result.
|
31
|
-
*/
|
32
|
-
function executeShellCommand(commandToExecute, cwd, abortSignal, onOutputChunk, onDebugMessage) {
|
33
|
-
return new Promise((resolve) => {
|
34
|
-
const isWindows = os.platform() === 'win32';
|
35
|
-
const shell = isWindows ? 'cmd.exe' : 'bash';
|
36
|
-
const shellArgs = isWindows
|
37
|
-
? ['/c', commandToExecute]
|
38
|
-
: ['-c', commandToExecute];
|
39
|
-
const child = spawn(shell, shellArgs, {
|
40
|
-
cwd,
|
41
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
42
|
-
detached: !isWindows, // Use process groups on non-Windows for robust killing
|
43
|
-
env: {
|
44
|
-
...process.env,
|
45
|
-
GEMINI_CLI: '1',
|
46
|
-
},
|
47
|
-
});
|
48
|
-
// Use decoders to handle multi-byte characters safely (for streaming output).
|
49
|
-
let stdoutDecoder = null;
|
50
|
-
let stderrDecoder = null;
|
51
|
-
let stdout = '';
|
52
|
-
let stderr = '';
|
53
|
-
const outputChunks = [];
|
54
|
-
let error = null;
|
55
|
-
let exited = false;
|
56
|
-
let streamToUi = true;
|
57
|
-
const MAX_SNIFF_SIZE = 4096;
|
58
|
-
let sniffedBytes = 0;
|
59
|
-
const handleOutput = (data, stream) => {
|
60
|
-
if (!stdoutDecoder || !stderrDecoder) {
|
61
|
-
const encoding = getCachedEncodingForBuffer(data);
|
62
|
-
stdoutDecoder = new TextDecoder(encoding);
|
63
|
-
stderrDecoder = new TextDecoder(encoding);
|
64
|
-
}
|
65
|
-
outputChunks.push(data);
|
66
|
-
if (streamToUi && sniffedBytes < MAX_SNIFF_SIZE) {
|
67
|
-
// Use a limited-size buffer for the check to avoid performance issues.
|
68
|
-
const sniffBuffer = Buffer.concat(outputChunks.slice(0, 20));
|
69
|
-
sniffedBytes = sniffBuffer.length;
|
70
|
-
if (isBinary(sniffBuffer)) {
|
71
|
-
streamToUi = false;
|
72
|
-
// Overwrite any garbled text that may have streamed with a clear message.
|
73
|
-
onOutputChunk('[Binary output detected. Halting stream...]');
|
74
|
-
}
|
75
|
-
}
|
76
|
-
const decodedChunk = stream === 'stdout'
|
77
|
-
? stdoutDecoder.decode(data, { stream: true })
|
78
|
-
: stderrDecoder.decode(data, { stream: true });
|
79
|
-
if (stream === 'stdout') {
|
80
|
-
stdout += stripAnsi(decodedChunk);
|
81
|
-
}
|
82
|
-
else {
|
83
|
-
stderr += stripAnsi(decodedChunk);
|
84
|
-
}
|
85
|
-
if (!exited && streamToUi) {
|
86
|
-
// Send only the new chunk to avoid re-rendering the whole output.
|
87
|
-
const combinedOutput = stdout + (stderr ? `\n${stderr}` : '');
|
88
|
-
onOutputChunk(combinedOutput);
|
89
|
-
}
|
90
|
-
else if (!exited && !streamToUi) {
|
91
|
-
// Send progress updates for the binary stream
|
92
|
-
const totalBytes = outputChunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
93
|
-
onOutputChunk(`[Receiving binary output... ${formatMemoryUsage(totalBytes)} received]`);
|
94
|
-
}
|
95
|
-
};
|
96
|
-
child.stdout.on('data', (data) => handleOutput(data, 'stdout'));
|
97
|
-
child.stderr.on('data', (data) => handleOutput(data, 'stderr'));
|
98
|
-
child.on('error', (err) => {
|
99
|
-
error = err;
|
100
|
-
});
|
101
|
-
const abortHandler = async () => {
|
102
|
-
if (child.pid && !exited) {
|
103
|
-
onDebugMessage(`Aborting shell command (PID: ${child.pid})`);
|
104
|
-
if (isWindows) {
|
105
|
-
spawn('taskkill', ['/pid', child.pid.toString(), '/f', '/t']);
|
106
|
-
}
|
107
|
-
else {
|
108
|
-
try {
|
109
|
-
// Kill the entire process group (negative PID).
|
110
|
-
// SIGTERM first, then SIGKILL if it doesn't die.
|
111
|
-
process.kill(-child.pid, 'SIGTERM');
|
112
|
-
await new Promise((res) => setTimeout(res, 200));
|
113
|
-
if (!exited) {
|
114
|
-
process.kill(-child.pid, 'SIGKILL');
|
115
|
-
}
|
116
|
-
}
|
117
|
-
catch (_e) {
|
118
|
-
// Fall back to killing just the main process if group kill fails.
|
119
|
-
if (!exited)
|
120
|
-
child.kill('SIGKILL');
|
121
|
-
}
|
122
|
-
}
|
123
|
-
}
|
124
|
-
};
|
125
|
-
abortSignal.addEventListener('abort', abortHandler, { once: true });
|
126
|
-
child.on('exit', (code, signal) => {
|
127
|
-
exited = true;
|
128
|
-
abortSignal.removeEventListener('abort', abortHandler);
|
129
|
-
// Handle any final bytes lingering in the decoders
|
130
|
-
if (stdoutDecoder) {
|
131
|
-
stdout += stdoutDecoder.decode();
|
132
|
-
}
|
133
|
-
if (stderrDecoder) {
|
134
|
-
stderr += stderrDecoder.decode();
|
135
|
-
}
|
136
|
-
const finalBuffer = Buffer.concat(outputChunks);
|
137
|
-
resolve({
|
138
|
-
rawOutput: finalBuffer,
|
139
|
-
output: stdout + (stderr ? `\n${stderr}` : ''),
|
140
|
-
exitCode: code,
|
141
|
-
signal,
|
142
|
-
error,
|
143
|
-
aborted: abortSignal.aborted,
|
144
|
-
});
|
145
|
-
});
|
146
|
-
});
|
147
|
-
}
|
148
17
|
function addShellCommandToGeminiHistory(geminiClient, rawQuery, resultText) {
|
149
18
|
const modelContent = resultText.length > MAX_OUTPUT_LENGTH
|
150
19
|
? resultText.substring(0, MAX_OUTPUT_LENGTH) + '\n... (truncated)'
|
@@ -196,7 +65,11 @@ export const useShellCommandProcessor = (addItemToHistory, setPendingHistoryItem
|
|
196
65
|
commandToExecute = `{ ${command} }; __code=$?; pwd > "${pwdFilePath}"; exit $__code`;
|
197
66
|
}
|
198
67
|
const execPromise = new Promise((resolve) => {
|
199
|
-
let lastUpdateTime =
|
68
|
+
let lastUpdateTime = Date.now();
|
69
|
+
let cumulativeStdout = '';
|
70
|
+
let cumulativeStderr = '';
|
71
|
+
let isBinaryStream = false;
|
72
|
+
let binaryBytesReceived = 0;
|
200
73
|
const initialToolDisplay = {
|
201
74
|
callId,
|
202
75
|
name: SHELL_COMMAND_NAME,
|
@@ -209,85 +82,151 @@ export const useShellCommandProcessor = (addItemToHistory, setPendingHistoryItem
|
|
209
82
|
type: 'tool_group',
|
210
83
|
tools: [initialToolDisplay],
|
211
84
|
});
|
85
|
+
let executionPid;
|
86
|
+
const abortHandler = () => {
|
87
|
+
onDebugMessage(`Aborting shell command (PID: ${executionPid ?? 'unknown'})`);
|
88
|
+
};
|
89
|
+
abortSignal.addEventListener('abort', abortHandler, { once: true });
|
212
90
|
onDebugMessage(`Executing in ${targetDir}: ${commandToExecute}`);
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
91
|
+
try {
|
92
|
+
const { pid, result } = ShellExecutionService.execute(commandToExecute, targetDir, (event) => {
|
93
|
+
switch (event.type) {
|
94
|
+
case 'data':
|
95
|
+
// Do not process text data if we've already switched to binary mode.
|
96
|
+
if (isBinaryStream)
|
97
|
+
break;
|
98
|
+
if (event.stream === 'stdout') {
|
99
|
+
cumulativeStdout += event.chunk;
|
100
|
+
}
|
101
|
+
else {
|
102
|
+
cumulativeStderr += event.chunk;
|
103
|
+
}
|
104
|
+
break;
|
105
|
+
case 'binary_detected':
|
106
|
+
isBinaryStream = true;
|
107
|
+
break;
|
108
|
+
case 'binary_progress':
|
109
|
+
isBinaryStream = true;
|
110
|
+
binaryBytesReceived = event.bytesReceived;
|
111
|
+
break;
|
112
|
+
default: {
|
113
|
+
throw new Error('An unhandled ShellOutputEvent was found.');
|
114
|
+
}
|
115
|
+
}
|
116
|
+
// Compute the display string based on the *current* state.
|
117
|
+
let currentDisplayOutput;
|
118
|
+
if (isBinaryStream) {
|
119
|
+
if (binaryBytesReceived > 0) {
|
120
|
+
currentDisplayOutput = `[Receiving binary output... ${formatMemoryUsage(binaryBytesReceived)} received]`;
|
121
|
+
}
|
122
|
+
else {
|
123
|
+
currentDisplayOutput =
|
124
|
+
'[Binary output detected. Halting stream...]';
|
125
|
+
}
|
126
|
+
}
|
127
|
+
else {
|
128
|
+
currentDisplayOutput =
|
129
|
+
cumulativeStdout +
|
130
|
+
(cumulativeStderr ? `\n${cumulativeStderr}` : '');
|
131
|
+
}
|
132
|
+
// Throttle pending UI updates to avoid excessive re-renders.
|
133
|
+
if (Date.now() - lastUpdateTime > OUTPUT_UPDATE_INTERVAL_MS) {
|
134
|
+
setPendingHistoryItem({
|
135
|
+
type: 'tool_group',
|
136
|
+
tools: [
|
137
|
+
{
|
138
|
+
...initialToolDisplay,
|
139
|
+
resultDisplay: currentDisplayOutput,
|
140
|
+
},
|
141
|
+
],
|
142
|
+
});
|
143
|
+
lastUpdateTime = Date.now();
|
144
|
+
}
|
145
|
+
}, abortSignal);
|
146
|
+
executionPid = pid;
|
147
|
+
result
|
148
|
+
.then((result) => {
|
149
|
+
setPendingHistoryItem(null);
|
150
|
+
let mainContent;
|
151
|
+
if (isBinary(result.rawOutput)) {
|
152
|
+
mainContent =
|
153
|
+
'[Command produced binary output, which is not shown.]';
|
154
|
+
}
|
155
|
+
else {
|
156
|
+
mainContent =
|
157
|
+
result.output.trim() || '(Command produced no output)';
|
158
|
+
}
|
159
|
+
let finalOutput = mainContent;
|
160
|
+
let finalStatus = ToolCallStatus.Success;
|
161
|
+
if (result.error) {
|
162
|
+
finalStatus = ToolCallStatus.Error;
|
163
|
+
finalOutput = `${result.error.message}\n${finalOutput}`;
|
164
|
+
}
|
165
|
+
else if (result.aborted) {
|
166
|
+
finalStatus = ToolCallStatus.Canceled;
|
167
|
+
finalOutput = `Command was cancelled.\n${finalOutput}`;
|
168
|
+
}
|
169
|
+
else if (result.signal) {
|
170
|
+
finalStatus = ToolCallStatus.Error;
|
171
|
+
finalOutput = `Command terminated by signal: ${result.signal}.\n${finalOutput}`;
|
172
|
+
}
|
173
|
+
else if (result.exitCode !== 0) {
|
174
|
+
finalStatus = ToolCallStatus.Error;
|
175
|
+
finalOutput = `Command exited with code ${result.exitCode}.\n${finalOutput}`;
|
176
|
+
}
|
177
|
+
if (pwdFilePath && fs.existsSync(pwdFilePath)) {
|
178
|
+
const finalPwd = fs.readFileSync(pwdFilePath, 'utf8').trim();
|
179
|
+
if (finalPwd && finalPwd !== targetDir) {
|
180
|
+
const warning = `WARNING: shell mode is stateless; the directory change to '${finalPwd}' will not persist.`;
|
181
|
+
finalOutput = `${warning}\n\n${finalOutput}`;
|
182
|
+
}
|
183
|
+
}
|
184
|
+
const finalToolDisplay = {
|
185
|
+
...initialToolDisplay,
|
186
|
+
status: finalStatus,
|
187
|
+
resultDisplay: finalOutput,
|
188
|
+
};
|
189
|
+
// Add the complete, contextual result to the local UI history.
|
190
|
+
addItemToHistory({
|
217
191
|
type: 'tool_group',
|
218
|
-
tools: [
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
}
|
236
|
-
let finalOutput = mainContent;
|
237
|
-
let finalStatus = ToolCallStatus.Success;
|
238
|
-
if (result.error) {
|
239
|
-
finalStatus = ToolCallStatus.Error;
|
240
|
-
finalOutput = `${result.error.message}\n${finalOutput}`;
|
241
|
-
}
|
242
|
-
else if (result.aborted) {
|
243
|
-
finalStatus = ToolCallStatus.Canceled;
|
244
|
-
finalOutput = `Command was cancelled.\n${finalOutput}`;
|
245
|
-
}
|
246
|
-
else if (result.signal) {
|
247
|
-
finalStatus = ToolCallStatus.Error;
|
248
|
-
finalOutput = `Command terminated by signal: ${result.signal}.\n${finalOutput}`;
|
249
|
-
}
|
250
|
-
else if (result.exitCode !== 0) {
|
251
|
-
finalStatus = ToolCallStatus.Error;
|
252
|
-
finalOutput = `Command exited with code ${result.exitCode}.\n${finalOutput}`;
|
253
|
-
}
|
254
|
-
if (pwdFilePath && fs.existsSync(pwdFilePath)) {
|
255
|
-
const finalPwd = fs.readFileSync(pwdFilePath, 'utf8').trim();
|
256
|
-
if (finalPwd && finalPwd !== targetDir) {
|
257
|
-
const warning = `WARNING: shell mode is stateless; the directory change to '${finalPwd}' will not persist.`;
|
258
|
-
finalOutput = `${warning}\n\n${finalOutput}`;
|
192
|
+
tools: [finalToolDisplay],
|
193
|
+
}, userMessageTimestamp);
|
194
|
+
// Add the same complete, contextual result to the LLM's history.
|
195
|
+
addShellCommandToGeminiHistory(geminiClient, rawQuery, finalOutput);
|
196
|
+
})
|
197
|
+
.catch((err) => {
|
198
|
+
setPendingHistoryItem(null);
|
199
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
200
|
+
addItemToHistory({
|
201
|
+
type: 'error',
|
202
|
+
text: `An unexpected error occurred: ${errorMessage}`,
|
203
|
+
}, userMessageTimestamp);
|
204
|
+
})
|
205
|
+
.finally(() => {
|
206
|
+
abortSignal.removeEventListener('abort', abortHandler);
|
207
|
+
if (pwdFilePath && fs.existsSync(pwdFilePath)) {
|
208
|
+
fs.unlinkSync(pwdFilePath);
|
259
209
|
}
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
};
|
266
|
-
// Add the complete, contextual result to the local UI history.
|
267
|
-
addItemToHistory({
|
268
|
-
type: 'tool_group',
|
269
|
-
tools: [finalToolDisplay],
|
270
|
-
}, userMessageTimestamp);
|
271
|
-
// Add the same complete, contextual result to the LLM's history.
|
272
|
-
addShellCommandToGeminiHistory(geminiClient, rawQuery, finalOutput);
|
273
|
-
})
|
274
|
-
.catch((err) => {
|
210
|
+
resolve();
|
211
|
+
});
|
212
|
+
}
|
213
|
+
catch (err) {
|
214
|
+
// This block handles synchronous errors from `execute`
|
275
215
|
setPendingHistoryItem(null);
|
276
216
|
const errorMessage = err instanceof Error ? err.message : String(err);
|
277
217
|
addItemToHistory({
|
278
218
|
type: 'error',
|
279
219
|
text: `An unexpected error occurred: ${errorMessage}`,
|
280
220
|
}, userMessageTimestamp);
|
281
|
-
|
282
|
-
.finally(() => {
|
221
|
+
// Perform cleanup here as well
|
283
222
|
if (pwdFilePath && fs.existsSync(pwdFilePath)) {
|
284
223
|
fs.unlinkSync(pwdFilePath);
|
285
224
|
}
|
286
|
-
resolve();
|
287
|
-
}
|
225
|
+
resolve(); // Resolve the promise to unblock `onExec`
|
226
|
+
}
|
288
227
|
});
|
289
228
|
onExec(execPromise);
|
290
|
-
return true;
|
229
|
+
return true;
|
291
230
|
}, [
|
292
231
|
config,
|
293
232
|
onDebugMessage,
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"shellCommandProcessor.js","sourceRoot":"","sources":["../../../../src/ui/hooks/shellCommandProcessor.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,
|
1
|
+
{"version":3,"file":"shellCommandProcessor.js","sourceRoot":"","sources":["../../../../src/ui/hooks/shellCommandProcessor.ts"],"names":[],"mappings":"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"}
|
@@ -5,16 +5,20 @@
|
|
5
5
|
*/
|
6
6
|
import { type PartListUnion } from '@google/genai';
|
7
7
|
import { UseHistoryManagerReturn } from './useHistoryManager.js';
|
8
|
-
import { Config } from '@vybestack/llxprt-code-core';
|
8
|
+
import { Config, ToolConfirmationOutcome } from '@vybestack/llxprt-code-core';
|
9
9
|
import { HistoryItemWithoutId, HistoryItem, SlashCommandProcessorResult } from '../types.js';
|
10
10
|
import { LoadedSettings } from '../../config/settings.js';
|
11
11
|
import { type CommandContext, type SlashCommand } from '../commands/types.js';
|
12
12
|
/**
|
13
13
|
* Hook to define and process slash commands (e.g., /help, /clear).
|
14
14
|
*/
|
15
|
-
export declare const useSlashCommandProcessor: (config: Config | null, settings: LoadedSettings, addItem: UseHistoryManagerReturn["addItem"], clearItems: UseHistoryManagerReturn["clearItems"], loadHistory: UseHistoryManagerReturn["loadHistory"], refreshStatic: () => void, setShowHelp: React.Dispatch<React.SetStateAction<boolean>>, onDebugMessage: (message: string) => void, openThemeDialog: () => void, openAuthDialog: () => void, openEditorDialog: () => void, openProviderDialog: () => void, openProviderModelDialog: () => void,
|
16
|
-
handleSlashCommand: (rawQuery: PartListUnion) => Promise<SlashCommandProcessorResult | false>;
|
15
|
+
export declare const useSlashCommandProcessor: (config: Config | null, settings: LoadedSettings, addItem: UseHistoryManagerReturn["addItem"], clearItems: UseHistoryManagerReturn["clearItems"], loadHistory: UseHistoryManagerReturn["loadHistory"], refreshStatic: () => void, setShowHelp: React.Dispatch<React.SetStateAction<boolean>>, onDebugMessage: (message: string) => void, openThemeDialog: () => void, openAuthDialog: () => void, openEditorDialog: () => void, openProviderDialog: () => void, openProviderModelDialog: () => void, toggleCorgiMode: () => void, setQuittingMessages: (message: HistoryItem[]) => void, openPrivacyNotice: () => void, toggleVimEnabled: () => Promise<boolean>, setIsProcessing: (isProcessing: boolean) => void) => {
|
16
|
+
handleSlashCommand: (rawQuery: PartListUnion, oneTimeShellAllowlist?: Set<string>) => Promise<SlashCommandProcessorResult | false>;
|
17
17
|
slashCommands: readonly SlashCommand[];
|
18
18
|
pendingHistoryItems: HistoryItemWithoutId[];
|
19
19
|
commandContext: CommandContext;
|
20
|
+
shellConfirmationRequest: {
|
21
|
+
commands: string[];
|
22
|
+
onConfirm: (outcome: ToolConfirmationOutcome, approvedCommands?: string[]) => void;
|
23
|
+
} | null;
|
20
24
|
};
|