mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-16 16:21:27 -07:00
feat: Introduce an AI-driven interactive shell mode with new
`read-shell` and `write-to-shell` tools and a configurable mode setting.
This commit is contained in:
@@ -105,6 +105,7 @@ export interface ShellExecutionConfig {
|
||||
backgroundCompletionBehavior?: 'inject' | 'notify' | 'silent';
|
||||
originalCommand?: string;
|
||||
sessionId?: string;
|
||||
autoPromoteTimeoutMs?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -889,6 +890,21 @@ export class ShellExecutionService {
|
||||
sessionId: shellExecutionConfig.sessionId,
|
||||
});
|
||||
|
||||
let autoPromoteTimer: NodeJS.Timeout | undefined;
|
||||
const resetAutoPromoteTimer = () => {
|
||||
if (shellExecutionConfig.autoPromoteTimeoutMs !== undefined) {
|
||||
if (autoPromoteTimer) clearTimeout(autoPromoteTimer);
|
||||
autoPromoteTimer = setTimeout(() => {
|
||||
ShellExecutionService.background(
|
||||
ptyPid,
|
||||
shellExecutionConfig.sessionId,
|
||||
);
|
||||
}, shellExecutionConfig.autoPromoteTimeoutMs);
|
||||
}
|
||||
};
|
||||
|
||||
resetAutoPromoteTimer();
|
||||
|
||||
const result = ExecutionLifecycleService.attachExecution(ptyPid, {
|
||||
executionMethod: ptyInfo?.name ?? 'node-pty',
|
||||
writeInput: (input) => {
|
||||
@@ -1066,6 +1082,7 @@ export class ShellExecutionService {
|
||||
});
|
||||
|
||||
const handleOutput = (data: Buffer) => {
|
||||
resetAutoPromoteTimer();
|
||||
processingChain = processingChain.then(
|
||||
() =>
|
||||
new Promise<void>((resolveChunk) => {
|
||||
@@ -1135,6 +1152,7 @@ export class ShellExecutionService {
|
||||
|
||||
ptyProcess.onExit(
|
||||
({ exitCode, signal }: { exitCode: number; signal?: number }) => {
|
||||
if (autoPromoteTimer) clearTimeout(autoPromoteTimer);
|
||||
exited = true;
|
||||
abortSignal.removeEventListener('abort', abortHandler);
|
||||
// Attempt to destroy the PTY to ensure FD is closed
|
||||
@@ -1220,6 +1238,7 @@ export class ShellExecutionService {
|
||||
);
|
||||
|
||||
const abortHandler = async () => {
|
||||
if (autoPromoteTimer) clearTimeout(autoPromoteTimer);
|
||||
if (ptyProcess.pid && !exited) {
|
||||
await killProcessGroup({
|
||||
pid: ptyPid,
|
||||
@@ -1398,6 +1417,28 @@ export class ShellExecutionService {
|
||||
return ExecutionLifecycleService.subscribe(pid, listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the current rendered screen state of a running process.
|
||||
* Returns the full terminal buffer text for PTY processes,
|
||||
* or the accumulated output for child processes.
|
||||
*
|
||||
* @param pid The process ID of the target process.
|
||||
* @returns The screen text, or null if the process is not found.
|
||||
*/
|
||||
static readScreen(pid: number): string | null {
|
||||
const activePty = this.activePtys.get(pid);
|
||||
if (activePty) {
|
||||
return getFullBufferText(activePty.headlessTerminal);
|
||||
}
|
||||
|
||||
const activeChild = this.activeChildProcesses.get(pid);
|
||||
if (activeChild) {
|
||||
return activeChild.state.output;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resizes the pseudo-terminal (PTY) of a running process.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user