mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-05-19 08:14:35 -07:00
fix(cli): resolve build failures and consolidate type guards
This commit is contained in:
@@ -95,6 +95,8 @@ export const uninstallCommand: CommandModule = {
|
||||
let namesArray: string[] = [];
|
||||
if (Array.isArray(names)) {
|
||||
namesArray = names.filter((n): n is string => typeof n === 'string');
|
||||
} else if (typeof names === 'string') {
|
||||
namesArray = [names];
|
||||
}
|
||||
await handleUninstall({
|
||||
names: namesArray,
|
||||
|
||||
@@ -11,6 +11,7 @@ import { debugLogger, getErrorMessage } from '@google/gemini-cli-core';
|
||||
import { loadSettings, SettingScope } from '../../config/settings.js';
|
||||
import { exitCli } from '../utils.js';
|
||||
import stripJsonComments from 'strip-json-comments';
|
||||
import { isRecord } from '../../utils/typeGuards.js';
|
||||
|
||||
/**
|
||||
* Mapping from Claude Code event names to Gemini event names
|
||||
@@ -58,10 +59,6 @@ function transformMatcher(matcher: string | undefined): string | undefined {
|
||||
return transformed;
|
||||
}
|
||||
|
||||
function isRecord(obj: unknown): obj is Record<string, unknown> {
|
||||
return typeof obj === 'object' && obj !== null && !Array.isArray(obj);
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate a Claude Code hook configuration to Gemini format
|
||||
*/
|
||||
|
||||
@@ -213,7 +213,15 @@ export const addCommand: CommandModule = {
|
||||
// Handle -- separator args as server args if present
|
||||
if (argv['--'] && Array.isArray(argv['--'])) {
|
||||
const args = argv['args'];
|
||||
const existingArgs = Array.isArray(args) ? args : [];
|
||||
let existingArgs: Array<string | number> = [];
|
||||
if (Array.isArray(args)) {
|
||||
existingArgs = args.filter(
|
||||
(a): a is string | number =>
|
||||
typeof a === 'string' || typeof a === 'number',
|
||||
);
|
||||
} else if (typeof args === 'string' || typeof args === 'number') {
|
||||
existingArgs = [args];
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
argv['args'] = [...existingArgs, ...argv['--']];
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
type SlashCommand,
|
||||
type CommandContext,
|
||||
} from './types.js';
|
||||
import { MessageType, type HistoryItem } from '../types.js';
|
||||
import { MessageType, type HistoryItemWithoutId } from '../types.js';
|
||||
import {
|
||||
refreshServerHierarchicalMemory,
|
||||
type Config,
|
||||
@@ -29,10 +29,7 @@ import * as fs from 'node:fs';
|
||||
|
||||
async function finishAddingDirectories(
|
||||
config: Config,
|
||||
addItem: (
|
||||
itemData: Omit<HistoryItem, 'id'>,
|
||||
baseTimestamp?: number,
|
||||
) => number,
|
||||
addItem: (itemData: HistoryItemWithoutId, baseTimestamp?: number) => number,
|
||||
added: string[],
|
||||
errors: string[],
|
||||
) {
|
||||
|
||||
@@ -209,8 +209,8 @@ async function restartAction(
|
||||
|
||||
const s = extensionsToRestart.length > 1 ? 's' : '';
|
||||
|
||||
const reloadingMessage = {
|
||||
type: MessageType.INFO,
|
||||
const reloadingMessage: HistoryItemInfo = {
|
||||
type: 'info',
|
||||
text: `Reloading ${extensionsToRestart.length} extension${s}...`,
|
||||
color: theme.text.primary,
|
||||
};
|
||||
@@ -472,8 +472,7 @@ async function installAction(
|
||||
args: string,
|
||||
requestConsentOverride?: (consent: string) => Promise<boolean>,
|
||||
) {
|
||||
const extensionLoader =
|
||||
context.services.agentContext?.config.getExtensionLoader();
|
||||
const extensionLoader = context.services.config?.getExtensionLoader();
|
||||
if (!(extensionLoader instanceof ExtensionManager)) {
|
||||
debugLogger.error(
|
||||
`Cannot ${context.invocation?.name} extensions in this environment`,
|
||||
|
||||
@@ -16,7 +16,7 @@ import { useKeypress } from '../hooks/useKeypress.js';
|
||||
import { loadTrustedFolders, TrustLevel } from '../../config/trustedFolders.js';
|
||||
import { expandHomeDir } from '../utils/directoryUtils.js';
|
||||
import * as path from 'node:path';
|
||||
import { MessageType, type HistoryItem } from '../types.js';
|
||||
import { MessageType, type HistoryItemWithoutId } from '../types.js';
|
||||
import { type Config } from '@google/gemini-cli-core';
|
||||
|
||||
export enum MultiFolderTrustChoice {
|
||||
@@ -32,18 +32,12 @@ export interface MultiFolderTrustDialogProps {
|
||||
errors: string[];
|
||||
finishAddingDirectories: (
|
||||
config: Config,
|
||||
addItem: (
|
||||
itemData: Omit<HistoryItem, 'id'>,
|
||||
baseTimestamp?: number,
|
||||
) => number,
|
||||
addItem: (itemData: HistoryItemWithoutId, baseTimestamp?: number) => number,
|
||||
added: string[],
|
||||
errors: string[],
|
||||
) => Promise<void>;
|
||||
config: Config;
|
||||
addItem: (
|
||||
itemData: Omit<HistoryItem, 'id'>,
|
||||
baseTimestamp?: number,
|
||||
) => number;
|
||||
addItem: (itemData: HistoryItemWithoutId, baseTimestamp?: number) => number;
|
||||
}
|
||||
|
||||
export const MultiFolderTrustDialog: React.FC<MultiFolderTrustDialogProps> = ({
|
||||
|
||||
@@ -63,10 +63,7 @@ import {
|
||||
LogoutChoice,
|
||||
} from '../components/LogoutConfirmationDialog.js';
|
||||
import { runExitCleanup } from '../../utils/cleanup.js';
|
||||
|
||||
function isRecord(obj: unknown): obj is Record<string, unknown> {
|
||||
return typeof obj === 'object' && obj !== null && !Array.isArray(obj);
|
||||
}
|
||||
import { isRecord } from '../../utils/typeGuards.js';
|
||||
|
||||
interface SlashCommandProcessorActions {
|
||||
openAuthDialog: () => void;
|
||||
|
||||
@@ -8,7 +8,7 @@ import { describe, it, expect } from 'vitest';
|
||||
import { act } from 'react';
|
||||
import { renderHook } from '../../test-utils/render.js';
|
||||
import { useHistory } from './useHistoryManager.js';
|
||||
import type { HistoryItem } from '../types.js';
|
||||
import type { HistoryItem, HistoryItemWithoutId } from '../types.js';
|
||||
|
||||
describe('useHistoryManager', () => {
|
||||
it('should initialize with an empty history', async () => {
|
||||
@@ -19,7 +19,7 @@ describe('useHistoryManager', () => {
|
||||
it('should add an item to history with a unique ID', async () => {
|
||||
const { result } = await renderHook(() => useHistory());
|
||||
const timestamp = Date.now();
|
||||
const itemData: Omit<HistoryItem, 'id'> = {
|
||||
const itemData: HistoryItemWithoutId = {
|
||||
type: 'user', // Replaced HistoryItemType.User
|
||||
text: 'Hello',
|
||||
};
|
||||
@@ -92,11 +92,11 @@ describe('useHistoryManager', () => {
|
||||
it('should generate unique IDs for items added with the same base timestamp', async () => {
|
||||
const { result } = await renderHook(() => useHistory());
|
||||
const timestamp = Date.now();
|
||||
const itemData1: Omit<HistoryItem, 'id'> = {
|
||||
const itemData1: HistoryItemWithoutId = {
|
||||
type: 'user', // Replaced HistoryItemType.User
|
||||
text: 'First',
|
||||
};
|
||||
const itemData2: Omit<HistoryItem, 'id'> = {
|
||||
const itemData2: HistoryItemWithoutId = {
|
||||
type: 'gemini', // Replaced HistoryItemType.Gemini
|
||||
text: 'Second',
|
||||
};
|
||||
@@ -120,7 +120,7 @@ describe('useHistoryManager', () => {
|
||||
it('should update an existing history item', async () => {
|
||||
const { result } = await renderHook(() => useHistory());
|
||||
const timestamp = Date.now();
|
||||
const initialItem: Omit<HistoryItem, 'id'> = {
|
||||
const initialItem: HistoryItemWithoutId = {
|
||||
type: 'gemini', // Replaced HistoryItemType.Gemini
|
||||
text: 'Initial content',
|
||||
};
|
||||
@@ -146,7 +146,7 @@ describe('useHistoryManager', () => {
|
||||
it('should not change history if updateHistoryItem is called with a nonexistent ID', async () => {
|
||||
const { result } = await renderHook(() => useHistory());
|
||||
const timestamp = Date.now();
|
||||
const itemData: Omit<HistoryItem, 'id'> = {
|
||||
const itemData: HistoryItemWithoutId = {
|
||||
type: 'user', // Replaced HistoryItemType.User
|
||||
text: 'Hello',
|
||||
};
|
||||
@@ -167,11 +167,11 @@ describe('useHistoryManager', () => {
|
||||
it('should clear the history', async () => {
|
||||
const { result } = await renderHook(() => useHistory());
|
||||
const timestamp = Date.now();
|
||||
const itemData1: Omit<HistoryItem, 'id'> = {
|
||||
const itemData1: HistoryItemWithoutId = {
|
||||
type: 'user', // Replaced HistoryItemType.User
|
||||
text: 'First',
|
||||
};
|
||||
const itemData2: Omit<HistoryItem, 'id'> = {
|
||||
const itemData2: HistoryItemWithoutId = {
|
||||
type: 'gemini', // Replaced HistoryItemType.Gemini
|
||||
text: 'Second',
|
||||
};
|
||||
@@ -193,19 +193,19 @@ describe('useHistoryManager', () => {
|
||||
it('should not add consecutive duplicate user messages', async () => {
|
||||
const { result } = await renderHook(() => useHistory());
|
||||
const timestamp = Date.now();
|
||||
const itemData1: Omit<HistoryItem, 'id'> = {
|
||||
const itemData1: HistoryItemWithoutId = {
|
||||
type: 'user', // Replaced HistoryItemType.User
|
||||
text: 'Duplicate message',
|
||||
};
|
||||
const itemData2: Omit<HistoryItem, 'id'> = {
|
||||
const itemData2: HistoryItemWithoutId = {
|
||||
type: 'user', // Replaced HistoryItemType.User
|
||||
text: 'Duplicate message',
|
||||
};
|
||||
const itemData3: Omit<HistoryItem, 'id'> = {
|
||||
const itemData3: HistoryItemWithoutId = {
|
||||
type: 'gemini', // Replaced HistoryItemType.Gemini
|
||||
text: 'Gemini response',
|
||||
};
|
||||
const itemData4: Omit<HistoryItem, 'id'> = {
|
||||
const itemData4: HistoryItemWithoutId = {
|
||||
type: 'user', // Replaced HistoryItemType.User
|
||||
text: 'Another user message',
|
||||
};
|
||||
@@ -226,15 +226,15 @@ describe('useHistoryManager', () => {
|
||||
it('should add duplicate user messages if they are not consecutive', async () => {
|
||||
const { result } = await renderHook(() => useHistory());
|
||||
const timestamp = Date.now();
|
||||
const itemData1: Omit<HistoryItem, 'id'> = {
|
||||
const itemData1: HistoryItemWithoutId = {
|
||||
type: 'user', // Replaced HistoryItemType.User
|
||||
text: 'Message 1',
|
||||
};
|
||||
const itemData2: Omit<HistoryItem, 'id'> = {
|
||||
const itemData2: HistoryItemWithoutId = {
|
||||
type: 'gemini', // Replaced HistoryItemType.Gemini
|
||||
text: 'Gemini response',
|
||||
};
|
||||
const itemData3: Omit<HistoryItem, 'id'> = {
|
||||
const itemData3: HistoryItemWithoutId = {
|
||||
type: 'user', // Replaced HistoryItemType.User
|
||||
text: 'Message 1', // Duplicate text, but not consecutive
|
||||
};
|
||||
@@ -254,7 +254,7 @@ describe('useHistoryManager', () => {
|
||||
it('should use Date.now() as default baseTimestamp if not provided', async () => {
|
||||
const { result } = await renderHook(() => useHistory());
|
||||
const before = Date.now();
|
||||
const itemData: Omit<HistoryItem, 'id'> = {
|
||||
const itemData: HistoryItemWithoutId = {
|
||||
type: 'user',
|
||||
text: 'Default timestamp test',
|
||||
};
|
||||
|
||||
@@ -5,24 +5,24 @@
|
||||
*/
|
||||
|
||||
import { useState, useRef, useCallback, useMemo } from 'react';
|
||||
import type { HistoryItem } from '../types.js';
|
||||
import type { HistoryItem, HistoryItemWithoutId } from '../types.js';
|
||||
import type { ChatRecordingService } from '@google/gemini-cli-core/src/services/chatRecordingService.js';
|
||||
|
||||
// Type for the updater function passed to updateHistoryItem
|
||||
type HistoryItemUpdater = (
|
||||
prevItem: HistoryItem,
|
||||
) => Partial<Omit<HistoryItem, 'id'>>;
|
||||
) => Partial<HistoryItemWithoutId>;
|
||||
|
||||
export interface UseHistoryManagerReturn {
|
||||
history: HistoryItem[];
|
||||
addItem: (
|
||||
itemData: Omit<HistoryItem, 'id'>,
|
||||
itemData: HistoryItemWithoutId,
|
||||
baseTimestamp?: number,
|
||||
isResuming?: boolean,
|
||||
) => number; // Returns the generated ID
|
||||
updateItem: (
|
||||
id: number,
|
||||
updates: Partial<Omit<HistoryItem, 'id'>> | HistoryItemUpdater,
|
||||
updates: Partial<HistoryItemWithoutId> | HistoryItemUpdater,
|
||||
) => void;
|
||||
clearItems: () => void;
|
||||
loadHistory: (newHistory: HistoryItem[]) => void;
|
||||
@@ -63,7 +63,7 @@ export function useHistory({
|
||||
// Adds a new item to the history state with a unique ID.
|
||||
const addItem = useCallback(
|
||||
(
|
||||
itemData: Omit<HistoryItem, 'id'>,
|
||||
itemData: HistoryItemWithoutId,
|
||||
baseTimestamp: number = Date.now(),
|
||||
isResuming: boolean = false,
|
||||
): number => {
|
||||
@@ -138,7 +138,7 @@ export function useHistory({
|
||||
const updateItem = useCallback(
|
||||
(
|
||||
id: number,
|
||||
updates: Partial<Omit<HistoryItem, 'id'>> | HistoryItemUpdater,
|
||||
updates: Partial<HistoryItemWithoutId> | HistoryItemUpdater,
|
||||
) => {
|
||||
setHistory((prevHistory) =>
|
||||
prevHistory.map((item) => {
|
||||
|
||||
@@ -14,14 +14,11 @@ import {
|
||||
} from '@google/gemini-cli-core';
|
||||
import { MultiFolderTrustDialog } from '../components/MultiFolderTrustDialog.js';
|
||||
import type { UseHistoryManagerReturn } from './useHistoryManager.js';
|
||||
import { MessageType, type HistoryItem } from '../types.js';
|
||||
import { MessageType, type HistoryItemWithoutId } from '../types.js';
|
||||
|
||||
async function finishAddingDirectories(
|
||||
config: Config,
|
||||
addItem: (
|
||||
itemData: Omit<HistoryItem, 'id'>,
|
||||
baseTimestamp?: number,
|
||||
) => number,
|
||||
addItem: (itemData: HistoryItemWithoutId, baseTimestamp?: number) => number,
|
||||
added: string[],
|
||||
errors: string[],
|
||||
) {
|
||||
|
||||
@@ -8,7 +8,7 @@ import type { UpdateObject } from '../ui/utils/updateCheck.js';
|
||||
import type { LoadedSettings } from '../config/settings.js';
|
||||
import { getInstallationInfo, PackageManager } from './installationInfo.js';
|
||||
import { updateEventEmitter } from './updateEventEmitter.js';
|
||||
import { MessageType, type HistoryItem } from '../ui/types.js';
|
||||
import { MessageType, type HistoryItemWithoutId } from '../ui/types.js';
|
||||
import { spawnWrapper } from './spawnWrapper.js';
|
||||
import type { spawn } from 'node:child_process';
|
||||
import { debugLogger } from '@google/gemini-cli-core';
|
||||
@@ -115,7 +115,6 @@ export function handleAutoUpdate(
|
||||
}
|
||||
updateEventEmitter.emit('update-received', {
|
||||
...info,
|
||||
message: combinedMessage,
|
||||
isUpdating: true,
|
||||
});
|
||||
if (_updateInProgress) {
|
||||
@@ -163,7 +162,7 @@ export function handleAutoUpdate(
|
||||
}
|
||||
|
||||
export function setUpdateHandler(
|
||||
addItem: (item: Omit<HistoryItem, 'id'>, timestamp: number) => void,
|
||||
addItem: (item: HistoryItemWithoutId, timestamp: number) => void,
|
||||
setUpdateInfo: (info: UpdateObject | null) => void,
|
||||
) {
|
||||
let successfullyInstalled = false;
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2025 Google LLC
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Type guard to check if a value is a non-null object and not an array.
|
||||
*/
|
||||
export function isRecord(obj: unknown): obj is Record<string, unknown> {
|
||||
return typeof obj === 'object' && obj !== null && !Array.isArray(obj);
|
||||
}
|
||||
Reference in New Issue
Block a user