@google/gemini-cli 0.19.0-nightly.20251124.e177314a4 → 0.19.0-preview.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/package.json +3 -3
- package/dist/src/commands/extensions/examples/mcp-server/package.json +1 -1
- package/dist/src/commands/extensions.test.d.ts +6 -0
- package/dist/src/commands/extensions.test.js +67 -0
- package/dist/src/commands/extensions.test.js.map +1 -0
- package/dist/src/commands/utils.test.d.ts +6 -0
- package/dist/src/commands/utils.test.js +35 -0
- package/dist/src/commands/utils.test.js.map +1 -0
- package/dist/src/config/config.js +1 -3
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +3 -16
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/extensions/github.js +20 -4
- package/dist/src/config/extensions/github.js.map +1 -1
- package/dist/src/config/extensions/github.test.js +6 -2
- package/dist/src/config/extensions/github.test.js.map +1 -1
- package/dist/src/config/settingsSchema.d.ts +9 -0
- package/dist/src/config/settingsSchema.js +9 -0
- package/dist/src/config/settingsSchema.js.map +1 -1
- package/dist/src/config/settingsSchema.test.js +11 -0
- package/dist/src/config/settingsSchema.test.js.map +1 -1
- package/dist/src/core/auth.test.d.ts +6 -0
- package/dist/src/core/auth.test.js +43 -0
- package/dist/src/core/auth.test.js.map +1 -0
- package/dist/src/core/initializer.test.d.ts +6 -0
- package/dist/src/core/initializer.test.js +101 -0
- package/dist/src/core/initializer.test.js.map +1 -0
- package/dist/src/core/theme.test.d.ts +6 -0
- package/dist/src/core/theme.test.js +46 -0
- package/dist/src/core/theme.test.js.map +1 -0
- package/dist/src/gemini.d.ts +1 -0
- package/dist/src/gemini.js +7 -2
- package/dist/src/gemini.js.map +1 -1
- package/dist/src/gemini.test.js +621 -1
- package/dist/src/gemini.test.js.map +1 -1
- package/dist/src/gemini_cleanup.test.d.ts +6 -0
- package/dist/src/gemini_cleanup.test.js +201 -0
- package/dist/src/gemini_cleanup.test.js.map +1 -0
- package/dist/src/generated/git-commit.d.ts +2 -2
- package/dist/src/generated/git-commit.js +2 -2
- package/dist/src/generated/git-commit.js.map +1 -1
- package/dist/src/nonInteractiveCli.test.js +336 -0
- package/dist/src/nonInteractiveCli.test.js.map +1 -1
- package/dist/src/services/BuiltinCommandLoader.js +2 -0
- package/dist/src/services/BuiltinCommandLoader.js.map +1 -1
- package/dist/src/services/BuiltinCommandLoader.test.js +1 -0
- package/dist/src/services/BuiltinCommandLoader.test.js.map +1 -1
- package/dist/src/test-utils/render.js +4 -0
- package/dist/src/test-utils/render.js.map +1 -1
- package/dist/src/ui/App.test.js +28 -14
- package/dist/src/ui/App.test.js.map +1 -1
- package/dist/src/ui/AppContainer.js +21 -2
- package/dist/src/ui/AppContainer.js.map +1 -1
- package/dist/src/ui/IdeIntegrationNudge.test.d.ts +6 -0
- package/dist/src/ui/IdeIntegrationNudge.test.js +147 -0
- package/dist/src/ui/IdeIntegrationNudge.test.js.map +1 -0
- package/dist/src/ui/auth/ApiAuthDialog.test.js +12 -17
- package/dist/src/ui/auth/ApiAuthDialog.test.js.map +1 -1
- package/dist/src/ui/auth/AuthDialog.test.js +120 -74
- package/dist/src/ui/auth/AuthDialog.test.js.map +1 -1
- package/dist/src/ui/auth/AuthInProgress.test.d.ts +6 -0
- package/dist/src/ui/auth/AuthInProgress.test.js +71 -0
- package/dist/src/ui/auth/AuthInProgress.test.js.map +1 -0
- package/dist/src/ui/auth/useAuth.test.d.ts +6 -0
- package/dist/src/ui/auth/useAuth.test.js +178 -0
- package/dist/src/ui/auth/useAuth.test.js.map +1 -0
- package/dist/src/ui/commands/extensionsCommand.js +28 -6
- package/dist/src/ui/commands/extensionsCommand.js.map +1 -1
- package/dist/src/ui/commands/extensionsCommand.test.js +32 -0
- package/dist/src/ui/commands/extensionsCommand.test.js.map +1 -1
- package/dist/src/ui/commands/resumeCommand.d.ts +7 -0
- package/dist/src/ui/commands/resumeCommand.js +16 -0
- package/dist/src/ui/commands/resumeCommand.js.map +1 -0
- package/dist/src/ui/commands/statsCommand.js +27 -16
- package/dist/src/ui/commands/statsCommand.js.map +1 -1
- package/dist/src/ui/commands/types.d.ts +1 -1
- package/dist/src/ui/commands/types.js.map +1 -1
- package/dist/src/ui/components/AlternateBufferQuittingDisplay.test.js +62 -11
- package/dist/src/ui/components/AlternateBufferQuittingDisplay.test.js.map +1 -1
- package/dist/src/ui/components/AnsiOutput.test.js +18 -23
- package/dist/src/ui/components/AnsiOutput.test.js.map +1 -1
- package/dist/src/ui/components/DialogManager.js +4 -0
- package/dist/src/ui/components/DialogManager.js.map +1 -1
- package/dist/src/ui/components/InputPrompt.test.js +6 -0
- package/dist/src/ui/components/InputPrompt.test.js.map +1 -1
- package/dist/src/ui/components/ProQuotaDialog.js +2 -2
- package/dist/src/ui/components/ProQuotaDialog.js.map +1 -1
- package/dist/src/ui/components/SessionBrowser.d.ts +2 -2
- package/dist/src/ui/components/SessionBrowser.js +11 -11
- package/dist/src/ui/components/SessionBrowser.js.map +1 -1
- package/dist/src/ui/components/SessionBrowser.test.js +15 -7
- package/dist/src/ui/components/SessionBrowser.test.js.map +1 -1
- package/dist/src/ui/contexts/UIActionsContext.d.ts +5 -0
- package/dist/src/ui/contexts/UIActionsContext.js.map +1 -1
- package/dist/src/ui/contexts/UIStateContext.d.ts +1 -0
- package/dist/src/ui/contexts/UIStateContext.js.map +1 -1
- package/dist/src/ui/hooks/slashCommandProcessor.d.ts +1 -0
- package/dist/src/ui/hooks/slashCommandProcessor.js +3 -0
- package/dist/src/ui/hooks/slashCommandProcessor.js.map +1 -1
- package/dist/src/ui/hooks/slashCommandProcessor.test.js +1 -0
- package/dist/src/ui/hooks/slashCommandProcessor.test.js.map +1 -1
- package/dist/src/ui/hooks/useQuotaAndFallback.js +9 -3
- package/dist/src/ui/hooks/useQuotaAndFallback.js.map +1 -1
- package/dist/src/ui/hooks/useQuotaAndFallback.test.js +25 -3
- package/dist/src/ui/hooks/useQuotaAndFallback.test.js.map +1 -1
- package/dist/src/ui/hooks/useSessionBrowser.js +5 -1
- package/dist/src/ui/hooks/useSessionBrowser.js.map +1 -1
- package/dist/src/ui/hooks/useSlashCompletion.test.js +4 -4
- package/dist/src/ui/hooks/useSlashCompletion.test.js.map +1 -1
- package/dist/src/ui/hooks/useToolScheduler.test.js +5 -1
- package/dist/src/ui/hooks/useToolScheduler.test.js.map +1 -1
- package/dist/src/ui/state/extensions.test.js +208 -51
- package/dist/src/ui/state/extensions.test.js.map +1 -1
- package/dist/src/ui/utils/kittyProtocolDetector.test.d.ts +6 -0
- package/dist/src/ui/utils/kittyProtocolDetector.test.js +113 -0
- package/dist/src/ui/utils/kittyProtocolDetector.test.js.map +1 -0
- package/dist/src/ui/utils/terminalSetup.js +39 -38
- package/dist/src/ui/utils/terminalSetup.js.map +1 -1
- package/dist/src/ui/utils/terminalSetup.test.d.ts +6 -0
- package/dist/src/ui/utils/terminalSetup.test.js +131 -0
- package/dist/src/ui/utils/terminalSetup.test.js.map +1 -0
- package/dist/src/ui/utils/ui-sizing.test.d.ts +6 -0
- package/dist/src/ui/utils/ui-sizing.test.js +56 -0
- package/dist/src/ui/utils/ui-sizing.test.js.map +1 -0
- package/dist/src/utils/checks.test.d.ts +6 -0
- package/dist/src/utils/checks.test.js +29 -0
- package/dist/src/utils/checks.test.js.map +1 -0
- package/dist/src/utils/cleanup.test.js +69 -16
- package/dist/src/utils/cleanup.test.js.map +1 -1
- package/dist/src/utils/dialogScopeUtils.test.d.ts +6 -0
- package/dist/src/utils/dialogScopeUtils.test.js +81 -0
- package/dist/src/utils/dialogScopeUtils.test.js.map +1 -0
- package/dist/src/utils/errors.test.js +62 -0
- package/dist/src/utils/errors.test.js.map +1 -1
- package/dist/src/utils/events.test.d.ts +6 -0
- package/dist/src/utils/events.test.js +24 -0
- package/dist/src/utils/events.test.js.map +1 -0
- package/dist/src/utils/handleAutoUpdate.test.js +103 -24
- package/dist/src/utils/handleAutoUpdate.test.js.map +1 -1
- package/dist/src/utils/math.test.d.ts +6 -0
- package/dist/src/utils/math.test.js +23 -0
- package/dist/src/utils/math.test.js.map +1 -0
- package/dist/src/utils/persistentState.test.d.ts +6 -0
- package/dist/src/utils/persistentState.test.js +68 -0
- package/dist/src/utils/persistentState.test.js.map +1 -0
- package/dist/src/utils/readStdin.js +1 -0
- package/dist/src/utils/readStdin.js.map +1 -1
- package/dist/src/utils/readStdin.test.js +25 -0
- package/dist/src/utils/readStdin.test.js.map +1 -1
- package/dist/src/utils/resolvePath.test.d.ts +6 -0
- package/dist/src/utils/resolvePath.test.js +31 -0
- package/dist/src/utils/resolvePath.test.js.map +1 -0
- package/dist/src/utils/sandbox.js +6 -137
- package/dist/src/utils/sandbox.js.map +1 -1
- package/dist/src/utils/sandbox.test.d.ts +6 -0
- package/dist/src/utils/sandbox.test.js +302 -0
- package/dist/src/utils/sandbox.test.js.map +1 -0
- package/dist/src/utils/sandboxUtils.d.ts +14 -0
- package/dist/src/utils/sandboxUtils.js +120 -0
- package/dist/src/utils/sandboxUtils.js.map +1 -0
- package/dist/src/utils/sandboxUtils.test.d.ts +6 -0
- package/dist/src/utils/sandboxUtils.test.js +119 -0
- package/dist/src/utils/sandboxUtils.test.js.map +1 -0
- package/dist/src/utils/updateEventEmitter.test.d.ts +6 -0
- package/dist/src/utils/updateEventEmitter.test.js +18 -0
- package/dist/src/utils/updateEventEmitter.test.js.map +1 -0
- package/dist/src/utils/version.test.d.ts +6 -0
- package/dist/src/utils/version.test.js +39 -0
- package/dist/src/utils/version.test.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/dist/google-gemini-cli-0.19.0-nightly.20251123.dadd606c0.tgz +0 -0
package/dist/src/gemini.test.js
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
6
|
import { describe, it, expect, vi, beforeEach, afterEach, } from 'vitest';
|
|
7
|
-
import { main, setupUnhandledRejectionHandler, validateDnsResolutionOrder, startInteractiveUI, } from './gemini.js';
|
|
7
|
+
import { main, setupUnhandledRejectionHandler, validateDnsResolutionOrder, startInteractiveUI, getNodeMemoryArgs, } from './gemini.js';
|
|
8
|
+
import os from 'node:os';
|
|
9
|
+
import v8 from 'node:v8';
|
|
8
10
|
import {} from './config/settings.js';
|
|
9
11
|
import { appEvents, AppEvent } from './utils/events.js';
|
|
10
12
|
import { debugLogger, } from '@google/gemini-cli-core';
|
|
@@ -126,6 +128,7 @@ vi.mock('./utils/sandbox.js', () => ({
|
|
|
126
128
|
}));
|
|
127
129
|
vi.mock('./utils/relaunch.js', () => ({
|
|
128
130
|
relaunchAppInChildProcess: vi.fn(),
|
|
131
|
+
relaunchOnExitCode: vi.fn(),
|
|
129
132
|
}));
|
|
130
133
|
vi.mock('./config/sandboxConfig.js', () => ({
|
|
131
134
|
loadSandboxConfig: vi.fn(),
|
|
@@ -279,6 +282,71 @@ describe('gemini.tsx main function', () => {
|
|
|
279
282
|
processExitSpy.mockRestore();
|
|
280
283
|
});
|
|
281
284
|
});
|
|
285
|
+
describe('setWindowTitle', () => {
|
|
286
|
+
it('should set window title when hideWindowTitle is false', async () => {
|
|
287
|
+
// setWindowTitle is not exported, but we can test its effect if we had a way to call it.
|
|
288
|
+
// Since we can't easily call it directly without exporting it, we skip direct testing
|
|
289
|
+
// and rely on startInteractiveUI tests which call it.
|
|
290
|
+
});
|
|
291
|
+
});
|
|
292
|
+
describe('initializeOutputListenersAndFlush', () => {
|
|
293
|
+
afterEach(() => {
|
|
294
|
+
vi.restoreAllMocks();
|
|
295
|
+
});
|
|
296
|
+
it('should flush backlogs and setup listeners if no listeners exist', async () => {
|
|
297
|
+
const { coreEvents } = await import('@google/gemini-cli-core');
|
|
298
|
+
const { initializeOutputListenersAndFlush } = await import('./gemini.js');
|
|
299
|
+
// Mock listenerCount to return 0
|
|
300
|
+
vi.spyOn(coreEvents, 'listenerCount').mockReturnValue(0);
|
|
301
|
+
const drainSpy = vi.spyOn(coreEvents, 'drainBacklogs');
|
|
302
|
+
initializeOutputListenersAndFlush();
|
|
303
|
+
expect(drainSpy).toHaveBeenCalled();
|
|
304
|
+
// We can't easily check if listeners were added without access to the internal state of coreEvents,
|
|
305
|
+
// but we can verify that drainBacklogs was called.
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
describe('getNodeMemoryArgs', () => {
|
|
309
|
+
let osTotalMemSpy;
|
|
310
|
+
let v8GetHeapStatisticsSpy;
|
|
311
|
+
beforeEach(() => {
|
|
312
|
+
osTotalMemSpy = vi.spyOn(os, 'totalmem');
|
|
313
|
+
v8GetHeapStatisticsSpy = vi.spyOn(v8, 'getHeapStatistics');
|
|
314
|
+
delete process.env['GEMINI_CLI_NO_RELAUNCH'];
|
|
315
|
+
});
|
|
316
|
+
afterEach(() => {
|
|
317
|
+
vi.restoreAllMocks();
|
|
318
|
+
});
|
|
319
|
+
it('should return empty array if GEMINI_CLI_NO_RELAUNCH is set', () => {
|
|
320
|
+
process.env['GEMINI_CLI_NO_RELAUNCH'] = 'true';
|
|
321
|
+
expect(getNodeMemoryArgs(false)).toEqual([]);
|
|
322
|
+
});
|
|
323
|
+
it('should return empty array if current heap limit is sufficient', () => {
|
|
324
|
+
osTotalMemSpy.mockReturnValue(16 * 1024 * 1024 * 1024); // 16GB
|
|
325
|
+
v8GetHeapStatisticsSpy.mockReturnValue({
|
|
326
|
+
heap_size_limit: 8 * 1024 * 1024 * 1024, // 8GB
|
|
327
|
+
});
|
|
328
|
+
// Target is 50% of 16GB = 8GB. Current is 8GB. No relaunch needed.
|
|
329
|
+
expect(getNodeMemoryArgs(false)).toEqual([]);
|
|
330
|
+
});
|
|
331
|
+
it('should return memory args if current heap limit is insufficient', () => {
|
|
332
|
+
osTotalMemSpy.mockReturnValue(16 * 1024 * 1024 * 1024); // 16GB
|
|
333
|
+
v8GetHeapStatisticsSpy.mockReturnValue({
|
|
334
|
+
heap_size_limit: 4 * 1024 * 1024 * 1024, // 4GB
|
|
335
|
+
});
|
|
336
|
+
// Target is 50% of 16GB = 8GB. Current is 4GB. Relaunch needed.
|
|
337
|
+
expect(getNodeMemoryArgs(false)).toEqual(['--max-old-space-size=8192']);
|
|
338
|
+
});
|
|
339
|
+
it('should log debug info when isDebugMode is true', () => {
|
|
340
|
+
const debugSpy = vi.spyOn(debugLogger, 'debug');
|
|
341
|
+
osTotalMemSpy.mockReturnValue(16 * 1024 * 1024 * 1024);
|
|
342
|
+
v8GetHeapStatisticsSpy.mockReturnValue({
|
|
343
|
+
heap_size_limit: 4 * 1024 * 1024 * 1024,
|
|
344
|
+
});
|
|
345
|
+
getNodeMemoryArgs(true);
|
|
346
|
+
expect(debugSpy).toHaveBeenCalledWith(expect.stringContaining('Current heap size'));
|
|
347
|
+
expect(debugSpy).toHaveBeenCalledWith(expect.stringContaining('Need to relaunch with more memory'));
|
|
348
|
+
});
|
|
349
|
+
});
|
|
282
350
|
describe('gemini.tsx main function kitty protocol', () => {
|
|
283
351
|
let originalEnvNoRelaunch;
|
|
284
352
|
let setRawModeSpy;
|
|
@@ -388,6 +456,547 @@ describe('gemini.tsx main function kitty protocol', () => {
|
|
|
388
456
|
expect(setRawModeSpy).toHaveBeenCalledWith(true);
|
|
389
457
|
expect(detectAndEnableKittyProtocol).toHaveBeenCalledTimes(1);
|
|
390
458
|
});
|
|
459
|
+
it.each([
|
|
460
|
+
{ flag: 'listExtensions' },
|
|
461
|
+
{ flag: 'listSessions' },
|
|
462
|
+
{ flag: 'deleteSession', value: 'session-id' },
|
|
463
|
+
])('should handle --$flag flag', async ({ flag, value }) => {
|
|
464
|
+
const { loadCliConfig, parseArguments } = await import('./config/config.js');
|
|
465
|
+
const { loadSettings } = await import('./config/settings.js');
|
|
466
|
+
const { listSessions, deleteSession } = await import('./utils/sessions.js');
|
|
467
|
+
const processExitSpy = vi
|
|
468
|
+
.spyOn(process, 'exit')
|
|
469
|
+
.mockImplementation((code) => {
|
|
470
|
+
throw new MockProcessExitError(code);
|
|
471
|
+
});
|
|
472
|
+
vi.mocked(loadSettings).mockReturnValue({
|
|
473
|
+
merged: {
|
|
474
|
+
advanced: {},
|
|
475
|
+
security: { auth: {} },
|
|
476
|
+
ui: {},
|
|
477
|
+
},
|
|
478
|
+
setValue: vi.fn(),
|
|
479
|
+
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
|
480
|
+
errors: [],
|
|
481
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
482
|
+
vi.mocked(parseArguments).mockResolvedValue({
|
|
483
|
+
promptInteractive: false,
|
|
484
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
485
|
+
const mockConfig = {
|
|
486
|
+
isInteractive: () => false,
|
|
487
|
+
getQuestion: () => '',
|
|
488
|
+
getSandbox: () => false,
|
|
489
|
+
getDebugMode: () => false,
|
|
490
|
+
getListExtensions: () => flag === 'listExtensions',
|
|
491
|
+
getListSessions: () => flag === 'listSessions',
|
|
492
|
+
getDeleteSession: () => (flag === 'deleteSession' ? value : undefined),
|
|
493
|
+
getExtensions: () => [{ name: 'ext1' }],
|
|
494
|
+
getPolicyEngine: vi.fn(),
|
|
495
|
+
getMessageBus: () => ({ subscribe: vi.fn() }),
|
|
496
|
+
initialize: vi.fn(),
|
|
497
|
+
getContentGeneratorConfig: vi.fn(),
|
|
498
|
+
getMcpServers: () => ({}),
|
|
499
|
+
getMcpClientManager: vi.fn(),
|
|
500
|
+
getIdeMode: () => false,
|
|
501
|
+
getExperimentalZedIntegration: () => false,
|
|
502
|
+
getScreenReader: () => false,
|
|
503
|
+
getGeminiMdFileCount: () => 0,
|
|
504
|
+
getProjectRoot: () => '/',
|
|
505
|
+
};
|
|
506
|
+
vi.mocked(loadCliConfig).mockResolvedValue(mockConfig);
|
|
507
|
+
vi.mock('./utils/sessions.js', () => ({
|
|
508
|
+
listSessions: vi.fn(),
|
|
509
|
+
deleteSession: vi.fn(),
|
|
510
|
+
}));
|
|
511
|
+
const debugLoggerLogSpy = vi
|
|
512
|
+
.spyOn(debugLogger, 'log')
|
|
513
|
+
.mockImplementation(() => { });
|
|
514
|
+
try {
|
|
515
|
+
await main();
|
|
516
|
+
}
|
|
517
|
+
catch (e) {
|
|
518
|
+
if (!(e instanceof MockProcessExitError))
|
|
519
|
+
throw e;
|
|
520
|
+
}
|
|
521
|
+
if (flag === 'listExtensions') {
|
|
522
|
+
expect(debugLoggerLogSpy).toHaveBeenCalledWith(expect.stringContaining('ext1'));
|
|
523
|
+
}
|
|
524
|
+
else if (flag === 'listSessions') {
|
|
525
|
+
expect(listSessions).toHaveBeenCalledWith(mockConfig);
|
|
526
|
+
}
|
|
527
|
+
else if (flag === 'deleteSession') {
|
|
528
|
+
expect(deleteSession).toHaveBeenCalledWith(mockConfig, value);
|
|
529
|
+
}
|
|
530
|
+
expect(processExitSpy).toHaveBeenCalledWith(0);
|
|
531
|
+
processExitSpy.mockRestore();
|
|
532
|
+
});
|
|
533
|
+
it('should handle sandbox activation', async () => {
|
|
534
|
+
const { loadCliConfig, parseArguments } = await import('./config/config.js');
|
|
535
|
+
const { loadSandboxConfig } = await import('./config/sandboxConfig.js');
|
|
536
|
+
const { start_sandbox } = await import('./utils/sandbox.js');
|
|
537
|
+
const { relaunchOnExitCode } = await import('./utils/relaunch.js');
|
|
538
|
+
const { loadSettings } = await import('./config/settings.js');
|
|
539
|
+
const processExitSpy = vi
|
|
540
|
+
.spyOn(process, 'exit')
|
|
541
|
+
.mockImplementation((code) => {
|
|
542
|
+
throw new MockProcessExitError(code);
|
|
543
|
+
});
|
|
544
|
+
vi.mocked(parseArguments).mockResolvedValue({
|
|
545
|
+
promptInteractive: false,
|
|
546
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
547
|
+
vi.mocked(loadSettings).mockReturnValue({
|
|
548
|
+
merged: {
|
|
549
|
+
advanced: {},
|
|
550
|
+
security: { auth: {} },
|
|
551
|
+
ui: {},
|
|
552
|
+
},
|
|
553
|
+
setValue: vi.fn(),
|
|
554
|
+
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
|
555
|
+
errors: [],
|
|
556
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
557
|
+
const mockConfig = {
|
|
558
|
+
isInteractive: () => false,
|
|
559
|
+
getQuestion: () => '',
|
|
560
|
+
getSandbox: () => true,
|
|
561
|
+
getDebugMode: () => false,
|
|
562
|
+
getListExtensions: () => false,
|
|
563
|
+
getListSessions: () => false,
|
|
564
|
+
getDeleteSession: () => undefined,
|
|
565
|
+
getExtensions: () => [],
|
|
566
|
+
getPolicyEngine: vi.fn(),
|
|
567
|
+
getMessageBus: () => ({ subscribe: vi.fn() }),
|
|
568
|
+
initialize: vi.fn(),
|
|
569
|
+
getContentGeneratorConfig: vi.fn(),
|
|
570
|
+
getMcpServers: () => ({}),
|
|
571
|
+
getMcpClientManager: vi.fn(),
|
|
572
|
+
getIdeMode: () => false,
|
|
573
|
+
getExperimentalZedIntegration: () => false,
|
|
574
|
+
getScreenReader: () => false,
|
|
575
|
+
getGeminiMdFileCount: () => 0,
|
|
576
|
+
getProjectRoot: () => '/',
|
|
577
|
+
refreshAuth: vi.fn(),
|
|
578
|
+
};
|
|
579
|
+
vi.mocked(loadCliConfig).mockResolvedValue(mockConfig);
|
|
580
|
+
vi.mocked(loadSandboxConfig).mockResolvedValue({}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
581
|
+
vi.mocked(relaunchOnExitCode).mockImplementation(async (fn) => {
|
|
582
|
+
await fn();
|
|
583
|
+
});
|
|
584
|
+
try {
|
|
585
|
+
await main();
|
|
586
|
+
}
|
|
587
|
+
catch (e) {
|
|
588
|
+
if (!(e instanceof MockProcessExitError))
|
|
589
|
+
throw e;
|
|
590
|
+
}
|
|
591
|
+
expect(start_sandbox).toHaveBeenCalled();
|
|
592
|
+
expect(processExitSpy).toHaveBeenCalledWith(0);
|
|
593
|
+
processExitSpy.mockRestore();
|
|
594
|
+
});
|
|
595
|
+
it('should exit with error when --prompt-interactive is used with piped input', async () => {
|
|
596
|
+
const { loadCliConfig, parseArguments } = await import('./config/config.js');
|
|
597
|
+
const { loadSettings } = await import('./config/settings.js');
|
|
598
|
+
const core = await import('@google/gemini-cli-core');
|
|
599
|
+
const processExitSpy = vi
|
|
600
|
+
.spyOn(process, 'exit')
|
|
601
|
+
.mockImplementation((code) => {
|
|
602
|
+
throw new MockProcessExitError(code);
|
|
603
|
+
});
|
|
604
|
+
const writeToStderrSpy = vi
|
|
605
|
+
.spyOn(core, 'writeToStderr')
|
|
606
|
+
.mockImplementation(() => true);
|
|
607
|
+
vi.mocked(loadSettings).mockReturnValue({
|
|
608
|
+
merged: { advanced: {}, security: { auth: {} }, ui: {} },
|
|
609
|
+
setValue: vi.fn(),
|
|
610
|
+
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
|
611
|
+
errors: [],
|
|
612
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
613
|
+
vi.mocked(parseArguments).mockResolvedValue({
|
|
614
|
+
promptInteractive: true,
|
|
615
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
616
|
+
vi.mocked(loadCliConfig).mockResolvedValue({
|
|
617
|
+
isInteractive: () => false,
|
|
618
|
+
getQuestion: () => '',
|
|
619
|
+
getSandbox: () => false,
|
|
620
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
621
|
+
// Mock stdin to be non-TTY
|
|
622
|
+
Object.defineProperty(process.stdin, 'isTTY', {
|
|
623
|
+
value: false,
|
|
624
|
+
configurable: true,
|
|
625
|
+
});
|
|
626
|
+
try {
|
|
627
|
+
await main();
|
|
628
|
+
}
|
|
629
|
+
catch (e) {
|
|
630
|
+
if (!(e instanceof MockProcessExitError))
|
|
631
|
+
throw e;
|
|
632
|
+
}
|
|
633
|
+
expect(writeToStderrSpy).toHaveBeenCalledWith(expect.stringContaining('Error: The --prompt-interactive flag cannot be used'));
|
|
634
|
+
expect(processExitSpy).toHaveBeenCalledWith(1);
|
|
635
|
+
processExitSpy.mockRestore();
|
|
636
|
+
writeToStderrSpy.mockRestore();
|
|
637
|
+
Object.defineProperty(process.stdin, 'isTTY', {
|
|
638
|
+
value: true,
|
|
639
|
+
configurable: true,
|
|
640
|
+
}); // Restore TTY
|
|
641
|
+
});
|
|
642
|
+
it('should log warning when theme is not found', async () => {
|
|
643
|
+
const { loadCliConfig, parseArguments } = await import('./config/config.js');
|
|
644
|
+
const { loadSettings } = await import('./config/settings.js');
|
|
645
|
+
const { themeManager } = await import('./ui/themes/theme-manager.js');
|
|
646
|
+
const debugLoggerWarnSpy = vi
|
|
647
|
+
.spyOn(debugLogger, 'warn')
|
|
648
|
+
.mockImplementation(() => { });
|
|
649
|
+
const processExitSpy = vi
|
|
650
|
+
.spyOn(process, 'exit')
|
|
651
|
+
.mockImplementation((code) => {
|
|
652
|
+
throw new MockProcessExitError(code);
|
|
653
|
+
});
|
|
654
|
+
vi.mocked(loadSettings).mockReturnValue({
|
|
655
|
+
merged: {
|
|
656
|
+
advanced: {},
|
|
657
|
+
security: { auth: {} },
|
|
658
|
+
ui: { theme: 'non-existent-theme' },
|
|
659
|
+
},
|
|
660
|
+
setValue: vi.fn(),
|
|
661
|
+
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
|
662
|
+
errors: [],
|
|
663
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
664
|
+
vi.mocked(parseArguments).mockResolvedValue({
|
|
665
|
+
promptInteractive: false,
|
|
666
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
667
|
+
vi.mocked(loadCliConfig).mockResolvedValue({
|
|
668
|
+
isInteractive: () => false,
|
|
669
|
+
getQuestion: () => 'test',
|
|
670
|
+
getSandbox: () => false,
|
|
671
|
+
getDebugMode: () => false,
|
|
672
|
+
getPolicyEngine: vi.fn(),
|
|
673
|
+
getMessageBus: () => ({ subscribe: vi.fn() }),
|
|
674
|
+
initialize: vi.fn(),
|
|
675
|
+
getContentGeneratorConfig: vi.fn(),
|
|
676
|
+
getMcpServers: () => ({}),
|
|
677
|
+
getMcpClientManager: vi.fn(),
|
|
678
|
+
getIdeMode: () => false,
|
|
679
|
+
getExperimentalZedIntegration: () => false,
|
|
680
|
+
getScreenReader: () => false,
|
|
681
|
+
getGeminiMdFileCount: () => 0,
|
|
682
|
+
getProjectRoot: () => '/',
|
|
683
|
+
getListExtensions: () => false,
|
|
684
|
+
getListSessions: () => false,
|
|
685
|
+
getDeleteSession: () => undefined,
|
|
686
|
+
getToolRegistry: vi.fn(),
|
|
687
|
+
getExtensions: () => [],
|
|
688
|
+
getModel: () => 'gemini-pro',
|
|
689
|
+
getEmbeddingModel: () => 'embedding-001',
|
|
690
|
+
getApprovalMode: () => 'default',
|
|
691
|
+
getCoreTools: () => [],
|
|
692
|
+
getTelemetryEnabled: () => false,
|
|
693
|
+
getTelemetryLogPromptsEnabled: () => false,
|
|
694
|
+
getFileFilteringRespectGitIgnore: () => true,
|
|
695
|
+
getOutputFormat: () => 'text',
|
|
696
|
+
getUsageStatisticsEnabled: () => false,
|
|
697
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
698
|
+
vi.spyOn(themeManager, 'setActiveTheme').mockReturnValue(false);
|
|
699
|
+
try {
|
|
700
|
+
await main();
|
|
701
|
+
}
|
|
702
|
+
catch (e) {
|
|
703
|
+
if (!(e instanceof MockProcessExitError))
|
|
704
|
+
throw e;
|
|
705
|
+
}
|
|
706
|
+
expect(debugLoggerWarnSpy).toHaveBeenCalledWith(expect.stringContaining('Warning: Theme "non-existent-theme" not found.'));
|
|
707
|
+
processExitSpy.mockRestore();
|
|
708
|
+
});
|
|
709
|
+
it('should handle session selector error', async () => {
|
|
710
|
+
const { loadCliConfig, parseArguments } = await import('./config/config.js');
|
|
711
|
+
const { loadSettings } = await import('./config/settings.js');
|
|
712
|
+
vi.mock('./utils/sessionUtils.js', () => ({
|
|
713
|
+
SessionSelector: class {
|
|
714
|
+
resolveSession = vi
|
|
715
|
+
.fn()
|
|
716
|
+
.mockRejectedValue(new Error('Session not found'));
|
|
717
|
+
},
|
|
718
|
+
}));
|
|
719
|
+
const processExitSpy = vi
|
|
720
|
+
.spyOn(process, 'exit')
|
|
721
|
+
.mockImplementation((code) => {
|
|
722
|
+
throw new MockProcessExitError(code);
|
|
723
|
+
});
|
|
724
|
+
const consoleErrorSpy = vi
|
|
725
|
+
.spyOn(console, 'error')
|
|
726
|
+
.mockImplementation(() => { });
|
|
727
|
+
vi.mocked(loadSettings).mockReturnValue({
|
|
728
|
+
merged: { advanced: {}, security: { auth: {} }, ui: { theme: 'test' } },
|
|
729
|
+
setValue: vi.fn(),
|
|
730
|
+
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
|
731
|
+
errors: [],
|
|
732
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
733
|
+
vi.mocked(parseArguments).mockResolvedValue({
|
|
734
|
+
promptInteractive: false,
|
|
735
|
+
resume: 'session-id',
|
|
736
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
737
|
+
vi.mocked(loadCliConfig).mockResolvedValue({
|
|
738
|
+
isInteractive: () => true,
|
|
739
|
+
getQuestion: () => '',
|
|
740
|
+
getSandbox: () => false,
|
|
741
|
+
getDebugMode: () => false,
|
|
742
|
+
getPolicyEngine: vi.fn(),
|
|
743
|
+
getMessageBus: () => ({ subscribe: vi.fn() }),
|
|
744
|
+
initialize: vi.fn(),
|
|
745
|
+
getContentGeneratorConfig: vi.fn(),
|
|
746
|
+
getMcpServers: () => ({}),
|
|
747
|
+
getMcpClientManager: vi.fn(),
|
|
748
|
+
getIdeMode: () => false,
|
|
749
|
+
getExperimentalZedIntegration: () => false,
|
|
750
|
+
getScreenReader: () => false,
|
|
751
|
+
getGeminiMdFileCount: () => 0,
|
|
752
|
+
getProjectRoot: () => '/',
|
|
753
|
+
getListExtensions: () => false,
|
|
754
|
+
getListSessions: () => false,
|
|
755
|
+
getDeleteSession: () => undefined,
|
|
756
|
+
getToolRegistry: vi.fn(),
|
|
757
|
+
getExtensions: () => [],
|
|
758
|
+
getModel: () => 'gemini-pro',
|
|
759
|
+
getEmbeddingModel: () => 'embedding-001',
|
|
760
|
+
getApprovalMode: () => 'default',
|
|
761
|
+
getCoreTools: () => [],
|
|
762
|
+
getTelemetryEnabled: () => false,
|
|
763
|
+
getTelemetryLogPromptsEnabled: () => false,
|
|
764
|
+
getFileFilteringRespectGitIgnore: () => true,
|
|
765
|
+
getOutputFormat: () => 'text',
|
|
766
|
+
getUsageStatisticsEnabled: () => false,
|
|
767
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
768
|
+
try {
|
|
769
|
+
await main();
|
|
770
|
+
}
|
|
771
|
+
catch (e) {
|
|
772
|
+
if (!(e instanceof MockProcessExitError))
|
|
773
|
+
throw e;
|
|
774
|
+
}
|
|
775
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Error resuming session: Session not found'));
|
|
776
|
+
expect(processExitSpy).toHaveBeenCalledWith(1);
|
|
777
|
+
processExitSpy.mockRestore();
|
|
778
|
+
consoleErrorSpy.mockRestore();
|
|
779
|
+
});
|
|
780
|
+
it.skip('should log error when cleanupExpiredSessions fails', async () => {
|
|
781
|
+
const { loadCliConfig, parseArguments } = await import('./config/config.js');
|
|
782
|
+
const { loadSettings } = await import('./config/settings.js');
|
|
783
|
+
const { cleanupExpiredSessions } = await import('./utils/sessionCleanup.js');
|
|
784
|
+
vi.mocked(cleanupExpiredSessions).mockRejectedValue(new Error('Cleanup failed'));
|
|
785
|
+
const debugLoggerErrorSpy = vi
|
|
786
|
+
.spyOn(debugLogger, 'error')
|
|
787
|
+
.mockImplementation(() => { });
|
|
788
|
+
const processExitSpy = vi
|
|
789
|
+
.spyOn(process, 'exit')
|
|
790
|
+
.mockImplementation((code) => {
|
|
791
|
+
throw new MockProcessExitError(code);
|
|
792
|
+
});
|
|
793
|
+
vi.mocked(loadSettings).mockReturnValue({
|
|
794
|
+
merged: { advanced: {}, security: { auth: {} }, ui: {} },
|
|
795
|
+
setValue: vi.fn(),
|
|
796
|
+
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
|
797
|
+
errors: [],
|
|
798
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
799
|
+
vi.mocked(parseArguments).mockResolvedValue({
|
|
800
|
+
promptInteractive: false,
|
|
801
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
802
|
+
vi.mocked(loadCliConfig).mockResolvedValue({
|
|
803
|
+
isInteractive: () => false,
|
|
804
|
+
getQuestion: () => 'test',
|
|
805
|
+
getSandbox: () => false,
|
|
806
|
+
getDebugMode: () => false,
|
|
807
|
+
getPolicyEngine: vi.fn(),
|
|
808
|
+
getMessageBus: () => ({ subscribe: vi.fn() }),
|
|
809
|
+
initialize: vi.fn(),
|
|
810
|
+
getContentGeneratorConfig: vi.fn(),
|
|
811
|
+
getMcpServers: () => ({}),
|
|
812
|
+
getMcpClientManager: vi.fn(),
|
|
813
|
+
getIdeMode: () => false,
|
|
814
|
+
getExperimentalZedIntegration: () => false,
|
|
815
|
+
getScreenReader: () => false,
|
|
816
|
+
getGeminiMdFileCount: () => 0,
|
|
817
|
+
getProjectRoot: () => '/',
|
|
818
|
+
getListExtensions: () => false,
|
|
819
|
+
getListSessions: () => false,
|
|
820
|
+
getDeleteSession: () => undefined,
|
|
821
|
+
getToolRegistry: vi.fn(),
|
|
822
|
+
getExtensions: () => [],
|
|
823
|
+
getModel: () => 'gemini-pro',
|
|
824
|
+
getEmbeddingModel: () => 'embedding-001',
|
|
825
|
+
getApprovalMode: () => 'default',
|
|
826
|
+
getCoreTools: () => [],
|
|
827
|
+
getTelemetryEnabled: () => false,
|
|
828
|
+
getTelemetryLogPromptsEnabled: () => false,
|
|
829
|
+
getFileFilteringRespectGitIgnore: () => true,
|
|
830
|
+
getOutputFormat: () => 'text',
|
|
831
|
+
getUsageStatisticsEnabled: () => false,
|
|
832
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
833
|
+
// The mock is already set up at the top of the test
|
|
834
|
+
try {
|
|
835
|
+
await main();
|
|
836
|
+
}
|
|
837
|
+
catch (e) {
|
|
838
|
+
if (!(e instanceof MockProcessExitError))
|
|
839
|
+
throw e;
|
|
840
|
+
}
|
|
841
|
+
expect(debugLoggerErrorSpy).toHaveBeenCalledWith(expect.stringContaining('Failed to cleanup expired sessions: Cleanup failed'));
|
|
842
|
+
expect(processExitSpy).toHaveBeenCalledWith(0); // Should not exit on cleanup failure
|
|
843
|
+
processExitSpy.mockRestore();
|
|
844
|
+
});
|
|
845
|
+
it('should handle refreshAuth failure', async () => {
|
|
846
|
+
const { loadCliConfig, parseArguments } = await import('./config/config.js');
|
|
847
|
+
const { loadSettings } = await import('./config/settings.js');
|
|
848
|
+
const { loadSandboxConfig } = await import('./config/sandboxConfig.js');
|
|
849
|
+
const processExitSpy = vi
|
|
850
|
+
.spyOn(process, 'exit')
|
|
851
|
+
.mockImplementation((code) => {
|
|
852
|
+
throw new MockProcessExitError(code);
|
|
853
|
+
});
|
|
854
|
+
const debugLoggerErrorSpy = vi
|
|
855
|
+
.spyOn(debugLogger, 'error')
|
|
856
|
+
.mockImplementation(() => { });
|
|
857
|
+
vi.mocked(loadSettings).mockReturnValue({
|
|
858
|
+
merged: {
|
|
859
|
+
advanced: {},
|
|
860
|
+
security: { auth: { selectedType: 'google' } },
|
|
861
|
+
ui: {},
|
|
862
|
+
},
|
|
863
|
+
setValue: vi.fn(),
|
|
864
|
+
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
|
865
|
+
errors: [],
|
|
866
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
867
|
+
vi.mocked(loadSandboxConfig).mockResolvedValue({}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
868
|
+
vi.mocked(parseArguments).mockResolvedValue({
|
|
869
|
+
promptInteractive: false,
|
|
870
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
871
|
+
vi.mocked(loadCliConfig).mockResolvedValue({
|
|
872
|
+
isInteractive: () => true,
|
|
873
|
+
getQuestion: () => '',
|
|
874
|
+
getSandbox: () => false,
|
|
875
|
+
getDebugMode: () => false,
|
|
876
|
+
getPolicyEngine: vi.fn(),
|
|
877
|
+
getMessageBus: () => ({ subscribe: vi.fn() }),
|
|
878
|
+
initialize: vi.fn(),
|
|
879
|
+
getContentGeneratorConfig: vi.fn(),
|
|
880
|
+
getMcpServers: () => ({}),
|
|
881
|
+
getMcpClientManager: vi.fn(),
|
|
882
|
+
getIdeMode: () => false,
|
|
883
|
+
getExperimentalZedIntegration: () => false,
|
|
884
|
+
getScreenReader: () => false,
|
|
885
|
+
getGeminiMdFileCount: () => 0,
|
|
886
|
+
getProjectRoot: () => '/',
|
|
887
|
+
getListExtensions: () => false,
|
|
888
|
+
getListSessions: () => false,
|
|
889
|
+
getDeleteSession: () => undefined,
|
|
890
|
+
getToolRegistry: vi.fn(),
|
|
891
|
+
getExtensions: () => [],
|
|
892
|
+
getModel: () => 'gemini-pro',
|
|
893
|
+
getEmbeddingModel: () => 'embedding-001',
|
|
894
|
+
getApprovalMode: () => 'default',
|
|
895
|
+
getCoreTools: () => [],
|
|
896
|
+
getTelemetryEnabled: () => false,
|
|
897
|
+
getTelemetryLogPromptsEnabled: () => false,
|
|
898
|
+
getFileFilteringRespectGitIgnore: () => true,
|
|
899
|
+
getOutputFormat: () => 'text',
|
|
900
|
+
getUsageStatisticsEnabled: () => false,
|
|
901
|
+
refreshAuth: vi.fn().mockRejectedValue(new Error('Auth refresh failed')),
|
|
902
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
903
|
+
try {
|
|
904
|
+
await main();
|
|
905
|
+
}
|
|
906
|
+
catch (e) {
|
|
907
|
+
if (!(e instanceof MockProcessExitError))
|
|
908
|
+
throw e;
|
|
909
|
+
}
|
|
910
|
+
expect(debugLoggerErrorSpy).toHaveBeenCalledWith('Error authenticating:', expect.any(Error));
|
|
911
|
+
expect(processExitSpy).toHaveBeenCalledWith(1);
|
|
912
|
+
processExitSpy.mockRestore();
|
|
913
|
+
});
|
|
914
|
+
it('should read from stdin in non-interactive mode', async () => {
|
|
915
|
+
const { loadCliConfig, parseArguments } = await import('./config/config.js');
|
|
916
|
+
const { loadSettings } = await import('./config/settings.js');
|
|
917
|
+
const { readStdin } = await import('./utils/readStdin.js');
|
|
918
|
+
const processExitSpy = vi
|
|
919
|
+
.spyOn(process, 'exit')
|
|
920
|
+
.mockImplementation((code) => {
|
|
921
|
+
throw new MockProcessExitError(code);
|
|
922
|
+
});
|
|
923
|
+
vi.mocked(loadSettings).mockReturnValue({
|
|
924
|
+
merged: { advanced: {}, security: { auth: {} }, ui: {} },
|
|
925
|
+
setValue: vi.fn(),
|
|
926
|
+
forScope: () => ({ settings: {}, originalSettings: {}, path: '' }),
|
|
927
|
+
errors: [],
|
|
928
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
929
|
+
vi.mocked(parseArguments).mockResolvedValue({
|
|
930
|
+
promptInteractive: false,
|
|
931
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
932
|
+
vi.mocked(loadCliConfig).mockResolvedValue({
|
|
933
|
+
isInteractive: () => false,
|
|
934
|
+
getQuestion: () => 'test-question',
|
|
935
|
+
getSandbox: () => false,
|
|
936
|
+
getDebugMode: () => false,
|
|
937
|
+
getPolicyEngine: vi.fn(),
|
|
938
|
+
getMessageBus: () => ({ subscribe: vi.fn() }),
|
|
939
|
+
initialize: vi.fn(),
|
|
940
|
+
getContentGeneratorConfig: vi.fn(),
|
|
941
|
+
getMcpServers: () => ({}),
|
|
942
|
+
getMcpClientManager: vi.fn(),
|
|
943
|
+
getIdeMode: () => false,
|
|
944
|
+
getExperimentalZedIntegration: () => false,
|
|
945
|
+
getScreenReader: () => false,
|
|
946
|
+
getGeminiMdFileCount: () => 0,
|
|
947
|
+
getProjectRoot: () => '/',
|
|
948
|
+
getListExtensions: () => false,
|
|
949
|
+
getListSessions: () => false,
|
|
950
|
+
getDeleteSession: () => undefined,
|
|
951
|
+
getToolRegistry: vi.fn(),
|
|
952
|
+
getExtensions: () => [],
|
|
953
|
+
getModel: () => 'gemini-pro',
|
|
954
|
+
getEmbeddingModel: () => 'embedding-001',
|
|
955
|
+
getApprovalMode: () => 'default',
|
|
956
|
+
getCoreTools: () => [],
|
|
957
|
+
getTelemetryEnabled: () => false,
|
|
958
|
+
getTelemetryLogPromptsEnabled: () => false,
|
|
959
|
+
getFileFilteringRespectGitIgnore: () => true,
|
|
960
|
+
getOutputFormat: () => 'text',
|
|
961
|
+
getUsageStatisticsEnabled: () => false,
|
|
962
|
+
}); // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
963
|
+
vi.mock('./utils/readStdin.js', () => ({
|
|
964
|
+
readStdin: vi.fn().mockResolvedValue('stdin-data'),
|
|
965
|
+
}));
|
|
966
|
+
const runNonInteractiveSpy = vi.hoisted(() => vi.fn());
|
|
967
|
+
vi.mock('./nonInteractiveCli.js', () => ({
|
|
968
|
+
runNonInteractive: runNonInteractiveSpy,
|
|
969
|
+
}));
|
|
970
|
+
runNonInteractiveSpy.mockClear();
|
|
971
|
+
vi.mock('./validateNonInterActiveAuth.js', () => ({
|
|
972
|
+
validateNonInteractiveAuth: vi.fn().mockResolvedValue({}),
|
|
973
|
+
}));
|
|
974
|
+
// Mock stdin to be non-TTY
|
|
975
|
+
Object.defineProperty(process.stdin, 'isTTY', {
|
|
976
|
+
value: false,
|
|
977
|
+
configurable: true,
|
|
978
|
+
});
|
|
979
|
+
try {
|
|
980
|
+
await main();
|
|
981
|
+
}
|
|
982
|
+
catch (e) {
|
|
983
|
+
if (!(e instanceof MockProcessExitError))
|
|
984
|
+
throw e;
|
|
985
|
+
}
|
|
986
|
+
expect(readStdin).toHaveBeenCalled();
|
|
987
|
+
// In this test setup, runNonInteractive might be called on the mocked module,
|
|
988
|
+
// but we need to ensure we are checking the correct spy instance.
|
|
989
|
+
// Since vi.mock is hoisted, runNonInteractiveSpy is defined early.
|
|
990
|
+
expect(runNonInteractiveSpy).toHaveBeenCalled();
|
|
991
|
+
const callArgs = runNonInteractiveSpy.mock.calls[0][0];
|
|
992
|
+
expect(callArgs.input).toBe('test-question');
|
|
993
|
+
expect(processExitSpy).toHaveBeenCalledWith(0);
|
|
994
|
+
processExitSpy.mockRestore();
|
|
995
|
+
Object.defineProperty(process.stdin, 'isTTY', {
|
|
996
|
+
value: true,
|
|
997
|
+
configurable: true,
|
|
998
|
+
});
|
|
999
|
+
});
|
|
391
1000
|
});
|
|
392
1001
|
describe('validateDnsResolutionOrder', () => {
|
|
393
1002
|
let debugLoggerWarnSpy;
|
|
@@ -483,6 +1092,17 @@ describe('startInteractiveUI', () => {
|
|
|
483
1092
|
// Verify React element structure is valid (but don't deep dive into JSX internals)
|
|
484
1093
|
expect(reactElement).toBeDefined();
|
|
485
1094
|
});
|
|
1095
|
+
it('should enable mouse events when alternate buffer is enabled', async () => {
|
|
1096
|
+
const { enableMouseEvents } = await import('@google/gemini-cli-core');
|
|
1097
|
+
await startTestInteractiveUI(mockConfig, mockSettings, mockStartupWarnings, mockWorkspaceRoot, undefined, mockInitializationResult);
|
|
1098
|
+
expect(enableMouseEvents).toHaveBeenCalled();
|
|
1099
|
+
});
|
|
1100
|
+
it('should patch console', async () => {
|
|
1101
|
+
const { ConsolePatcher } = await import('./ui/utils/ConsolePatcher.js');
|
|
1102
|
+
const patchSpy = vi.spyOn(ConsolePatcher.prototype, 'patch');
|
|
1103
|
+
await startTestInteractiveUI(mockConfig, mockSettings, mockStartupWarnings, mockWorkspaceRoot, undefined, mockInitializationResult);
|
|
1104
|
+
expect(patchSpy).toHaveBeenCalled();
|
|
1105
|
+
});
|
|
486
1106
|
it('should perform all startup tasks in correct order', async () => {
|
|
487
1107
|
const { getCliVersion } = await import('./utils/version.js');
|
|
488
1108
|
const { checkForUpdates } = await import('./ui/utils/updateCheck.js');
|