Refactor: Migrate CLI appEvents to Core coreEvents (#15737)

This commit is contained in:
Adib234
2026-01-23 11:45:46 -05:00
committed by GitHub
parent 0b7d26c9e3
commit 488d5fc439
13 changed files with 90 additions and 93 deletions
+6 -10
View File
@@ -20,8 +20,10 @@ import {
getErrorMessage,
MCPOAuthTokenStorage,
mcpServerRequiresOAuth,
CoreEvent,
coreEvents,
} from '@google/gemini-cli-core';
import { appEvents, AppEvent } from '../../utils/events.js';
import { MessageType, type HistoryItemMcpStatus } from '../types.js';
import {
McpServerEnablementManager,
@@ -100,8 +102,7 @@ const authCommand: SlashCommand = {
context.ui.addItem({ type: 'info', text: message });
};
appEvents.on(AppEvent.OauthDisplayMessage, displayListener);
coreEvents.on(CoreEvent.OauthDisplayMessage, displayListener);
try {
context.ui.addItem({
type: 'info',
@@ -118,12 +119,7 @@ const authCommand: SlashCommand = {
const mcpServerUrl = server.httpUrl || server.url;
const authProvider = new MCPOAuthProvider(new MCPOAuthTokenStorage());
await authProvider.authenticate(
serverName,
oauthConfig,
mcpServerUrl,
appEvents,
);
await authProvider.authenticate(serverName, oauthConfig, mcpServerUrl);
context.ui.addItem({
type: 'info',
@@ -160,7 +156,7 @@ const authCommand: SlashCommand = {
content: `Failed to authenticate with MCP server '${serverName}': ${getErrorMessage(error)}`,
};
} finally {
appEvents.removeListener(AppEvent.OauthDisplayMessage, displayListener);
coreEvents.removeListener(CoreEvent.OauthDisplayMessage, displayListener);
}
},
completion: async (context: CommandContext, partialArg: string) => {
@@ -5,12 +5,25 @@
*/
import { act } from 'react';
import type { EventEmitter } from 'node:events';
import { render } from '../../test-utils/render.js';
import { waitFor } from '../../test-utils/async.js';
import { ConfigInitDisplay } from './ConfigInitDisplay.js';
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { AppEvent } from '../../utils/events.js';
import { MCPServerStatus, type McpClient } from '@google/gemini-cli-core';
import {
describe,
it,
expect,
vi,
beforeEach,
afterEach,
type MockInstance,
} from 'vitest';
import {
CoreEvent,
MCPServerStatus,
type McpClient,
coreEvents,
} from '@google/gemini-cli-core';
import { Text } from 'ink';
// Mock GeminiSpinner
@@ -18,30 +31,11 @@ vi.mock('./GeminiRespondingSpinner.js', () => ({
GeminiSpinner: () => <Text>Spinner</Text>,
}));
// Mock appEvents
const { mockOn, mockOff, mockEmit } = vi.hoisted(() => ({
mockOn: vi.fn(),
mockOff: vi.fn(),
mockEmit: vi.fn(),
}));
vi.mock('../../utils/events.js', async (importOriginal) => {
const actual = await importOriginal<typeof import('../../utils/events.js')>();
return {
...actual,
appEvents: {
on: mockOn,
off: mockOff,
emit: mockEmit,
},
};
});
describe('ConfigInitDisplay', () => {
let onSpy: MockInstance<EventEmitter['on']>;
beforeEach(() => {
mockOn.mockClear();
mockOff.mockClear();
mockEmit.mockClear();
onSpy = vi.spyOn(coreEvents as EventEmitter, 'on');
});
afterEach(() => {
@@ -55,10 +49,11 @@ describe('ConfigInitDisplay', () => {
it('updates message on McpClientUpdate event', async () => {
let listener: ((clients?: Map<string, McpClient>) => void) | undefined;
mockOn.mockImplementation((event, fn) => {
if (event === AppEvent.McpClientUpdate) {
listener = fn;
onSpy.mockImplementation((event: unknown, fn: unknown) => {
if (event === CoreEvent.McpClientUpdate) {
listener = fn as (clients?: Map<string, McpClient>) => void;
}
return coreEvents;
});
const { lastFrame } = render(<ConfigInitDisplay />);
@@ -92,10 +87,11 @@ describe('ConfigInitDisplay', () => {
it('truncates list of waiting servers if too many', async () => {
let listener: ((clients?: Map<string, McpClient>) => void) | undefined;
mockOn.mockImplementation((event, fn) => {
if (event === AppEvent.McpClientUpdate) {
listener = fn;
onSpy.mockImplementation((event: unknown, fn: unknown) => {
if (event === CoreEvent.McpClientUpdate) {
listener = fn as (clients?: Map<string, McpClient>) => void;
}
return coreEvents;
});
const { lastFrame } = render(<ConfigInitDisplay />);
@@ -127,10 +123,11 @@ describe('ConfigInitDisplay', () => {
it('handles empty clients map', async () => {
let listener: ((clients?: Map<string, McpClient>) => void) | undefined;
mockOn.mockImplementation((event, fn) => {
if (event === AppEvent.McpClientUpdate) {
listener = fn;
onSpy.mockImplementation((event: unknown, fn: unknown) => {
if (event === CoreEvent.McpClientUpdate) {
listener = fn as (clients?: Map<string, McpClient>) => void;
}
return coreEvents;
});
const { lastFrame } = render(<ConfigInitDisplay />);
@@ -5,9 +5,13 @@
*/
import { useEffect, useState } from 'react';
import { AppEvent, appEvents } from './../../utils/events.js';
import { Box, Text } from 'ink';
import { type McpClient, MCPServerStatus } from '@google/gemini-cli-core';
import {
CoreEvent,
coreEvents,
type McpClient,
MCPServerStatus,
} from '@google/gemini-cli-core';
import { GeminiSpinner } from './GeminiRespondingSpinner.js';
import { theme } from '../semantic-colors.js';
@@ -45,9 +49,9 @@ export const ConfigInitDisplay = () => {
}
};
appEvents.on(AppEvent.McpClientUpdate, onChange);
coreEvents.on(CoreEvent.McpClientUpdate, onChange);
return () => {
appEvents.off(AppEvent.McpClientUpdate, onChange);
coreEvents.off(CoreEvent.McpClientUpdate, onChange);
};
}, []);
@@ -20,8 +20,8 @@ import {
type GeminiClient,
SlashCommandStatus,
makeFakeConfig,
coreEvents,
} from '@google/gemini-cli-core';
import { appEvents } from '../../utils/events.js';
const {
logSlashCommand,
@@ -1044,7 +1044,7 @@ describe('useSlashCommandProcessor', () => {
// We should not see a change until we fire an event.
await waitFor(() => expect(result.current.slashCommands).toEqual([]));
act(() => {
appEvents.emit('extensionsStarting');
coreEvents.emit('extensionsStarting');
});
await waitFor(() =>
expect(result.current.slashCommands).toEqual([newCommand]),
@@ -30,6 +30,7 @@ import {
ToolConfirmationOutcome,
Storage,
IdeClient,
coreEvents,
addMCPStatusChangeListener,
removeMCPStatusChangeListener,
MCPDiscoveryState,
@@ -55,7 +56,6 @@ import {
type ExtensionUpdateAction,
type ExtensionUpdateStatus,
} from '../state/extensions.js';
import { appEvents } from '../../utils/events.js';
import {
LogoutConfirmationDialog,
LogoutChoice,
@@ -295,8 +295,8 @@ export const useSlashCommandProcessor = (
// starting/stopping
reloadCommands();
};
appEvents.on('extensionsStarting', extensionEventListener);
appEvents.on('extensionsStopping', extensionEventListener);
coreEvents.on('extensionsStarting', extensionEventListener);
coreEvents.on('extensionsStopping', extensionEventListener);
return () => {
// eslint-disable-next-line @typescript-eslint/no-floating-promises
@@ -305,8 +305,8 @@ export const useSlashCommandProcessor = (
ideClient.removeStatusChangeListener(listener);
})();
removeMCPStatusChangeListener(listener);
appEvents.off('extensionsStarting', extensionEventListener);
appEvents.off('extensionsStopping', extensionEventListener);
coreEvents.off('extensionsStarting', extensionEventListener);
coreEvents.off('extensionsStopping', extensionEventListener);
};
}, [config, reloadCommands]);