mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-04-16 00:00:52 -07:00
111 lines
3.5 KiB
TypeScript
111 lines
3.5 KiB
TypeScript
/**
|
|
* @license
|
|
* Copyright 2026 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
import { useMemo } from 'react';
|
|
import { useUIState } from '../contexts/UIStateContext.js';
|
|
import { useSettings } from '../contexts/SettingsContext.js';
|
|
import { CoreToolCallStatus, ApprovalMode } from '@google/gemini-cli-core';
|
|
import { type HistoryItemToolGroup, StreamingState } from '../types.js';
|
|
import { INTERACTIVE_SHELL_WAITING_PHRASE } from './usePhraseCycler.js';
|
|
import { isContextUsageHigh } from '../utils/contextUsage.js';
|
|
import { theme } from '../semantic-colors.js';
|
|
|
|
/**
|
|
* A hook that encapsulates complex status and action-required logic for the Composer.
|
|
*/
|
|
export const useComposerStatus = () => {
|
|
const uiState = useUIState();
|
|
const settings = useSettings();
|
|
|
|
const hasPendingToolConfirmation = useMemo(
|
|
() =>
|
|
(uiState.pendingHistoryItems ?? [])
|
|
.filter(
|
|
(item): item is HistoryItemToolGroup => item.type === 'tool_group',
|
|
)
|
|
.some((item) =>
|
|
item.tools.some(
|
|
(tool) => tool.status === CoreToolCallStatus.AwaitingApproval,
|
|
),
|
|
),
|
|
[uiState.pendingHistoryItems],
|
|
);
|
|
|
|
const hasPendingActionRequired =
|
|
hasPendingToolConfirmation ||
|
|
Boolean(uiState.commandConfirmationRequest) ||
|
|
Boolean(uiState.authConsentRequest) ||
|
|
(uiState.confirmUpdateExtensionRequests?.length ?? 0) > 0 ||
|
|
Boolean(uiState.loopDetectionConfirmationRequest) ||
|
|
Boolean(uiState.quota.proQuotaRequest) ||
|
|
Boolean(uiState.quota.validationRequest) ||
|
|
Boolean(uiState.customDialog);
|
|
|
|
const isInteractiveShellWaiting = Boolean(
|
|
uiState.currentLoadingPhrase?.includes(INTERACTIVE_SHELL_WAITING_PHRASE),
|
|
);
|
|
|
|
const showLoadingIndicator =
|
|
(!uiState.embeddedShellFocused || uiState.isBackgroundShellVisible) &&
|
|
uiState.streamingState === StreamingState.Responding &&
|
|
!hasPendingActionRequired;
|
|
|
|
const showApprovalModeIndicator = uiState.showApprovalModeIndicator;
|
|
|
|
const modeContentObj = useMemo(() => {
|
|
const hideMinimalModeHintWhileBusy =
|
|
!uiState.cleanUiDetailsVisible &&
|
|
(showLoadingIndicator || uiState.activeHooks.length > 0);
|
|
|
|
if (hideMinimalModeHintWhileBusy) return null;
|
|
|
|
switch (showApprovalModeIndicator) {
|
|
case ApprovalMode.YOLO:
|
|
return { text: 'YOLO', color: theme.status.error };
|
|
case ApprovalMode.PLAN:
|
|
return { text: 'plan', color: theme.status.success };
|
|
case ApprovalMode.AUTO_EDIT:
|
|
return { text: 'auto edit', color: theme.status.warning };
|
|
case ApprovalMode.DEFAULT:
|
|
default:
|
|
return null;
|
|
}
|
|
}, [
|
|
uiState.cleanUiDetailsVisible,
|
|
showLoadingIndicator,
|
|
uiState.activeHooks.length,
|
|
showApprovalModeIndicator,
|
|
]);
|
|
|
|
const showMinimalContext = isContextUsageHigh(
|
|
uiState.sessionStats.lastPromptTokenCount,
|
|
uiState.currentModel,
|
|
settings.merged.model?.compressionThreshold,
|
|
);
|
|
|
|
const loadingPhrases = settings.merged.ui.loadingPhrases;
|
|
const showTips = loadingPhrases === 'tips' || loadingPhrases === 'all';
|
|
const showWit = loadingPhrases === 'witty' || loadingPhrases === 'all';
|
|
|
|
/**
|
|
* Use the setting if provided, otherwise default to true for the new UX.
|
|
* This allows tests to override the collapse behavior.
|
|
*/
|
|
const shouldCollapseDuringApproval =
|
|
settings.merged.ui.collapseDrawerDuringApproval !== false;
|
|
|
|
return {
|
|
hasPendingActionRequired,
|
|
shouldCollapseDuringApproval,
|
|
isInteractiveShellWaiting,
|
|
showLoadingIndicator,
|
|
showTips,
|
|
showWit,
|
|
modeContentObj,
|
|
showMinimalContext,
|
|
};
|
|
};
|