Files
gemini-cli/packages/cli/src/ui/hooks/useBackgroundShellManager.ts
T
Gaurav Ghosh 651ad63ed6 feat: Introduce an AI-driven interactive shell mode with new
`read-shell` and `write-to-shell` tools and a configurable mode setting.
2026-04-08 07:27:28 -07:00

102 lines
2.9 KiB
TypeScript

/**
* @license
* Copyright 2025 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import { useState, useEffect, useMemo, useRef } from 'react';
import { type BackgroundTask } from './shellReducer.js';
export interface BackgroundShellManagerProps {
backgroundTasks: Map<number, BackgroundTask>;
backgroundTaskCount: number;
isBackgroundTaskVisible: boolean;
activePtyId: number | null | undefined;
embeddedShellFocused: boolean;
setEmbeddedShellFocused: (focused: boolean) => void;
terminalHeight: number;
}
export function useBackgroundShellManager({
backgroundTasks,
backgroundTaskCount,
isBackgroundTaskVisible,
activePtyId,
embeddedShellFocused,
setEmbeddedShellFocused,
terminalHeight,
}: BackgroundShellManagerProps) {
const [isBackgroundShellListOpen, setIsBackgroundShellListOpen] =
useState(false);
const [activeBackgroundShellPid, setActiveBackgroundShellPid] = useState<
number | null
>(null);
const prevShellCountRef = useRef(backgroundTaskCount);
useEffect(() => {
if (backgroundTasks.size === 0) {
if (activeBackgroundShellPid !== null) {
setActiveBackgroundShellPid(null);
}
if (isBackgroundShellListOpen) {
setIsBackgroundShellListOpen(false);
}
} else if (
activeBackgroundShellPid === null ||
!backgroundTasks.has(activeBackgroundShellPid)
) {
// If active shell is closed or none selected, select the first one
setActiveBackgroundShellPid(backgroundTasks.keys().next().value ?? null);
} else if (backgroundTaskCount > prevShellCountRef.current) {
// A new shell was added — auto-switch to the newest one (last in the map)
const pids = Array.from(backgroundTasks.keys());
const newestPid = pids[pids.length - 1];
if (newestPid !== undefined && newestPid !== activeBackgroundShellPid) {
setActiveBackgroundShellPid(newestPid);
}
}
prevShellCountRef.current = backgroundTaskCount;
}, [
backgroundTasks,
activeBackgroundShellPid,
backgroundTaskCount,
isBackgroundShellListOpen,
]);
useEffect(() => {
if (embeddedShellFocused) {
const hasActiveForegroundShell = !!activePtyId;
const hasVisibleBackgroundShell =
isBackgroundTaskVisible && backgroundTasks.size > 0;
if (!hasActiveForegroundShell && !hasVisibleBackgroundShell) {
setEmbeddedShellFocused(false);
}
}
}, [
isBackgroundTaskVisible,
backgroundTasks,
embeddedShellFocused,
backgroundTaskCount,
activePtyId,
setEmbeddedShellFocused,
]);
const backgroundShellHeight = useMemo(
() =>
isBackgroundTaskVisible && backgroundTasks.size > 0
? Math.max(Math.floor(terminalHeight * 0.3), 5)
: 0,
[isBackgroundTaskVisible, backgroundTasks.size, terminalHeight],
);
return {
isBackgroundShellListOpen,
setIsBackgroundShellListOpen,
activeBackgroundShellPid,
setActiveBackgroundShellPid,
backgroundShellHeight,
};
}