mirror of
https://github.com/google-gemini/gemini-cli.git
synced 2026-08-08 16:11:58 -07:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 65893ee03f |
@@ -1,6 +1,6 @@
|
||||
# Preview release: v0.41.0-preview.0
|
||||
# Preview release: v0.42.0-preview.1
|
||||
|
||||
Released: April 28, 2026
|
||||
Released: May 05, 2026
|
||||
|
||||
Our preview release includes the latest, new, and experimental features. This
|
||||
release may not be as stable as our [latest weekly release](latest.md).
|
||||
@@ -28,6 +28,10 @@ npm install -g @google/gemini-cli@preview
|
||||
|
||||
## What's Changed
|
||||
|
||||
- fix(patch): cherry-pick 3627f47 to release/v0.42.0-preview.0-pr-26542 to patch
|
||||
version v0.42.0-preview.0 and create version 0.42.0-preview.1 by
|
||||
@gemini-cli-robot in
|
||||
[#26544](https://github.com/google-gemini/gemini-cli/pull/26544)
|
||||
- chore(release): bump version to 0.41.0-nightly.20260423.gaa05b4583 by
|
||||
@gemini-cli-robot in
|
||||
[#25847](https://github.com/google-gemini/gemini-cli/pull/25847)
|
||||
@@ -118,4 +122,4 @@ npm install -g @google/gemini-cli@preview
|
||||
[#26078](https://github.com/google-gemini/gemini-cli/pull/26078)
|
||||
|
||||
**Full Changelog**:
|
||||
https://github.com/google-gemini/gemini-cli/compare/v0.40.0-preview.5...v0.41.0-preview.0
|
||||
https://github.com/google-gemini/gemini-cli/compare/v0.40.0-preview.5...v0.42.0-preview.1
|
||||
|
||||
@@ -56,6 +56,7 @@ creating a "discovery file."
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `port` (number, required): The port of the MCP server.
|
||||
- `workspacePath` (string, required): A list of all open workspace root paths,
|
||||
delimited by the OS-specific path separator (`:` for Linux/macOS, `;` for
|
||||
|
||||
@@ -329,9 +329,8 @@ async function expectSeedSessionEligible(
|
||||
fixture: Fixture,
|
||||
sessionId: string,
|
||||
): Promise<void> {
|
||||
const { buildSessionIndex } = await import(
|
||||
'../packages/core/src/services/memoryService.js'
|
||||
);
|
||||
const { buildSessionIndex } =
|
||||
await import('../packages/core/src/services/memoryService.js');
|
||||
const { newSessionIds } = await buildSessionIndex(
|
||||
path.join(fixture.projectTempDir, 'chats'),
|
||||
{ runs: [] },
|
||||
@@ -386,9 +385,8 @@ describe('Auto Memory inbox routing', () => {
|
||||
autoMemoryEval(
|
||||
'every memory patch lands in .inbox/<kind>/ for review and active files stay untouched',
|
||||
async () => {
|
||||
const { startMemoryService } = await import(
|
||||
'../packages/core/src/services/memoryService.js'
|
||||
);
|
||||
const { startMemoryService } =
|
||||
await import('../packages/core/src/services/memoryService.js');
|
||||
const fixture = await createFixture();
|
||||
evalState.sessionFilePath = await seedSession(
|
||||
fixture,
|
||||
|
||||
@@ -141,9 +141,8 @@ async function run() {
|
||||
// --- Heavy Child Process ---
|
||||
// Now we can safely import everything.
|
||||
const { main } = await import('./src/gemini.js');
|
||||
const { FatalError, writeToStderr } = await import(
|
||||
'@google/gemini-cli-core'
|
||||
);
|
||||
const { FatalError, writeToStderr } =
|
||||
await import('@google/gemini-cli-core');
|
||||
const { runExitCleanup } = await import('./src/utils/cleanup.js');
|
||||
|
||||
main().catch(async (error: unknown) => {
|
||||
|
||||
@@ -566,9 +566,8 @@ describe('Session', () => {
|
||||
});
|
||||
|
||||
it('should send sessionUpdate when approval mode changes', async () => {
|
||||
const { coreEvents, CoreEvent, ApprovalMode } = await import(
|
||||
'@google/gemini-cli-core'
|
||||
);
|
||||
const { coreEvents, CoreEvent, ApprovalMode } =
|
||||
await import('@google/gemini-cli-core');
|
||||
|
||||
coreEvents.emit(CoreEvent.ApprovalModeChanged, {
|
||||
sessionId: 'session-1',
|
||||
|
||||
@@ -20,9 +20,8 @@ import { ExtensionManager } from '../../config/extension-manager.js';
|
||||
import { loadSettings, type LoadedSettings } from '../../config/settings.js';
|
||||
|
||||
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
const { mockCoreDebugLogger } = await import(
|
||||
'../../test-utils/mockDebugLogger.js'
|
||||
);
|
||||
const { mockCoreDebugLogger } =
|
||||
await import('../../test-utils/mockDebugLogger.js');
|
||||
const actual =
|
||||
await importOriginal<typeof import('@google/gemini-cli-core')>();
|
||||
const mocked = mockCoreDebugLogger(actual, { stripAnsi: true });
|
||||
|
||||
@@ -11,9 +11,8 @@ import { ExtensionManager } from '../../config/extension-manager.js';
|
||||
import { loadSettings, type LoadedSettings } from '../../config/settings.js';
|
||||
|
||||
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
const { mockCoreDebugLogger } = await import(
|
||||
'../../test-utils/mockDebugLogger.js'
|
||||
);
|
||||
const { mockCoreDebugLogger } =
|
||||
await import('../../test-utils/mockDebugLogger.js');
|
||||
const actual =
|
||||
await importOriginal<typeof import('@google/gemini-cli-core')>();
|
||||
const mocked = mockCoreDebugLogger(actual, { stripAnsi: false });
|
||||
|
||||
@@ -16,9 +16,8 @@ import { getLogFilePath } from './constants.js';
|
||||
import { logsCommand, readLastLines } from './logs.js';
|
||||
|
||||
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
const { mockCoreDebugLogger } = await import(
|
||||
'../../test-utils/mockDebugLogger.js'
|
||||
);
|
||||
const { mockCoreDebugLogger } =
|
||||
await import('../../test-utils/mockDebugLogger.js');
|
||||
return mockCoreDebugLogger(
|
||||
await importOriginal<typeof import('@google/gemini-cli-core')>(),
|
||||
{
|
||||
|
||||
@@ -16,9 +16,8 @@ const mockReadServerProcessInfo = vi.hoisted(() => vi.fn());
|
||||
const mockResolveGemmaConfig = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
const { mockCoreDebugLogger } = await import(
|
||||
'../../test-utils/mockDebugLogger.js'
|
||||
);
|
||||
const { mockCoreDebugLogger } =
|
||||
await import('../../test-utils/mockDebugLogger.js');
|
||||
return mockCoreDebugLogger(
|
||||
await importOriginal<typeof import('@google/gemini-cli-core')>(),
|
||||
{
|
||||
|
||||
@@ -14,9 +14,8 @@ import {
|
||||
} from '../../config/settings.js';
|
||||
|
||||
const { emitConsoleLog, debugLogger } = await vi.hoisted(async () => {
|
||||
const { createMockDebugLogger } = await import(
|
||||
'../../test-utils/mockDebugLogger.js'
|
||||
);
|
||||
const { createMockDebugLogger } =
|
||||
await import('../../test-utils/mockDebugLogger.js');
|
||||
return createMockDebugLogger({ stripAnsi: true });
|
||||
});
|
||||
|
||||
|
||||
@@ -13,9 +13,8 @@ import {
|
||||
} from '../../config/settings.js';
|
||||
|
||||
const { emitConsoleLog, debugLogger } = await vi.hoisted(async () => {
|
||||
const { createMockDebugLogger } = await import(
|
||||
'../../test-utils/mockDebugLogger.js'
|
||||
);
|
||||
const { createMockDebugLogger } =
|
||||
await import('../../test-utils/mockDebugLogger.js');
|
||||
return createMockDebugLogger({ stripAnsi: true });
|
||||
});
|
||||
|
||||
|
||||
@@ -20,9 +20,8 @@ vi.mock('../../config/extensions/consent.js', () => ({
|
||||
}));
|
||||
|
||||
const { debugLogger, emitConsoleLog } = await vi.hoisted(async () => {
|
||||
const { createMockDebugLogger } = await import(
|
||||
'../../test-utils/mockDebugLogger.js'
|
||||
);
|
||||
const { createMockDebugLogger } =
|
||||
await import('../../test-utils/mockDebugLogger.js');
|
||||
return createMockDebugLogger({ stripAnsi: true });
|
||||
});
|
||||
|
||||
|
||||
@@ -16,9 +16,8 @@ vi.mock('../../utils/skillUtils.js', () => ({
|
||||
}));
|
||||
|
||||
const { debugLogger } = await vi.hoisted(async () => {
|
||||
const { createMockDebugLogger } = await import(
|
||||
'../../test-utils/mockDebugLogger.js'
|
||||
);
|
||||
const { createMockDebugLogger } =
|
||||
await import('../../test-utils/mockDebugLogger.js');
|
||||
return createMockDebugLogger({ stripAnsi: false });
|
||||
});
|
||||
|
||||
|
||||
@@ -20,9 +20,8 @@ import { loadCliConfig } from '../../config/config.js';
|
||||
import chalk from 'chalk';
|
||||
|
||||
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
const { mockCoreDebugLogger } = await import(
|
||||
'../../test-utils/mockDebugLogger.js'
|
||||
);
|
||||
const { mockCoreDebugLogger } =
|
||||
await import('../../test-utils/mockDebugLogger.js');
|
||||
return mockCoreDebugLogger(
|
||||
await importOriginal<typeof import('@google/gemini-cli-core')>(),
|
||||
{
|
||||
|
||||
@@ -13,9 +13,8 @@ vi.mock('../../utils/skillUtils.js', () => ({
|
||||
}));
|
||||
|
||||
const { debugLogger, emitConsoleLog } = await vi.hoisted(async () => {
|
||||
const { createMockDebugLogger } = await import(
|
||||
'../../test-utils/mockDebugLogger.js'
|
||||
);
|
||||
const { createMockDebugLogger } =
|
||||
await import('../../test-utils/mockDebugLogger.js');
|
||||
return createMockDebugLogger({ stripAnsi: true });
|
||||
});
|
||||
|
||||
|
||||
@@ -300,9 +300,8 @@ System using model: \${MODEL_NAME}
|
||||
});
|
||||
expect(extension.skills![0].body).toContain('Value is: first');
|
||||
|
||||
const { updateSetting, ExtensionSettingScope } = await import(
|
||||
'./extensions/extensionSettings.js'
|
||||
);
|
||||
const { updateSetting, ExtensionSettingScope } =
|
||||
await import('./extensions/extensionSettings.js');
|
||||
const extensionConfig =
|
||||
await extensionManager.loadExtensionConfig(extensionPath);
|
||||
|
||||
|
||||
@@ -334,8 +334,8 @@ Would you like to attempt to install via "git clone" instead?`,
|
||||
const previousSkills = previous?.skills ?? [];
|
||||
const isMigrating = Boolean(
|
||||
previous &&
|
||||
previous.installMetadata &&
|
||||
previous.installMetadata.source !== installMetadata.source,
|
||||
previous.installMetadata &&
|
||||
previous.installMetadata.source !== installMetadata.source,
|
||||
);
|
||||
|
||||
await maybeRequestConsentOrFail(
|
||||
|
||||
@@ -938,9 +938,8 @@ describe('gemini.tsx main function kitty protocol', () => {
|
||||
});
|
||||
|
||||
it.skip('should log error when cleanupExpiredSessions fails', async () => {
|
||||
const { cleanupExpiredSessions } = await import(
|
||||
'./utils/sessionCleanup.js'
|
||||
);
|
||||
const { cleanupExpiredSessions } =
|
||||
await import('./utils/sessionCleanup.js');
|
||||
vi.mocked(cleanupExpiredSessions).mockRejectedValue(
|
||||
new Error('Cleanup failed'),
|
||||
);
|
||||
|
||||
@@ -552,9 +552,8 @@ export async function main() {
|
||||
adminControlsListner.setConfig(config);
|
||||
|
||||
if (config.isInteractive() && settings.merged.general.devtools) {
|
||||
const { setupInitialActivityLogger } = await import(
|
||||
'./utils/devtoolsService.js'
|
||||
);
|
||||
const { setupInitialActivityLogger } =
|
||||
await import('./utils/devtoolsService.js');
|
||||
setupInitialActivityLogger(config);
|
||||
}
|
||||
|
||||
|
||||
@@ -201,9 +201,8 @@ describe('gemini.tsx main function cleanup', () => {
|
||||
});
|
||||
|
||||
it.skip('should log error when cleanupExpiredSessions fails', async () => {
|
||||
const { loadCliConfig, parseArguments } = await import(
|
||||
'./config/config.js'
|
||||
);
|
||||
const { loadCliConfig, parseArguments } =
|
||||
await import('./config/config.js');
|
||||
const { loadSettings } = await import('./config/settings.js');
|
||||
cleanupMockState.shouldThrow = true;
|
||||
cleanupMockState.called = false;
|
||||
@@ -272,9 +271,8 @@ describe('gemini.tsx main function cleanup', () => {
|
||||
});
|
||||
|
||||
it('should register SessionEnd hook exactly once in non-interactive mode', async () => {
|
||||
const { loadCliConfig, parseArguments } = await import(
|
||||
'./config/config.js'
|
||||
);
|
||||
const { loadCliConfig, parseArguments } =
|
||||
await import('./config/config.js');
|
||||
const { registerCleanup } = await import('./utils/cleanup.js');
|
||||
|
||||
const mockHookSystem = {
|
||||
@@ -310,9 +308,8 @@ describe('gemini.tsx main function cleanup', () => {
|
||||
it('should not register ConsolePatcher cleanup in ACP mode', async () => {
|
||||
const { registerCleanup } = await import('./utils/cleanup.js');
|
||||
const { ConsolePatcher } = await import('./ui/utils/ConsolePatcher.js');
|
||||
const { loadCliConfig, parseArguments } = await import(
|
||||
'./config/config.js'
|
||||
);
|
||||
const { loadCliConfig, parseArguments } =
|
||||
await import('./config/config.js');
|
||||
const { loadSettings } = await import('./config/settings.js');
|
||||
|
||||
vi.mocked(parseArguments).mockResolvedValue({
|
||||
@@ -364,9 +361,8 @@ describe('gemini.tsx main function cleanup', () => {
|
||||
it('should register ConsolePatcher cleanup in non-ACP mode', async () => {
|
||||
const { registerCleanup } = await import('./utils/cleanup.js');
|
||||
const { ConsolePatcher } = await import('./ui/utils/ConsolePatcher.js');
|
||||
const { loadCliConfig, parseArguments } = await import(
|
||||
'./config/config.js'
|
||||
);
|
||||
const { loadCliConfig, parseArguments } =
|
||||
await import('./config/config.js');
|
||||
const { loadSettings } = await import('./config/settings.js');
|
||||
|
||||
vi.mocked(parseArguments).mockResolvedValue({
|
||||
|
||||
@@ -215,9 +215,8 @@ describe('runNonInteractive', () => {
|
||||
computeMergedSettings: vi.fn(),
|
||||
} as unknown as LoadedSettings;
|
||||
|
||||
const { handleAtCommand } = await import(
|
||||
'./ui/hooks/atCommandProcessor.js'
|
||||
);
|
||||
const { handleAtCommand } =
|
||||
await import('./ui/hooks/atCommandProcessor.js');
|
||||
vi.mocked(handleAtCommand).mockImplementation(async ({ query }) => ({
|
||||
processedQuery: [{ text: query }],
|
||||
}));
|
||||
@@ -636,9 +635,8 @@ describe('runNonInteractive', () => {
|
||||
|
||||
it('should preprocess @include commands before sending to the model', async () => {
|
||||
// 1. Mock the imported atCommandProcessor
|
||||
const { handleAtCommand } = await import(
|
||||
'./ui/hooks/atCommandProcessor.js'
|
||||
);
|
||||
const { handleAtCommand } =
|
||||
await import('./ui/hooks/atCommandProcessor.js');
|
||||
const mockHandleAtCommand = vi.mocked(handleAtCommand);
|
||||
|
||||
// 2. Define the raw input and the expected processed output
|
||||
@@ -991,9 +989,8 @@ describe('runNonInteractive', () => {
|
||||
});
|
||||
|
||||
it('should handle slash commands', async () => {
|
||||
const nonInteractiveCliCommands = await import(
|
||||
'./nonInteractiveCliCommands.js'
|
||||
);
|
||||
const nonInteractiveCliCommands =
|
||||
await import('./nonInteractiveCliCommands.js');
|
||||
const handleSlashCommandSpy = vi.spyOn(
|
||||
nonInteractiveCliCommands,
|
||||
'handleSlashCommand',
|
||||
@@ -1271,13 +1268,11 @@ describe('runNonInteractive', () => {
|
||||
|
||||
it('should instantiate CommandService with correct loaders for slash commands', async () => {
|
||||
// This test indirectly checks that handleSlashCommand is using the right loaders.
|
||||
const { FileCommandLoader } = await import(
|
||||
'./services/FileCommandLoader.js'
|
||||
);
|
||||
const { FileCommandLoader } =
|
||||
await import('./services/FileCommandLoader.js');
|
||||
const { McpPromptLoader } = await import('./services/McpPromptLoader.js');
|
||||
const { BuiltinCommandLoader } = await import(
|
||||
'./services/BuiltinCommandLoader.js'
|
||||
);
|
||||
const { BuiltinCommandLoader } =
|
||||
await import('./services/BuiltinCommandLoader.js');
|
||||
mockGetCommands.mockReturnValue([]); // No commands found, so it will fall through
|
||||
const events: ServerGeminiStreamEvent[] = [
|
||||
{ type: GeminiEventType.Content, value: 'Acknowledged' },
|
||||
|
||||
@@ -84,9 +84,8 @@ export async function runNonInteractive(
|
||||
});
|
||||
|
||||
if (process.env['GEMINI_CLI_ACTIVITY_LOG_TARGET']) {
|
||||
const { setupInitialActivityLogger } = await import(
|
||||
'./utils/devtoolsService.js'
|
||||
);
|
||||
const { setupInitialActivityLogger } =
|
||||
await import('./utils/devtoolsService.js');
|
||||
setupInitialActivityLogger(config);
|
||||
}
|
||||
|
||||
|
||||
@@ -221,9 +221,8 @@ describe('runNonInteractive', () => {
|
||||
computeMergedSettings: vi.fn(),
|
||||
} as unknown as LoadedSettings;
|
||||
|
||||
const { handleAtCommand } = await import(
|
||||
'./ui/hooks/atCommandProcessor.js'
|
||||
);
|
||||
const { handleAtCommand } =
|
||||
await import('./ui/hooks/atCommandProcessor.js');
|
||||
vi.mocked(handleAtCommand).mockImplementation(async ({ query }) => ({
|
||||
processedQuery: [{ text: query }],
|
||||
}));
|
||||
@@ -690,9 +689,8 @@ describe('runNonInteractive', () => {
|
||||
|
||||
it('should preprocess @include commands before sending to the model', async () => {
|
||||
// 1. Mock the imported atCommandProcessor
|
||||
const { handleAtCommand } = await import(
|
||||
'./ui/hooks/atCommandProcessor.js'
|
||||
);
|
||||
const { handleAtCommand } =
|
||||
await import('./ui/hooks/atCommandProcessor.js');
|
||||
const mockHandleAtCommand = vi.mocked(handleAtCommand);
|
||||
|
||||
// 2. Define the raw input and the expected processed output
|
||||
@@ -1118,9 +1116,8 @@ describe('runNonInteractive', () => {
|
||||
});
|
||||
|
||||
it('should handle slash commands', async () => {
|
||||
const nonInteractiveCliCommands = await import(
|
||||
'./nonInteractiveCliCommands.js'
|
||||
);
|
||||
const nonInteractiveCliCommands =
|
||||
await import('./nonInteractiveCliCommands.js');
|
||||
const handleSlashCommandSpy = vi.spyOn(
|
||||
nonInteractiveCliCommands,
|
||||
'handleSlashCommand',
|
||||
@@ -1440,13 +1437,11 @@ describe('runNonInteractive', () => {
|
||||
|
||||
it('should instantiate CommandService with correct loaders for slash commands', async () => {
|
||||
// This test indirectly checks that handleSlashCommand is using the right loaders.
|
||||
const { FileCommandLoader } = await import(
|
||||
'./services/FileCommandLoader.js'
|
||||
);
|
||||
const { FileCommandLoader } =
|
||||
await import('./services/FileCommandLoader.js');
|
||||
const { McpPromptLoader } = await import('./services/McpPromptLoader.js');
|
||||
const { BuiltinCommandLoader } = await import(
|
||||
'./services/BuiltinCommandLoader.js'
|
||||
);
|
||||
const { BuiltinCommandLoader } =
|
||||
await import('./services/BuiltinCommandLoader.js');
|
||||
mockGetCommands.mockReturnValue([]); // No commands found, so it will fall through
|
||||
const events: ServerGeminiStreamEvent[] = [
|
||||
{ type: GeminiEventType.Content, value: 'Acknowledged' },
|
||||
|
||||
@@ -84,9 +84,8 @@ export async function runNonInteractive({
|
||||
});
|
||||
|
||||
if (process.env['GEMINI_CLI_ACTIVITY_LOG_TARGET']) {
|
||||
const { setupInitialActivityLogger } = await import(
|
||||
'./utils/devtoolsService.js'
|
||||
);
|
||||
const { setupInitialActivityLogger } =
|
||||
await import('./utils/devtoolsService.js');
|
||||
setupInitialActivityLogger(config);
|
||||
}
|
||||
|
||||
|
||||
@@ -91,9 +91,8 @@ vi.mock('../ui/contexts/StreamingContext.js', async (importOriginal) => {
|
||||
vi.mock('@google/gemini-cli-core', async (importOriginal) => {
|
||||
const original =
|
||||
await importOriginal<typeof import('@google/gemini-cli-core')>();
|
||||
const { MockShellExecutionService: MockService } = await import(
|
||||
'./MockShellExecutionService.js'
|
||||
);
|
||||
const { MockShellExecutionService: MockService } =
|
||||
await import('./MockShellExecutionService.js');
|
||||
// Register the real execution logic so MockShellExecutionService can fall back to it
|
||||
MockService.setOriginalImplementation(original.ShellExecutionService.execute);
|
||||
|
||||
|
||||
@@ -3134,9 +3134,8 @@ describe('AppContainer State Management', () => {
|
||||
|
||||
describe('Submission Handling', () => {
|
||||
it('resets expansion state on submission when not in alternate buffer', async () => {
|
||||
const { checkPermissions } = await import(
|
||||
'./hooks/atCommandProcessor.js'
|
||||
);
|
||||
const { checkPermissions } =
|
||||
await import('./hooks/atCommandProcessor.js');
|
||||
vi.mocked(checkPermissions).mockResolvedValue([]);
|
||||
|
||||
const { unmount } = await act(async () =>
|
||||
@@ -3164,9 +3163,8 @@ describe('AppContainer State Management', () => {
|
||||
});
|
||||
|
||||
it('resets expansion state on submission when in alternate buffer without clearing terminal', async () => {
|
||||
const { checkPermissions } = await import(
|
||||
'./hooks/atCommandProcessor.js'
|
||||
);
|
||||
const { checkPermissions } =
|
||||
await import('./hooks/atCommandProcessor.js');
|
||||
vi.mocked(checkPermissions).mockResolvedValue([]);
|
||||
|
||||
vi.spyOn(mockConfig, 'getUseTerminalBuffer').mockReturnValue(false);
|
||||
@@ -3448,9 +3446,8 @@ describe('AppContainer State Management', () => {
|
||||
|
||||
describe('Permission Handling', () => {
|
||||
it('shows permission dialog when checkPermissions returns paths', async () => {
|
||||
const { checkPermissions } = await import(
|
||||
'./hooks/atCommandProcessor.js'
|
||||
);
|
||||
const { checkPermissions } =
|
||||
await import('./hooks/atCommandProcessor.js');
|
||||
vi.mocked(checkPermissions).mockResolvedValue(['/test/file.txt']);
|
||||
|
||||
const { unmount } = await act(async () => renderAppContainer());
|
||||
@@ -3471,9 +3468,8 @@ describe('AppContainer State Management', () => {
|
||||
it.each([true, false])(
|
||||
'handles permissions when allowed is %s',
|
||||
async (allowed) => {
|
||||
const { checkPermissions } = await import(
|
||||
'./hooks/atCommandProcessor.js'
|
||||
);
|
||||
const { checkPermissions } =
|
||||
await import('./hooks/atCommandProcessor.js');
|
||||
vi.mocked(checkPermissions).mockResolvedValue(['/test/file.txt']);
|
||||
const addReadOnlyPathSpy = vi.spyOn(
|
||||
mockConfig.getWorkspaceContext(),
|
||||
@@ -3579,9 +3575,8 @@ describe('AppContainer State Management', () => {
|
||||
|
||||
describe('Compression Queuing', () => {
|
||||
beforeEach(async () => {
|
||||
const { checkPermissions } = await import(
|
||||
'./hooks/atCommandProcessor.js'
|
||||
);
|
||||
const { checkPermissions } =
|
||||
await import('./hooks/atCommandProcessor.js');
|
||||
vi.mocked(checkPermissions).mockResolvedValue([]);
|
||||
|
||||
vi.spyOn(mockConfig, 'isModelSteeringEnabled').mockReturnValue(true);
|
||||
|
||||
@@ -1644,9 +1644,9 @@ Logging in with Google... Restarting Gemini CLI to continue.
|
||||
}, []);
|
||||
const shouldShowIdePrompt = Boolean(
|
||||
currentIDE &&
|
||||
!config.getIdeMode() &&
|
||||
!settings.merged.ide.hasSeenNudge &&
|
||||
!idePromptAnswered,
|
||||
!config.getIdeMode() &&
|
||||
!settings.merged.ide.hasSeenNudge &&
|
||||
!idePromptAnswered,
|
||||
);
|
||||
|
||||
const [showErrorDetails, setShowErrorDetails] = useState<boolean>(false);
|
||||
@@ -1927,9 +1927,8 @@ Logging in with Google... Restarting Gemini CLI to continue.
|
||||
if (keyMatchers[Command.SHOW_ERROR_DETAILS](key)) {
|
||||
if (settings.merged.general.devtools) {
|
||||
void (async () => {
|
||||
const { toggleDevToolsPanel } = await import(
|
||||
'../utils/devtoolsService.js'
|
||||
);
|
||||
const { toggleDevToolsPanel } =
|
||||
await import('../utils/devtoolsService.js');
|
||||
await toggleDevToolsPanel(
|
||||
config,
|
||||
showErrorDetails,
|
||||
|
||||
@@ -78,9 +78,8 @@ describe('authCommand', () => {
|
||||
const logoutCommand = authCommand.subCommands?.[1];
|
||||
expect(logoutCommand?.name).toBe('signout');
|
||||
|
||||
const { clearCachedCredentialFile } = await import(
|
||||
'@google/gemini-cli-core'
|
||||
);
|
||||
const { clearCachedCredentialFile } =
|
||||
await import('@google/gemini-cli-core');
|
||||
|
||||
await logoutCommand!.action!(mockContext, '');
|
||||
|
||||
|
||||
@@ -1139,9 +1139,8 @@ describe('extensionsCommand', () => {
|
||||
const prompts = (await import('prompts')).default;
|
||||
vi.mocked(prompts).mockResolvedValue({ overwrite: true });
|
||||
|
||||
const { getScopedEnvContents } = await import(
|
||||
'../../config/extensions/extensionSettings.js'
|
||||
);
|
||||
const { getScopedEnvContents } =
|
||||
await import('../../config/extensions/extensionSettings.js');
|
||||
vi.mocked(getScopedEnvContents).mockResolvedValue({});
|
||||
});
|
||||
|
||||
|
||||
@@ -635,9 +635,8 @@ describe('MainContent', () => {
|
||||
});
|
||||
|
||||
it('renders a ToolConfirmationQueue without an extra line when preceded by hidden tools', async () => {
|
||||
const { ApprovalMode, WRITE_FILE_DISPLAY_NAME } = await import(
|
||||
'@google/gemini-cli-core'
|
||||
);
|
||||
const { ApprovalMode, WRITE_FILE_DISPLAY_NAME } =
|
||||
await import('@google/gemini-cli-core');
|
||||
const hiddenToolCalls = [
|
||||
{
|
||||
callId: 'tool-hidden',
|
||||
@@ -713,9 +712,8 @@ describe('MainContent', () => {
|
||||
});
|
||||
|
||||
it('renders a spurious line when a tool group has only hidden tools and borderBottom true', async () => {
|
||||
const { ApprovalMode, WRITE_FILE_DISPLAY_NAME } = await import(
|
||||
'@google/gemini-cli-core'
|
||||
);
|
||||
const { ApprovalMode, WRITE_FILE_DISPLAY_NAME } =
|
||||
await import('@google/gemini-cli-core');
|
||||
const uiState = {
|
||||
...defaultMockUiState,
|
||||
history: [{ id: 1, type: 'user', text: 'Apply plan' }],
|
||||
|
||||
@@ -11,8 +11,10 @@ import { MaxSizedBox, type MaxSizedBoxProps } from './MaxSizedBox.js';
|
||||
// outputs that will get truncated further MaxSizedBox anyway.
|
||||
const MAXIMUM_RESULT_DISPLAY_CHARACTERS = 20000;
|
||||
|
||||
export interface SlicingMaxSizedBoxProps<T>
|
||||
extends Omit<MaxSizedBoxProps, 'children'> {
|
||||
export interface SlicingMaxSizedBoxProps<T> extends Omit<
|
||||
MaxSizedBoxProps,
|
||||
'children'
|
||||
> {
|
||||
data: T;
|
||||
maxLines?: number;
|
||||
isAlternateBuffer?: boolean;
|
||||
|
||||
@@ -153,15 +153,15 @@ const inScreen = (): boolean =>
|
||||
const isSSH = (): boolean =>
|
||||
Boolean(
|
||||
process.env['SSH_TTY'] ||
|
||||
process.env['SSH_CONNECTION'] ||
|
||||
process.env['SSH_CLIENT'],
|
||||
process.env['SSH_CONNECTION'] ||
|
||||
process.env['SSH_CLIENT'],
|
||||
);
|
||||
|
||||
const isWSL = (): boolean =>
|
||||
Boolean(
|
||||
process.env['WSL_DISTRO_NAME'] ||
|
||||
process.env['WSLENV'] ||
|
||||
process.env['WSL_INTEROP'],
|
||||
process.env['WSLENV'] ||
|
||||
process.env['WSL_INTEROP'],
|
||||
);
|
||||
|
||||
const isWindowsTerminal = (): boolean =>
|
||||
|
||||
@@ -220,9 +220,8 @@ describe('rewindFileOps', () => {
|
||||
});
|
||||
|
||||
it('reverts exact match', async () => {
|
||||
const { getFileDiffFromResultDisplay } = await import(
|
||||
'@google/gemini-cli-core'
|
||||
);
|
||||
const { getFileDiffFromResultDisplay } =
|
||||
await import('@google/gemini-cli-core');
|
||||
vi.mocked(getFileDiffFromResultDisplay).mockReturnValue({
|
||||
filePath: '/abs/path/test.ts',
|
||||
fileName: 'test.ts',
|
||||
@@ -270,9 +269,8 @@ describe('rewindFileOps', () => {
|
||||
});
|
||||
|
||||
it('deletes new file on revert', async () => {
|
||||
const { getFileDiffFromResultDisplay } = await import(
|
||||
'@google/gemini-cli-core'
|
||||
);
|
||||
const { getFileDiffFromResultDisplay } =
|
||||
await import('@google/gemini-cli-core');
|
||||
vi.mocked(getFileDiffFromResultDisplay).mockReturnValue({
|
||||
filePath: '/abs/path/new.ts',
|
||||
fileName: 'new.ts',
|
||||
@@ -317,9 +315,8 @@ describe('rewindFileOps', () => {
|
||||
});
|
||||
|
||||
it('handles smart revert (patching) successfully', async () => {
|
||||
const { getFileDiffFromResultDisplay } = await import(
|
||||
'@google/gemini-cli-core'
|
||||
);
|
||||
const { getFileDiffFromResultDisplay } =
|
||||
await import('@google/gemini-cli-core');
|
||||
vi.mocked(getFileDiffFromResultDisplay).mockReturnValue({
|
||||
filePath: '/abs/path/test.ts',
|
||||
fileName: 'test.ts',
|
||||
@@ -369,9 +366,8 @@ describe('rewindFileOps', () => {
|
||||
});
|
||||
|
||||
it('emits warning on smart revert failure', async () => {
|
||||
const { getFileDiffFromResultDisplay } = await import(
|
||||
'@google/gemini-cli-core'
|
||||
);
|
||||
const { getFileDiffFromResultDisplay } =
|
||||
await import('@google/gemini-cli-core');
|
||||
vi.mocked(getFileDiffFromResultDisplay).mockReturnValue({
|
||||
filePath: '/abs/path/test.ts',
|
||||
fileName: 'test.ts',
|
||||
@@ -421,9 +417,8 @@ describe('rewindFileOps', () => {
|
||||
});
|
||||
|
||||
it('emits error if fs.readFile fails with a generic error', async () => {
|
||||
const { getFileDiffFromResultDisplay } = await import(
|
||||
'@google/gemini-cli-core'
|
||||
);
|
||||
const { getFileDiffFromResultDisplay } =
|
||||
await import('@google/gemini-cli-core');
|
||||
vi.mocked(getFileDiffFromResultDisplay).mockReturnValue({
|
||||
filePath: '/abs/path/test.ts',
|
||||
fileName: 'test.ts',
|
||||
|
||||
@@ -17,8 +17,10 @@ export type AgentActionStatus = 'success' | 'no-op' | 'error';
|
||||
/**
|
||||
* Metadata representing the result of an agent settings operation.
|
||||
*/
|
||||
export interface AgentActionResult
|
||||
extends Omit<FeatureActionResult, 'featureName'> {
|
||||
export interface AgentActionResult extends Omit<
|
||||
FeatureActionResult,
|
||||
'featureName'
|
||||
> {
|
||||
agentName: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -207,9 +207,8 @@ export async function toggleDevToolsPanel(
|
||||
}
|
||||
|
||||
try {
|
||||
const { openBrowserSecurely, shouldLaunchBrowser } = await import(
|
||||
'@google/gemini-cli-core'
|
||||
);
|
||||
const { openBrowserSecurely, shouldLaunchBrowser } =
|
||||
await import('@google/gemini-cli-core');
|
||||
const url = await startDevToolsServer(config);
|
||||
if (shouldLaunchBrowser()) {
|
||||
try {
|
||||
|
||||
@@ -20,8 +20,10 @@ export type SkillActionStatus = 'success' | 'no-op' | 'error';
|
||||
/**
|
||||
* Metadata representing the result of a skill settings operation.
|
||||
*/
|
||||
export interface SkillActionResult
|
||||
extends Omit<FeatureActionResult, 'featureName'> {
|
||||
export interface SkillActionResult extends Omit<
|
||||
FeatureActionResult,
|
||||
'featureName'
|
||||
> {
|
||||
skillName: string;
|
||||
}
|
||||
|
||||
|
||||
@@ -194,9 +194,8 @@ describe('getUserStartupWarnings', () => {
|
||||
|
||||
describe('folder trust check', () => {
|
||||
it('should throw FatalUntrustedWorkspaceError when untrusted in headless mode', async () => {
|
||||
const { isHeadlessMode, FatalUntrustedWorkspaceError } = await import(
|
||||
'@google/gemini-cli-core'
|
||||
);
|
||||
const { isHeadlessMode, FatalUntrustedWorkspaceError } =
|
||||
await import('@google/gemini-cli-core');
|
||||
vi.mocked(isFolderTrustEnabled).mockReturnValue(true);
|
||||
vi.mocked(isWorkspaceTrusted).mockImplementation(() => {
|
||||
throw new FatalUntrustedWorkspaceError(
|
||||
|
||||
@@ -281,7 +281,7 @@ export type ElicitationResponse = {
|
||||
export interface ErrorData {
|
||||
// One of https://github.com/googleapis/googleapis/blob/master/google/rpc/code.proto
|
||||
status: // 400
|
||||
| 'INVALID_ARGUMENT'
|
||||
| 'INVALID_ARGUMENT'
|
||||
| 'FAILED_PRECONDITION'
|
||||
| 'OUT_OF_RANGE'
|
||||
// 401
|
||||
|
||||
@@ -84,9 +84,8 @@ vi.mock('../../utils/debugLogger.js', () => ({
|
||||
}));
|
||||
|
||||
// Re-import mocked modules for assertions.
|
||||
const { MCPOAuthTokenStorage } = await import(
|
||||
'../../mcp/oauth-token-storage.js'
|
||||
);
|
||||
const { MCPOAuthTokenStorage } =
|
||||
await import('../../mcp/oauth-token-storage.js');
|
||||
const {
|
||||
refreshAccessToken,
|
||||
exchangeCodeForToken,
|
||||
|
||||
@@ -379,9 +379,8 @@ describe('browserAgentFactory', () => {
|
||||
|
||||
describe('resetBrowserSession', () => {
|
||||
it('should delegate to BrowserManager.resetAll', async () => {
|
||||
const { BrowserManager: MockBrowserManager } = await import(
|
||||
'./browserManager.js'
|
||||
);
|
||||
const { BrowserManager: MockBrowserManager } =
|
||||
await import('./browserManager.js');
|
||||
await resetBrowserSession();
|
||||
expect(
|
||||
(
|
||||
|
||||
@@ -1627,9 +1627,8 @@ describe('oauth2', () => {
|
||||
});
|
||||
|
||||
it('should save credentials using OAuthCredentialStorage during web login', async () => {
|
||||
const { OAuthCredentialStorage } = await import(
|
||||
'./oauth-credential-storage.js'
|
||||
);
|
||||
const { OAuthCredentialStorage } =
|
||||
await import('./oauth-credential-storage.js');
|
||||
const mockAuthUrl = 'https://example.com/auth';
|
||||
const mockCode = 'test-code';
|
||||
const mockState = 'test-state';
|
||||
@@ -1729,9 +1728,8 @@ describe('oauth2', () => {
|
||||
});
|
||||
|
||||
it('should load credentials using OAuthCredentialStorage and not from file', async () => {
|
||||
const { OAuthCredentialStorage } = await import(
|
||||
'./oauth-credential-storage.js'
|
||||
);
|
||||
const { OAuthCredentialStorage } =
|
||||
await import('./oauth-credential-storage.js');
|
||||
const cachedCreds = { refresh_token: 'cached-encrypted-token' };
|
||||
vi.mocked(OAuthCredentialStorage.loadCredentials).mockResolvedValue(
|
||||
cachedCreds,
|
||||
@@ -1767,9 +1765,8 @@ describe('oauth2', () => {
|
||||
});
|
||||
|
||||
it('should clear credentials using OAuthCredentialStorage', async () => {
|
||||
const { OAuthCredentialStorage } = await import(
|
||||
'./oauth-credential-storage.js'
|
||||
);
|
||||
const { OAuthCredentialStorage } =
|
||||
await import('./oauth-credential-storage.js');
|
||||
|
||||
// Create a dummy unencrypted credential file. It should not be deleted.
|
||||
const credsPath = path.join(tempHomeDir, GEMINI_DIR, 'oauth_creds.json');
|
||||
|
||||
@@ -436,9 +436,8 @@ describe('Server Config (config.ts)', () => {
|
||||
// interactive defaults to false
|
||||
});
|
||||
|
||||
const { McpClientManager } = await import(
|
||||
'../tools/mcp-client-manager.js'
|
||||
);
|
||||
const { McpClientManager } =
|
||||
await import('../tools/mcp-client-manager.js');
|
||||
let mcpStarted = false;
|
||||
|
||||
vi.mocked(McpClientManager).mockImplementation(
|
||||
@@ -466,9 +465,8 @@ describe('Server Config (config.ts)', () => {
|
||||
interactive: true,
|
||||
});
|
||||
|
||||
const { McpClientManager } = await import(
|
||||
'../tools/mcp-client-manager.js'
|
||||
);
|
||||
const { McpClientManager } =
|
||||
await import('../tools/mcp-client-manager.js');
|
||||
let mcpStarted = false;
|
||||
let resolveMcp: (value: unknown) => void;
|
||||
const mcpPromise = new Promise((resolve) => {
|
||||
|
||||
@@ -2453,9 +2453,8 @@ export class Config implements McpContext, AgentLoopContext {
|
||||
if (this.experimentalJitContext && this.memoryContextManager) {
|
||||
await this.memoryContextManager.refresh();
|
||||
} else {
|
||||
const { refreshServerHierarchicalMemory } = await import(
|
||||
'../utils/memoryDiscovery.js'
|
||||
);
|
||||
const { refreshServerHierarchicalMemory } =
|
||||
await import('../utils/memoryDiscovery.js');
|
||||
await refreshServerHierarchicalMemory(this);
|
||||
}
|
||||
if (this._geminiClient?.isInitialized()) {
|
||||
|
||||
@@ -1305,9 +1305,8 @@ ${JSON.stringify(
|
||||
|
||||
it('should stop infinite loop after MAX_TURNS when nextSpeaker always returns model', async () => {
|
||||
// Get the mocked checkNextSpeaker function and configure it to trigger infinite loop
|
||||
const { checkNextSpeaker } = await import(
|
||||
'../utils/nextSpeakerChecker.js'
|
||||
);
|
||||
const { checkNextSpeaker } =
|
||||
await import('../utils/nextSpeakerChecker.js');
|
||||
const mockCheckNextSpeaker = vi.mocked(checkNextSpeaker);
|
||||
mockCheckNextSpeaker.mockResolvedValue({
|
||||
next_speaker: 'model',
|
||||
@@ -1429,9 +1428,8 @@ ${JSON.stringify(
|
||||
// someone tries to bypass it by calling with a very large turns value
|
||||
|
||||
// Get the mocked checkNextSpeaker function and configure it to trigger infinite loop
|
||||
const { checkNextSpeaker } = await import(
|
||||
'../utils/nextSpeakerChecker.js'
|
||||
);
|
||||
const { checkNextSpeaker } =
|
||||
await import('../utils/nextSpeakerChecker.js');
|
||||
const mockCheckNextSpeaker = vi.mocked(checkNextSpeaker);
|
||||
mockCheckNextSpeaker.mockResolvedValue({
|
||||
next_speaker: 'model',
|
||||
@@ -2837,9 +2835,8 @@ ${JSON.stringify(
|
||||
|
||||
it('should not call checkNextSpeaker when turn.run() yields an error', async () => {
|
||||
// Arrange
|
||||
const { checkNextSpeaker } = await import(
|
||||
'../utils/nextSpeakerChecker.js'
|
||||
);
|
||||
const { checkNextSpeaker } =
|
||||
await import('../utils/nextSpeakerChecker.js');
|
||||
const mockCheckNextSpeaker = vi.mocked(checkNextSpeaker);
|
||||
|
||||
const mockStream = (async function* () {
|
||||
@@ -2874,9 +2871,8 @@ ${JSON.stringify(
|
||||
|
||||
it('should not call checkNextSpeaker when turn.run() yields a value then an error', async () => {
|
||||
// Arrange
|
||||
const { checkNextSpeaker } = await import(
|
||||
'../utils/nextSpeakerChecker.js'
|
||||
);
|
||||
const { checkNextSpeaker } =
|
||||
await import('../utils/nextSpeakerChecker.js');
|
||||
const mockCheckNextSpeaker = vi.mocked(checkNextSpeaker);
|
||||
|
||||
const mockStream = (async function* () {
|
||||
@@ -3254,9 +3250,8 @@ ${JSON.stringify(
|
||||
});
|
||||
|
||||
it('should fire BeforeAgent once and AfterAgent once even with recursion', async () => {
|
||||
const { checkNextSpeaker } = await import(
|
||||
'../utils/nextSpeakerChecker.js'
|
||||
);
|
||||
const { checkNextSpeaker } =
|
||||
await import('../utils/nextSpeakerChecker.js');
|
||||
vi.mocked(checkNextSpeaker)
|
||||
.mockResolvedValueOnce({ next_speaker: 'model', reasoning: 'more' })
|
||||
.mockResolvedValueOnce(null);
|
||||
@@ -3295,9 +3290,8 @@ ${JSON.stringify(
|
||||
});
|
||||
|
||||
it('should use original request in AfterAgent hook even when continuation happened', async () => {
|
||||
const { checkNextSpeaker } = await import(
|
||||
'../utils/nextSpeakerChecker.js'
|
||||
);
|
||||
const { checkNextSpeaker } =
|
||||
await import('../utils/nextSpeakerChecker.js');
|
||||
vi.mocked(checkNextSpeaker)
|
||||
.mockResolvedValueOnce({ next_speaker: 'model', reasoning: 'more' })
|
||||
.mockResolvedValueOnce(null);
|
||||
|
||||
@@ -699,9 +699,8 @@ describe('ide-connection-utils', () => {
|
||||
|
||||
describe('createProxyAwareFetch', () => {
|
||||
it('should return a proxy-aware fetcher function', async () => {
|
||||
const { createProxyAwareFetch } = await import(
|
||||
'./ide-connection-utils.js'
|
||||
);
|
||||
const { createProxyAwareFetch } =
|
||||
await import('./ide-connection-utils.js');
|
||||
const fetcher = await createProxyAwareFetch('127.0.0.1');
|
||||
expect(typeof fetcher).toBe('function');
|
||||
});
|
||||
|
||||
@@ -334,9 +334,8 @@ describe('memoryService', () => {
|
||||
});
|
||||
|
||||
it('writes state atomically via temp file + rename', async () => {
|
||||
const { writeExtractionState, readExtractionState } = await import(
|
||||
'./memoryService.js'
|
||||
);
|
||||
const { writeExtractionState, readExtractionState } =
|
||||
await import('./memoryService.js');
|
||||
|
||||
const statePath = path.join(tmpDir, '.extraction-state.json');
|
||||
const state: ExtractionState = {
|
||||
@@ -364,9 +363,8 @@ describe('memoryService', () => {
|
||||
describe('startMemoryService', () => {
|
||||
it('skips when lock is held by another instance', async () => {
|
||||
const { startMemoryService } = await import('./memoryService.js');
|
||||
const { LocalAgentExecutor } = await import(
|
||||
'../agents/local-executor.js'
|
||||
);
|
||||
const { LocalAgentExecutor } =
|
||||
await import('../agents/local-executor.js');
|
||||
|
||||
const memoryDir = path.join(tmpDir, 'memory');
|
||||
const skillsDir = path.join(tmpDir, 'skills');
|
||||
@@ -404,9 +402,8 @@ describe('memoryService', () => {
|
||||
|
||||
it('skips when no unprocessed sessions exist', async () => {
|
||||
const { startMemoryService } = await import('./memoryService.js');
|
||||
const { LocalAgentExecutor } = await import(
|
||||
'../agents/local-executor.js'
|
||||
);
|
||||
const { LocalAgentExecutor } =
|
||||
await import('../agents/local-executor.js');
|
||||
|
||||
const memoryDir = path.join(tmpDir, 'memory2');
|
||||
const skillsDir = path.join(tmpDir, 'skills2');
|
||||
@@ -439,12 +436,10 @@ describe('memoryService', () => {
|
||||
|
||||
it('releases lock on error', async () => {
|
||||
const { startMemoryService } = await import('./memoryService.js');
|
||||
const { LocalAgentExecutor } = await import(
|
||||
'../agents/local-executor.js'
|
||||
);
|
||||
const { ExecutionLifecycleService } = await import(
|
||||
'./executionLifecycleService.js'
|
||||
);
|
||||
const { LocalAgentExecutor } =
|
||||
await import('../agents/local-executor.js');
|
||||
const { ExecutionLifecycleService } =
|
||||
await import('./executionLifecycleService.js');
|
||||
|
||||
const memoryDir = path.join(tmpDir, 'memory3');
|
||||
const skillsDir = path.join(tmpDir, 'skills3');
|
||||
@@ -498,9 +493,8 @@ describe('memoryService', () => {
|
||||
|
||||
it('emits feedback when new skills are created during extraction', async () => {
|
||||
const { startMemoryService } = await import('./memoryService.js');
|
||||
const { LocalAgentExecutor } = await import(
|
||||
'../agents/local-executor.js'
|
||||
);
|
||||
const { LocalAgentExecutor } =
|
||||
await import('../agents/local-executor.js');
|
||||
|
||||
// Reset mocks that may carry state from prior tests
|
||||
vi.mocked(coreEvents.emitFeedback).mockClear();
|
||||
@@ -568,12 +562,10 @@ describe('memoryService', () => {
|
||||
});
|
||||
|
||||
it('records inbox patches as memoryCandidatesCreated without applying them', async () => {
|
||||
const { startMemoryService, readExtractionState } = await import(
|
||||
'./memoryService.js'
|
||||
);
|
||||
const { LocalAgentExecutor } = await import(
|
||||
'../agents/local-executor.js'
|
||||
);
|
||||
const { startMemoryService, readExtractionState } =
|
||||
await import('./memoryService.js');
|
||||
const { LocalAgentExecutor } =
|
||||
await import('../agents/local-executor.js');
|
||||
|
||||
vi.mocked(coreEvents.emitFeedback).mockClear();
|
||||
vi.mocked(LocalAgentExecutor.create).mockReset();
|
||||
@@ -671,12 +663,10 @@ describe('memoryService', () => {
|
||||
});
|
||||
|
||||
it('records only sessions whose read_file completed successfully as processed', async () => {
|
||||
const { startMemoryService, readExtractionState } = await import(
|
||||
'./memoryService.js'
|
||||
);
|
||||
const { LocalAgentExecutor } = await import(
|
||||
'../agents/local-executor.js'
|
||||
);
|
||||
const { startMemoryService, readExtractionState } =
|
||||
await import('./memoryService.js');
|
||||
const { LocalAgentExecutor } =
|
||||
await import('../agents/local-executor.js');
|
||||
|
||||
vi.mocked(LocalAgentExecutor.create).mockReset();
|
||||
|
||||
@@ -1633,9 +1623,8 @@ describe('memoryService', () => {
|
||||
});
|
||||
|
||||
it('writeExtractionState + readExtractionState roundtrips runs correctly', async () => {
|
||||
const { writeExtractionState, readExtractionState } = await import(
|
||||
'./memoryService.js'
|
||||
);
|
||||
const { writeExtractionState, readExtractionState } =
|
||||
await import('./memoryService.js');
|
||||
|
||||
const statePath = path.join(tmpDir, 'roundtrip-state.json');
|
||||
const runs: ExtractionRun[] = [
|
||||
@@ -1981,9 +1970,8 @@ describe('memoryService', () => {
|
||||
describe('startMemoryService feedback for patch-only runs', () => {
|
||||
it('emits feedback when extraction produces only patch suggestions', async () => {
|
||||
const { startMemoryService } = await import('./memoryService.js');
|
||||
const { LocalAgentExecutor } = await import(
|
||||
'../agents/local-executor.js'
|
||||
);
|
||||
const { LocalAgentExecutor } =
|
||||
await import('../agents/local-executor.js');
|
||||
|
||||
vi.mocked(coreEvents.emitFeedback).mockClear();
|
||||
vi.mocked(LocalAgentExecutor.create).mockReset();
|
||||
@@ -2065,9 +2053,8 @@ describe('memoryService', () => {
|
||||
|
||||
it('does not emit feedback for old inbox patches when this run creates none', async () => {
|
||||
const { startMemoryService } = await import('./memoryService.js');
|
||||
const { LocalAgentExecutor } = await import(
|
||||
'../agents/local-executor.js'
|
||||
);
|
||||
const { LocalAgentExecutor } =
|
||||
await import('../agents/local-executor.js');
|
||||
|
||||
vi.mocked(coreEvents.emitFeedback).mockClear();
|
||||
vi.mocked(LocalAgentExecutor.create).mockReset();
|
||||
|
||||
@@ -143,9 +143,8 @@ describe('sessionSummaryUtils', () => {
|
||||
|
||||
mockGenerateSummary = vi.fn().mockResolvedValue('Add dark mode to the app');
|
||||
|
||||
const { SessionSummaryService } = await import(
|
||||
'./sessionSummaryService.js'
|
||||
);
|
||||
const { SessionSummaryService } =
|
||||
await import('./sessionSummaryService.js');
|
||||
(
|
||||
SessionSummaryService as unknown as ReturnType<typeof vi.fn>
|
||||
).mockImplementation(() => ({
|
||||
|
||||
@@ -1885,9 +1885,8 @@ describe('ShellExecutionService environment variables', () => {
|
||||
vi.stubEnv('GEMINI_CLI_TEST_VAR', 'test-value'); // A test var that should be kept
|
||||
|
||||
vi.resetModules();
|
||||
const { ShellExecutionService } = await import(
|
||||
'./shellExecutionService.js'
|
||||
);
|
||||
const { ShellExecutionService } =
|
||||
await import('./shellExecutionService.js');
|
||||
|
||||
// Test pty path
|
||||
await ShellExecutionService.execute(
|
||||
@@ -1945,9 +1944,8 @@ describe('ShellExecutionService environment variables', () => {
|
||||
vi.stubEnv('GEMINI_CLI_TEST_VAR', 'test-value'); // A test var that should be kept
|
||||
|
||||
vi.resetModules();
|
||||
const { ShellExecutionService } = await import(
|
||||
'./shellExecutionService.js'
|
||||
);
|
||||
const { ShellExecutionService } =
|
||||
await import('./shellExecutionService.js');
|
||||
|
||||
// Test pty path
|
||||
await ShellExecutionService.execute(
|
||||
@@ -2002,9 +2000,8 @@ describe('ShellExecutionService environment variables', () => {
|
||||
vi.stubEnv('GITHUB_SHA', '');
|
||||
vi.stubEnv('SURFACE', '');
|
||||
vi.resetModules();
|
||||
const { ShellExecutionService } = await import(
|
||||
'./shellExecutionService.js'
|
||||
);
|
||||
const { ShellExecutionService } =
|
||||
await import('./shellExecutionService.js');
|
||||
|
||||
// Test pty path
|
||||
await ShellExecutionService.execute(
|
||||
@@ -2110,9 +2107,8 @@ describe('ShellExecutionService environment variables', () => {
|
||||
vi.stubEnv('GIT_CONFIG_KEY_1', 'pull.rebase');
|
||||
vi.stubEnv('GIT_CONFIG_VALUE_1', 'true');
|
||||
|
||||
const { ShellExecutionService } = await import(
|
||||
'./shellExecutionService.js'
|
||||
);
|
||||
const { ShellExecutionService } =
|
||||
await import('./shellExecutionService.js');
|
||||
|
||||
mockGetPty.mockResolvedValue(null); // Force child_process fallback
|
||||
await ShellExecutionService.execute(
|
||||
@@ -2162,9 +2158,8 @@ describe('ShellExecutionService environment variables', () => {
|
||||
vi.stubEnv('GCM_INTERACTIVE', undefined);
|
||||
vi.stubEnv('GIT_CONFIG_COUNT', undefined);
|
||||
|
||||
const { ShellExecutionService } = await import(
|
||||
'./shellExecutionService.js'
|
||||
);
|
||||
const { ShellExecutionService } =
|
||||
await import('./shellExecutionService.js');
|
||||
|
||||
mockGetPty.mockResolvedValue(null); // Force child_process fallback
|
||||
await ShellExecutionService.execute(
|
||||
|
||||
@@ -1261,9 +1261,8 @@ function doIt() {
|
||||
|
||||
describe('JIT context discovery', () => {
|
||||
it('should append JIT context to output when enabled and context is found', async () => {
|
||||
const { discoverJitContext, appendJitContext } = await import(
|
||||
'./jit-context.js'
|
||||
);
|
||||
const { discoverJitContext, appendJitContext } =
|
||||
await import('./jit-context.js');
|
||||
vi.mocked(discoverJitContext).mockResolvedValue('Use the useAuth hook.');
|
||||
vi.mocked(appendJitContext).mockImplementation((content, context) => {
|
||||
if (!context) return content;
|
||||
@@ -1292,9 +1291,8 @@ function doIt() {
|
||||
});
|
||||
|
||||
it('should not append JIT context when disabled', async () => {
|
||||
const { discoverJitContext, appendJitContext } = await import(
|
||||
'./jit-context.js'
|
||||
);
|
||||
const { discoverJitContext, appendJitContext } =
|
||||
await import('./jit-context.js');
|
||||
vi.mocked(discoverJitContext).mockResolvedValue('');
|
||||
vi.mocked(appendJitContext).mockImplementation((content, context) => {
|
||||
if (!context) return content;
|
||||
|
||||
@@ -21,8 +21,9 @@ import { debugLogger } from '../utils/debugLogger.js';
|
||||
/**
|
||||
* A declarative tool that supports a modify operation.
|
||||
*/
|
||||
export interface ModifiableDeclarativeTool<TParams extends object>
|
||||
extends DeclarativeTool<TParams, ToolResult> {
|
||||
export interface ModifiableDeclarativeTool<
|
||||
TParams extends object,
|
||||
> extends DeclarativeTool<TParams, ToolResult> {
|
||||
getModifyContext(abortSignal: AbortSignal): ModifyContext<TParams>;
|
||||
}
|
||||
|
||||
|
||||
@@ -157,8 +157,7 @@ export interface PolicyUpdateOptions {
|
||||
export abstract class BaseToolInvocation<
|
||||
TParams extends object,
|
||||
TResult extends ToolResult,
|
||||
> implements ToolInvocation<TParams, TResult>
|
||||
{
|
||||
> implements ToolInvocation<TParams, TResult> {
|
||||
constructor(
|
||||
readonly params: TParams,
|
||||
protected readonly messageBus: MessageBus,
|
||||
@@ -462,8 +461,7 @@ export interface ToolParameterSchema {
|
||||
export abstract class DeclarativeTool<
|
||||
TParams extends object,
|
||||
TResult extends ToolResult,
|
||||
> implements ToolBuilder<TParams, TResult>
|
||||
{
|
||||
> implements ToolBuilder<TParams, TResult> {
|
||||
constructor(
|
||||
readonly name: string,
|
||||
readonly displayName: string,
|
||||
|
||||
@@ -978,7 +978,8 @@ describe('WriteFileTool', () => {
|
||||
const content = 'test content';
|
||||
|
||||
let existsSyncSpy: // eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
ReturnType<typeof vi.spyOn<any, 'existsSync'>> | undefined = undefined;
|
||||
ReturnType<typeof vi.spyOn<any, 'existsSync'>> | undefined =
|
||||
undefined;
|
||||
|
||||
try {
|
||||
if (mockFsExistsSync) {
|
||||
|
||||
@@ -20,8 +20,7 @@ export interface TranscriptionEvents {
|
||||
/**
|
||||
* Common interface for all transcription backends (Cloud or Local).
|
||||
*/
|
||||
export interface TranscriptionProvider
|
||||
extends EventEmitter<TranscriptionEvents> {
|
||||
export interface TranscriptionProvider extends EventEmitter<TranscriptionEvents> {
|
||||
/** Establish connection to the transcription service. */
|
||||
connect(): Promise<void>;
|
||||
/** Send a chunk of raw audio data to the service. */
|
||||
|
||||
@@ -56,11 +56,11 @@ SOFTWARE.
|
||||
|
||||
============================================================
|
||||
ajv@6.14.0
|
||||
(https://github.com/ajv-validator/ajv.git)
|
||||
(No repository found)
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015-2017 Evgeny Poberezkin
|
||||
Copyright (c) 2015-2021 Evgeny Poberezkin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -492,7 +492,7 @@ eventsource-parser@3.0.3
|
||||
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2025 Espen Hovlandsdal <espen@hovlandsdal.com>
|
||||
Copyright (c) 2026 Espen Hovlandsdal <espen@hovlandsdal.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
Reference in New Issue
Block a user