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