mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-08 04:10:35 -07:00
Persistent shell support
This commit is contained in:
@@ -783,6 +783,7 @@ export async function loadCliConfig(
|
||||
useAlternateBuffer: settings.ui?.useAlternateBuffer,
|
||||
useRipgrep: settings.tools?.useRipgrep,
|
||||
enableInteractiveShell: settings.tools?.shell?.enableInteractiveShell,
|
||||
enablePersistentShell: settings.tools?.shell?.enablePersistentShell,
|
||||
shellToolInactivityTimeout: settings.tools?.shell?.inactivityTimeout,
|
||||
enableShellOutputEfficiency:
|
||||
settings.tools?.shell?.enableShellOutputEfficiency ?? true,
|
||||
|
||||
@@ -1282,6 +1282,17 @@ const SETTINGS_SCHEMA = {
|
||||
`,
|
||||
showInDialog: true,
|
||||
},
|
||||
enablePersistentShell: {
|
||||
type: 'boolean',
|
||||
label: 'Enable Persistent Shell',
|
||||
category: 'Tools',
|
||||
requiresRestart: true,
|
||||
default: true,
|
||||
description: oneLine`
|
||||
Maintain a persistent shell session across commands to preserve environment variables, directory changes, and aliases.
|
||||
`,
|
||||
showInDialog: true,
|
||||
},
|
||||
pager: {
|
||||
type: 'string',
|
||||
label: 'Pager',
|
||||
|
||||
@@ -77,6 +77,7 @@ describe('ShellProcessor', () => {
|
||||
getTargetDir: vi.fn().mockReturnValue('/test/dir'),
|
||||
getApprovalMode: vi.fn().mockReturnValue(ApprovalMode.DEFAULT),
|
||||
getEnableInteractiveShell: vi.fn().mockReturnValue(false),
|
||||
getEnablePersistentShell: vi.fn().mockReturnValue(false),
|
||||
getShellExecutionConfig: vi.fn().mockReturnValue({}),
|
||||
getPolicyEngine: vi.fn().mockReturnValue({
|
||||
check: mockPolicyEngineCheck,
|
||||
|
||||
@@ -167,6 +167,7 @@ export class ShellProcessor implements IPromptProcessor {
|
||||
...config.getShellExecutionConfig(),
|
||||
defaultFg: activeTheme.colors.Foreground,
|
||||
defaultBg: activeTheme.colors.Background,
|
||||
persistent: config.getEnablePersistentShell(),
|
||||
};
|
||||
const { result } = await ShellExecutionService.execute(
|
||||
injection.resolvedCommand,
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
SessionEndReason,
|
||||
SessionStartSource,
|
||||
flushTelemetry,
|
||||
ShellExecutionService,
|
||||
} from '@google/gemini-cli-core';
|
||||
import type { SlashCommand } from './types.js';
|
||||
import { CommandKind } from './types.js';
|
||||
@@ -70,6 +71,7 @@ export const clearCommand: SlashCommand = {
|
||||
}
|
||||
|
||||
uiTelemetryService.setLastPromptTokenCount(0);
|
||||
ShellExecutionService.clearPersistentSession();
|
||||
context.ui.clear();
|
||||
|
||||
if (result?.systemMessage) {
|
||||
|
||||
@@ -106,6 +106,7 @@ describe('useShellCommandProcessor', () => {
|
||||
mockConfig = {
|
||||
getTargetDir: () => '/test/dir',
|
||||
getEnableInteractiveShell: () => false,
|
||||
getEnablePersistentShell: () => false,
|
||||
getShellExecutionConfig: () => ({
|
||||
terminalHeight: 20,
|
||||
terminalWidth: 80,
|
||||
|
||||
@@ -283,6 +283,7 @@ export const useShellCommandProcessor = (
|
||||
let commandToExecute = rawQuery;
|
||||
let pwdFilePath: string | undefined;
|
||||
|
||||
const isPersistent = config.getEnablePersistentShell();
|
||||
// On non-windows, wrap the command to capture the final working directory.
|
||||
if (!isWindows) {
|
||||
let command = rawQuery.trim();
|
||||
@@ -292,7 +293,11 @@ export const useShellCommandProcessor = (
|
||||
if (!command.endsWith(';') && !command.endsWith('&')) {
|
||||
command += ';';
|
||||
}
|
||||
commandToExecute = `{ ${command} }; __code=$?; pwd > "${pwdFilePath}"; exit $__code`;
|
||||
if (isPersistent) {
|
||||
commandToExecute = `{ ${command} }; __code=$?; pwd > "${pwdFilePath}"; (exit $__code)`;
|
||||
} else {
|
||||
commandToExecute = `{ ${command} }; __code=$?; pwd > "${pwdFilePath}"; exit $__code`;
|
||||
}
|
||||
}
|
||||
|
||||
const executeCommand = async () => {
|
||||
@@ -324,7 +329,9 @@ export const useShellCommandProcessor = (
|
||||
};
|
||||
abortSignal.addEventListener('abort', abortHandler, { once: true });
|
||||
|
||||
onDebugMessage(`Executing in ${targetDir}: ${commandToExecute}`);
|
||||
onDebugMessage(
|
||||
`Executing in ${targetDir} (persistent=${isPersistent}): ${commandToExecute}`,
|
||||
);
|
||||
|
||||
try {
|
||||
const activeTheme = themeManager.getActiveTheme();
|
||||
@@ -334,6 +341,7 @@ export const useShellCommandProcessor = (
|
||||
terminalHeight,
|
||||
defaultFg: activeTheme.colors.Foreground,
|
||||
defaultBg: activeTheme.colors.Background,
|
||||
persistent: isPersistent,
|
||||
};
|
||||
|
||||
const { pid, result: resultPromise } =
|
||||
|
||||
@@ -1799,7 +1799,6 @@ export const useGeminiStream = (
|
||||
addItem,
|
||||
registerBackgroundShell,
|
||||
consumeUserHint,
|
||||
config,
|
||||
isLowErrorVerbosity,
|
||||
maybeAddSuppressedToolErrorNote,
|
||||
maybeAddLowVerbosityFailureNote,
|
||||
|
||||
Reference in New Issue
Block a user