feat(hooks): Hook Session Lifecycle & Compression Integration (#14151)

This commit is contained in:
Edilmo Palencia
2025-12-03 09:04:13 -08:00
committed by GitHub
parent 7a6d3067c6
commit 1c12da1fad
27 changed files with 1026 additions and 302 deletions

View File

@@ -59,6 +59,10 @@ import {
disableLineWrapping,
shouldEnterAlternateScreen,
startupProfiler,
SessionStartSource,
SessionEndReason,
fireSessionStartHook,
fireSessionEndHook,
} from '@google/gemini-cli-core';
import { validateAuthMethod } from '../config/auth.js';
import process from 'node:process';
@@ -284,14 +288,32 @@ export const AppContainer = (props: AppContainerProps) => {
await config.initialize();
setConfigInitialized(true);
startupProfiler.flush(config);
// Fire SessionStart hook through MessageBus (only if hooks are enabled)
// Must be called AFTER config.initialize() to ensure HookRegistry is loaded
const hooksEnabled = config.getEnableHooks();
const hookMessageBus = config.getMessageBus();
if (hooksEnabled && hookMessageBus) {
const sessionStartSource = resumedSessionData
? SessionStartSource.Resume
: SessionStartSource.Startup;
await fireSessionStartHook(hookMessageBus, sessionStartSource);
}
})();
registerCleanup(async () => {
// Turn off mouse scroll.
disableMouseEvents();
const ideClient = await IdeClient.getInstance();
await ideClient.disconnect();
// Fire SessionEnd hook on cleanup (only if hooks are enabled)
const hooksEnabled = config.getEnableHooks();
const hookMessageBus = config.getMessageBus();
if (hooksEnabled && hookMessageBus) {
await fireSessionEndHook(hookMessageBus, SessionEndReason.Exit);
}
});
}, [config]);
}, [config, resumedSessionData]);
useEffect(
() => setUpdateHandler(historyManager.addItem, setUpdateInfo),

View File

@@ -44,6 +44,8 @@ describe('clearCommand', () => {
}),
}) as unknown as GeminiClient,
setSessionId: vi.fn(),
getEnableHooks: vi.fn().mockReturnValue(false),
getMessageBus: vi.fn().mockReturnValue(undefined),
},
},
});

View File

@@ -4,7 +4,14 @@
* SPDX-License-Identifier: Apache-2.0
*/
import { uiTelemetryService } from '@google/gemini-cli-core';
import {
uiTelemetryService,
fireSessionEndHook,
fireSessionStartHook,
SessionEndReason,
SessionStartSource,
flushTelemetry,
} from '@google/gemini-cli-core';
import type { SlashCommand } from './types.js';
import { CommandKind } from './types.js';
import { randomUUID } from 'node:crypto';
@@ -21,6 +28,12 @@ export const clearCommand: SlashCommand = {
?.getGeminiClient()
?.getChat()
.getChatRecordingService();
const messageBus = config?.getMessageBus();
// Fire SessionEnd hook before clearing
if (config?.getEnableHooks() && messageBus) {
await fireSessionEndHook(messageBus, SessionEndReason.Clear);
}
if (geminiClient) {
context.ui.setDebugMessage('Clearing terminal and resetting chat.');
@@ -38,6 +51,21 @@ export const clearCommand: SlashCommand = {
chatRecordingService.initialize();
}
// Fire SessionStart hook after clearing
if (config?.getEnableHooks() && messageBus) {
await fireSessionStartHook(messageBus, SessionStartSource.Clear);
}
// Give the event loop a chance to process any pending telemetry operations
// This ensures logger.emit() calls have fully propagated to the BatchLogRecordProcessor
await new Promise((resolve) => setImmediate(resolve));
// Flush telemetry to ensure hooks are written to disk immediately
// This is critical for tests and environments with I/O latency
if (config) {
await flushTelemetry(config);
}
uiTelemetryService.setLastPromptTokenCount(0);
context.ui.clear();
},