@google/gemini-cli-core 0.3.2 → 0.4.0-preview
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/dist/google-gemini-cli-core-0.3.1.tgz +0 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/src/code_assist/codeAssist.d.ts +2 -0
- package/dist/src/code_assist/codeAssist.js +12 -0
- package/dist/src/code_assist/codeAssist.js.map +1 -1
- package/dist/src/code_assist/converter.d.ts +2 -1
- package/dist/src/code_assist/converter.js +1 -1
- package/dist/src/code_assist/converter.js.map +1 -1
- package/dist/src/code_assist/oauth2.js +64 -27
- package/dist/src/code_assist/oauth2.js.map +1 -1
- package/dist/src/code_assist/oauth2.test.js +252 -0
- package/dist/src/code_assist/oauth2.test.js.map +1 -1
- package/dist/src/config/config.d.ts +12 -7
- package/dist/src/config/config.js +47 -27
- package/dist/src/config/config.js.map +1 -1
- package/dist/src/config/config.test.js +65 -41
- package/dist/src/config/config.test.js.map +1 -1
- package/dist/src/config/models.d.ts +1 -0
- package/dist/src/config/models.js +2 -0
- package/dist/src/config/models.js.map +1 -1
- package/dist/src/core/client.d.ts +6 -2
- package/dist/src/core/client.js +22 -11
- package/dist/src/core/client.js.map +1 -1
- package/dist/src/core/client.test.js +62 -7
- package/dist/src/core/client.test.js.map +1 -1
- package/dist/src/core/contentGenerator.d.ts +2 -2
- package/dist/src/core/coreToolScheduler.test.js +18 -0
- package/dist/src/core/coreToolScheduler.test.js.map +1 -1
- package/dist/src/core/geminiChat.d.ts +30 -1
- package/dist/src/core/geminiChat.js +145 -5
- package/dist/src/core/geminiChat.js.map +1 -1
- package/dist/src/core/geminiChat.test.js +273 -5
- package/dist/src/core/geminiChat.test.js.map +1 -1
- package/dist/src/core/loggingContentGenerator.js +9 -9
- package/dist/src/core/loggingContentGenerator.js.map +1 -1
- package/dist/src/core/nonInteractiveToolExecutor.test.js +2 -0
- package/dist/src/core/nonInteractiveToolExecutor.test.js.map +1 -1
- package/dist/src/core/subagent.js +5 -6
- package/dist/src/core/subagent.js.map +1 -1
- package/dist/src/core/subagent.test.js +20 -9
- package/dist/src/core/subagent.test.js.map +1 -1
- package/dist/src/core/turn.d.ts +18 -4
- package/dist/src/core/turn.js +43 -9
- package/dist/src/core/turn.js.map +1 -1
- package/dist/src/core/turn.test.js +329 -89
- package/dist/src/core/turn.test.js.map +1 -1
- 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/ide/ide-client.d.ts +7 -2
- package/dist/src/ide/ide-client.js +33 -13
- package/dist/src/ide/ide-client.js.map +1 -1
- package/dist/src/ide/ideContext.d.ts +12 -0
- package/dist/src/ide/ideContext.js +1 -0
- package/dist/src/ide/ideContext.js.map +1 -1
- package/dist/src/ide/process-utils.d.ts +1 -0
- package/dist/src/ide/process-utils.js +31 -36
- package/dist/src/ide/process-utils.js.map +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.js +3 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcp/oauth-provider.d.ts +12 -12
- package/dist/src/mcp/oauth-provider.js +32 -31
- package/dist/src/mcp/oauth-provider.js.map +1 -1
- package/dist/src/mcp/oauth-provider.test.js +74 -35
- package/dist/src/mcp/oauth-provider.test.js.map +1 -1
- package/dist/src/mcp/oauth-token-storage.d.ts +8 -8
- package/dist/src/mcp/oauth-token-storage.js +8 -8
- package/dist/src/mcp/oauth-token-storage.js.map +1 -1
- package/dist/src/mcp/oauth-token-storage.test.js +23 -21
- package/dist/src/mcp/oauth-token-storage.test.js.map +1 -1
- package/dist/src/mcp/token-storage/base-token-storage.d.ts +1 -1
- package/dist/src/mcp/token-storage/base-token-storage.js +1 -1
- package/dist/src/mcp/token-storage/base-token-storage.js.map +1 -1
- package/dist/src/mcp/token-storage/base-token-storage.test.js +1 -1
- package/dist/src/mcp/token-storage/base-token-storage.test.js.map +1 -1
- package/dist/src/mcp/token-storage/file-token-storage.d.ts +24 -0
- package/dist/src/mcp/token-storage/file-token-storage.js +144 -0
- package/dist/src/mcp/token-storage/file-token-storage.js.map +1 -0
- package/dist/src/mcp/token-storage/file-token-storage.test.d.ts +6 -0
- package/dist/src/mcp/token-storage/file-token-storage.test.js +235 -0
- package/dist/src/mcp/token-storage/file-token-storage.test.js.map +1 -0
- package/dist/src/mcp/token-storage/hybrid-token-storage.d.ts +23 -0
- package/dist/src/mcp/token-storage/hybrid-token-storage.js +78 -0
- package/dist/src/mcp/token-storage/hybrid-token-storage.js.map +1 -0
- package/dist/src/mcp/token-storage/hybrid-token-storage.test.d.ts +6 -0
- package/dist/src/mcp/token-storage/hybrid-token-storage.test.js +193 -0
- package/dist/src/mcp/token-storage/hybrid-token-storage.test.js.map +1 -0
- package/dist/src/mcp/token-storage/keychain-token-storage.d.ts +31 -0
- package/dist/src/mcp/token-storage/keychain-token-storage.js +190 -0
- package/dist/src/mcp/token-storage/keychain-token-storage.js.map +1 -0
- package/dist/src/mcp/token-storage/keychain-token-storage.test.d.ts +6 -0
- package/dist/src/mcp/token-storage/keychain-token-storage.test.js +254 -0
- package/dist/src/mcp/token-storage/keychain-token-storage.test.js.map +1 -0
- package/dist/src/mcp/token-storage/types.d.ts +4 -0
- package/dist/src/mcp/token-storage/types.js +5 -1
- package/dist/src/mcp/token-storage/types.js.map +1 -1
- package/dist/src/services/chatRecordingService.d.ts +5 -12
- package/dist/src/services/chatRecordingService.js +25 -16
- package/dist/src/services/chatRecordingService.js.map +1 -1
- package/dist/src/services/chatRecordingService.test.js +54 -17
- package/dist/src/services/chatRecordingService.test.js.map +1 -1
- package/dist/src/services/shellExecutionService.js +5 -5
- package/dist/src/services/shellExecutionService.js.map +1 -1
- package/dist/src/services/shellExecutionService.test.js +1 -1
- package/dist/src/services/shellExecutionService.test.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js +12 -18
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js +27 -0
- package/dist/src/telemetry/clearcut-logger/clearcut-logger.test.js.map +1 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.d.ts +3 -1
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js +4 -0
- package/dist/src/telemetry/clearcut-logger/event-metadata-key.js.map +1 -1
- package/dist/src/telemetry/constants.d.ts +1 -0
- package/dist/src/telemetry/constants.js +1 -0
- package/dist/src/telemetry/constants.js.map +1 -1
- package/dist/src/telemetry/loggers.js +27 -2
- package/dist/src/telemetry/loggers.js.map +1 -1
- package/dist/src/telemetry/loggers.test.js +39 -3
- package/dist/src/telemetry/loggers.test.js.map +1 -1
- package/dist/src/telemetry/metrics.d.ts +1 -2
- package/dist/src/telemetry/metrics.js +1 -7
- package/dist/src/telemetry/metrics.js.map +1 -1
- package/dist/src/telemetry/metrics.test.js +5 -25
- package/dist/src/telemetry/metrics.test.js.map +1 -1
- package/dist/src/telemetry/types.d.ts +1 -3
- package/dist/src/telemetry/types.js +3 -5
- package/dist/src/telemetry/types.js.map +1 -1
- package/dist/src/telemetry/uiTelemetry.js +4 -4
- package/dist/src/telemetry/uiTelemetry.js.map +1 -1
- package/dist/src/telemetry/uiTelemetry.test.js +4 -4
- package/dist/src/telemetry/uiTelemetry.test.js.map +1 -1
- package/dist/src/test-utils/index.d.ts +6 -0
- package/dist/src/test-utils/index.js +7 -0
- package/dist/src/test-utils/index.js.map +1 -0
- package/dist/src/test-utils/mock-tool.d.ts +41 -0
- package/dist/src/test-utils/mock-tool.js +51 -0
- package/dist/src/test-utils/mock-tool.js.map +1 -0
- package/dist/src/tools/diffOptions.js +21 -13
- package/dist/src/tools/diffOptions.js.map +1 -1
- package/dist/src/tools/diffOptions.test.js +58 -22
- package/dist/src/tools/diffOptions.test.js.map +1 -1
- package/dist/src/tools/edit.d.ts +2 -2
- package/dist/src/tools/edit.js +30 -40
- package/dist/src/tools/edit.js.map +1 -1
- package/dist/src/tools/edit.test.js +50 -9
- package/dist/src/tools/edit.test.js.map +1 -1
- package/dist/src/tools/mcp-client-manager.d.ts +5 -3
- package/dist/src/tools/mcp-client-manager.js +30 -5
- package/dist/src/tools/mcp-client-manager.js.map +1 -1
- package/dist/src/tools/mcp-client-manager.test.js +20 -1
- package/dist/src/tools/mcp-client-manager.test.js.map +1 -1
- package/dist/src/tools/mcp-client.d.ts +5 -5
- package/dist/src/tools/mcp-client.js +40 -35
- package/dist/src/tools/mcp-client.js.map +1 -1
- package/dist/src/tools/mcp-client.test.js +3 -3
- package/dist/src/tools/mcp-client.test.js.map +1 -1
- package/dist/src/tools/mcp-tool.d.ts +3 -2
- package/dist/src/tools/mcp-tool.js +9 -9
- package/dist/src/tools/mcp-tool.js.map +1 -1
- package/dist/src/tools/mcp-tool.test.js +28 -7
- package/dist/src/tools/mcp-tool.test.js.map +1 -1
- package/dist/src/tools/memoryTool.js +5 -33
- package/dist/src/tools/memoryTool.js.map +1 -1
- package/dist/src/tools/read-file.js +1 -1
- package/dist/src/tools/read-file.js.map +1 -1
- package/dist/src/tools/read-many-files.js +1 -1
- package/dist/src/tools/read-many-files.js.map +1 -1
- package/dist/src/tools/read-many-files.test.js +4 -4
- package/dist/src/tools/read-many-files.test.js.map +1 -1
- package/dist/src/tools/shell.js +6 -3
- package/dist/src/tools/shell.js.map +1 -1
- package/dist/src/tools/shell.test.js +3 -3
- package/dist/src/tools/shell.test.js.map +1 -1
- package/dist/src/tools/smart-edit.d.ts +73 -0
- package/dist/src/tools/smart-edit.js +607 -0
- package/dist/src/tools/smart-edit.js.map +1 -0
- package/dist/src/tools/smart-edit.test.d.ts +6 -0
- package/dist/src/tools/smart-edit.test.js +405 -0
- package/dist/src/tools/smart-edit.test.js.map +1 -0
- package/dist/src/tools/tool-registry.d.ts +2 -1
- package/dist/src/tools/tool-registry.js +5 -5
- package/dist/src/tools/tool-registry.js.map +1 -1
- package/dist/src/tools/tools.d.ts +6 -2
- package/dist/src/tools/tools.js.map +1 -1
- package/dist/src/tools/web-fetch.js +4 -3
- package/dist/src/tools/web-fetch.js.map +1 -1
- package/dist/src/tools/web-search.d.ts +1 -1
- package/dist/src/tools/web-search.js +3 -1
- package/dist/src/tools/web-search.js.map +1 -1
- package/dist/src/tools/write-file.js +11 -15
- package/dist/src/tools/write-file.js.map +1 -1
- package/dist/src/tools/write-file.test.js +5 -9
- package/dist/src/tools/write-file.test.js.map +1 -1
- package/dist/src/utils/fileUtils.d.ts +19 -3
- package/dist/src/utils/fileUtils.js +144 -32
- package/dist/src/utils/fileUtils.js.map +1 -1
- package/dist/src/utils/fileUtils.test.js +314 -21
- package/dist/src/utils/fileUtils.test.js.map +1 -1
- package/dist/src/utils/gitIgnoreParser.d.ts +1 -0
- package/dist/src/utils/gitIgnoreParser.js +101 -10
- package/dist/src/utils/gitIgnoreParser.js.map +1 -1
- package/dist/src/utils/gitIgnoreParser.test.js +66 -0
- package/dist/src/utils/gitIgnoreParser.test.js.map +1 -1
- package/dist/src/utils/ide-trust.d.ts +10 -0
- package/dist/src/utils/ide-trust.js +14 -0
- package/dist/src/utils/ide-trust.js.map +1 -0
- package/dist/src/utils/llm-edit-fixer.d.ts +25 -0
- package/dist/src/utils/llm-edit-fixer.js +112 -0
- package/dist/src/utils/llm-edit-fixer.js.map +1 -0
- package/dist/src/utils/memoryDiscovery.d.ts +5 -4
- package/dist/src/utils/memoryDiscovery.js +10 -9
- package/dist/src/utils/memoryDiscovery.js.map +1 -1
- package/dist/src/utils/memoryDiscovery.test.js +38 -19
- package/dist/src/utils/memoryDiscovery.test.js.map +1 -1
- package/dist/src/utils/nextSpeakerChecker.test.js +33 -0
- package/dist/src/utils/nextSpeakerChecker.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -2
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2025 Google LLC
|
|
4
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
5
|
+
*/
|
|
6
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
7
|
+
// Hoist the mock to be available in the vi.mock factory
|
|
8
|
+
const mockKeytar = vi.hoisted(() => ({
|
|
9
|
+
getPassword: vi.fn(),
|
|
10
|
+
setPassword: vi.fn(),
|
|
11
|
+
deletePassword: vi.fn(),
|
|
12
|
+
findCredentials: vi.fn(),
|
|
13
|
+
}));
|
|
14
|
+
const mockServiceName = 'service-name';
|
|
15
|
+
const mockCryptoRandomBytesString = 'random-string';
|
|
16
|
+
// Mock the dynamic import of 'keytar'
|
|
17
|
+
vi.mock('keytar', () => ({
|
|
18
|
+
default: mockKeytar,
|
|
19
|
+
}));
|
|
20
|
+
vi.mock('node:crypto', () => ({
|
|
21
|
+
randomBytes: vi.fn(() => ({
|
|
22
|
+
toString: vi.fn(() => mockCryptoRandomBytesString),
|
|
23
|
+
})),
|
|
24
|
+
}));
|
|
25
|
+
describe('KeychainTokenStorage', () => {
|
|
26
|
+
let storage;
|
|
27
|
+
beforeEach(async () => {
|
|
28
|
+
vi.resetAllMocks();
|
|
29
|
+
// Reset the internal state of the keychain-token-storage module
|
|
30
|
+
vi.resetModules();
|
|
31
|
+
const { KeychainTokenStorage } = await import('./keychain-token-storage.js');
|
|
32
|
+
storage = new KeychainTokenStorage(mockServiceName);
|
|
33
|
+
});
|
|
34
|
+
afterEach(() => {
|
|
35
|
+
vi.restoreAllMocks();
|
|
36
|
+
vi.useRealTimers();
|
|
37
|
+
});
|
|
38
|
+
const validCredentials = {
|
|
39
|
+
serverName: 'test-server',
|
|
40
|
+
token: {
|
|
41
|
+
accessToken: 'access-token',
|
|
42
|
+
tokenType: 'Bearer',
|
|
43
|
+
expiresAt: Date.now() + 3600000,
|
|
44
|
+
},
|
|
45
|
+
updatedAt: Date.now(),
|
|
46
|
+
};
|
|
47
|
+
describe('checkKeychainAvailability', () => {
|
|
48
|
+
it('should return true if keytar is available and functional', async () => {
|
|
49
|
+
mockKeytar.setPassword.mockResolvedValue(undefined);
|
|
50
|
+
mockKeytar.getPassword.mockResolvedValue('test');
|
|
51
|
+
mockKeytar.deletePassword.mockResolvedValue(true);
|
|
52
|
+
const isAvailable = await storage.checkKeychainAvailability();
|
|
53
|
+
expect(isAvailable).toBe(true);
|
|
54
|
+
expect(mockKeytar.setPassword).toHaveBeenCalledWith(mockServiceName, `__keychain_test__${mockCryptoRandomBytesString}`, 'test');
|
|
55
|
+
expect(mockKeytar.getPassword).toHaveBeenCalledWith(mockServiceName, `__keychain_test__${mockCryptoRandomBytesString}`);
|
|
56
|
+
expect(mockKeytar.deletePassword).toHaveBeenCalledWith(mockServiceName, `__keychain_test__${mockCryptoRandomBytesString}`);
|
|
57
|
+
});
|
|
58
|
+
it('should return false if keytar fails to set password', async () => {
|
|
59
|
+
mockKeytar.setPassword.mockRejectedValue(new Error('write error'));
|
|
60
|
+
const isAvailable = await storage.checkKeychainAvailability();
|
|
61
|
+
expect(isAvailable).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
it('should return false if retrieved password does not match', async () => {
|
|
64
|
+
mockKeytar.setPassword.mockResolvedValue(undefined);
|
|
65
|
+
mockKeytar.getPassword.mockResolvedValue('wrong-password');
|
|
66
|
+
mockKeytar.deletePassword.mockResolvedValue(true);
|
|
67
|
+
const isAvailable = await storage.checkKeychainAvailability();
|
|
68
|
+
expect(isAvailable).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
it('should cache the availability result', async () => {
|
|
71
|
+
mockKeytar.setPassword.mockResolvedValue(undefined);
|
|
72
|
+
mockKeytar.getPassword.mockResolvedValue('test');
|
|
73
|
+
mockKeytar.deletePassword.mockResolvedValue(true);
|
|
74
|
+
await storage.checkKeychainAvailability();
|
|
75
|
+
await storage.checkKeychainAvailability();
|
|
76
|
+
expect(mockKeytar.setPassword).toHaveBeenCalledTimes(1);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
describe('with keychain unavailable', () => {
|
|
80
|
+
beforeEach(async () => {
|
|
81
|
+
// Force keychain to be unavailable
|
|
82
|
+
mockKeytar.setPassword.mockRejectedValue(new Error('keychain error'));
|
|
83
|
+
await storage.checkKeychainAvailability();
|
|
84
|
+
});
|
|
85
|
+
it('getCredentials should throw', async () => {
|
|
86
|
+
await expect(storage.getCredentials('server')).rejects.toThrow('Keychain is not available');
|
|
87
|
+
});
|
|
88
|
+
it('setCredentials should throw', async () => {
|
|
89
|
+
await expect(storage.setCredentials(validCredentials)).rejects.toThrow('Keychain is not available');
|
|
90
|
+
});
|
|
91
|
+
it('deleteCredentials should throw', async () => {
|
|
92
|
+
await expect(storage.deleteCredentials('server')).rejects.toThrow('Keychain is not available');
|
|
93
|
+
});
|
|
94
|
+
it('listServers should throw', async () => {
|
|
95
|
+
await expect(storage.listServers()).rejects.toThrow('Keychain is not available');
|
|
96
|
+
});
|
|
97
|
+
it('getAllCredentials should throw', async () => {
|
|
98
|
+
await expect(storage.getAllCredentials()).rejects.toThrow('Keychain is not available');
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
describe('with keychain available', () => {
|
|
102
|
+
beforeEach(async () => {
|
|
103
|
+
mockKeytar.setPassword.mockResolvedValue(undefined);
|
|
104
|
+
mockKeytar.getPassword.mockResolvedValue('test');
|
|
105
|
+
mockKeytar.deletePassword.mockResolvedValue(true);
|
|
106
|
+
await storage.checkKeychainAvailability();
|
|
107
|
+
// Reset mocks after availability check
|
|
108
|
+
vi.resetAllMocks();
|
|
109
|
+
});
|
|
110
|
+
describe('getCredentials', () => {
|
|
111
|
+
it('should return null if no credentials are found', async () => {
|
|
112
|
+
mockKeytar.getPassword.mockResolvedValue(null);
|
|
113
|
+
const result = await storage.getCredentials('test-server');
|
|
114
|
+
expect(result).toBeNull();
|
|
115
|
+
expect(mockKeytar.getPassword).toHaveBeenCalledWith(mockServiceName, 'test-server');
|
|
116
|
+
});
|
|
117
|
+
it('should return credentials if found and not expired', async () => {
|
|
118
|
+
mockKeytar.getPassword.mockResolvedValue(JSON.stringify(validCredentials));
|
|
119
|
+
const result = await storage.getCredentials('test-server');
|
|
120
|
+
expect(result).toEqual(validCredentials);
|
|
121
|
+
});
|
|
122
|
+
it('should return null if credentials have expired', async () => {
|
|
123
|
+
const expiredCreds = {
|
|
124
|
+
...validCredentials,
|
|
125
|
+
token: { ...validCredentials.token, expiresAt: Date.now() - 1000 },
|
|
126
|
+
};
|
|
127
|
+
mockKeytar.getPassword.mockResolvedValue(JSON.stringify(expiredCreds));
|
|
128
|
+
const result = await storage.getCredentials('test-server');
|
|
129
|
+
expect(result).toBeNull();
|
|
130
|
+
});
|
|
131
|
+
it('should throw if stored data is corrupted JSON', async () => {
|
|
132
|
+
mockKeytar.getPassword.mockResolvedValue('not-json');
|
|
133
|
+
await expect(storage.getCredentials('test-server')).rejects.toThrow('Failed to parse stored credentials for test-server');
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
describe('setCredentials', () => {
|
|
137
|
+
it('should save credentials to keychain', async () => {
|
|
138
|
+
vi.useFakeTimers();
|
|
139
|
+
mockKeytar.setPassword.mockResolvedValue(undefined);
|
|
140
|
+
await storage.setCredentials(validCredentials);
|
|
141
|
+
expect(mockKeytar.setPassword).toHaveBeenCalledWith(mockServiceName, 'test-server', JSON.stringify({ ...validCredentials, updatedAt: Date.now() }));
|
|
142
|
+
});
|
|
143
|
+
it('should throw if saving to keychain fails', async () => {
|
|
144
|
+
mockKeytar.setPassword.mockRejectedValue(new Error('keychain write error'));
|
|
145
|
+
await expect(storage.setCredentials(validCredentials)).rejects.toThrow('keychain write error');
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
describe('deleteCredentials', () => {
|
|
149
|
+
it('should delete credentials from keychain', async () => {
|
|
150
|
+
mockKeytar.deletePassword.mockResolvedValue(true);
|
|
151
|
+
await storage.deleteCredentials('test-server');
|
|
152
|
+
expect(mockKeytar.deletePassword).toHaveBeenCalledWith(mockServiceName, 'test-server');
|
|
153
|
+
});
|
|
154
|
+
it('should throw if no credentials were found to delete', async () => {
|
|
155
|
+
mockKeytar.deletePassword.mockResolvedValue(false);
|
|
156
|
+
await expect(storage.deleteCredentials('test-server')).rejects.toThrow('No credentials found for test-server');
|
|
157
|
+
});
|
|
158
|
+
it('should throw if deleting from keychain fails', async () => {
|
|
159
|
+
mockKeytar.deletePassword.mockRejectedValue(new Error('keychain delete error'));
|
|
160
|
+
await expect(storage.deleteCredentials('test-server')).rejects.toThrow('keychain delete error');
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
describe('listServers', () => {
|
|
164
|
+
it('should return a list of server names', async () => {
|
|
165
|
+
mockKeytar.findCredentials.mockResolvedValue([
|
|
166
|
+
{ account: 'server1', password: '' },
|
|
167
|
+
{ account: 'server2', password: '' },
|
|
168
|
+
]);
|
|
169
|
+
const result = await storage.listServers();
|
|
170
|
+
expect(result).toEqual(['server1', 'server2']);
|
|
171
|
+
});
|
|
172
|
+
it('should not include internal test keys in the server list', async () => {
|
|
173
|
+
mockKeytar.findCredentials.mockResolvedValue([
|
|
174
|
+
{ account: 'server1', password: '' },
|
|
175
|
+
{
|
|
176
|
+
account: `__keychain_test__${mockCryptoRandomBytesString}`,
|
|
177
|
+
password: '',
|
|
178
|
+
},
|
|
179
|
+
{ account: 'server2', password: '' },
|
|
180
|
+
]);
|
|
181
|
+
const result = await storage.listServers();
|
|
182
|
+
expect(result).toEqual(['server1', 'server2']);
|
|
183
|
+
});
|
|
184
|
+
it('should return an empty array on error', async () => {
|
|
185
|
+
mockKeytar.findCredentials.mockRejectedValue(new Error('find error'));
|
|
186
|
+
const result = await storage.listServers();
|
|
187
|
+
expect(result).toEqual([]);
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
describe('getAllCredentials', () => {
|
|
191
|
+
it('should return a map of all valid credentials', async () => {
|
|
192
|
+
const creds2 = {
|
|
193
|
+
...validCredentials,
|
|
194
|
+
serverName: 'server2',
|
|
195
|
+
};
|
|
196
|
+
const expiredCreds = {
|
|
197
|
+
...validCredentials,
|
|
198
|
+
serverName: 'expired-server',
|
|
199
|
+
token: { ...validCredentials.token, expiresAt: Date.now() - 1000 },
|
|
200
|
+
};
|
|
201
|
+
const structurallyInvalidCreds = {
|
|
202
|
+
serverName: 'invalid-server',
|
|
203
|
+
};
|
|
204
|
+
mockKeytar.findCredentials.mockResolvedValue([
|
|
205
|
+
{
|
|
206
|
+
account: 'test-server',
|
|
207
|
+
password: JSON.stringify(validCredentials),
|
|
208
|
+
},
|
|
209
|
+
{ account: 'server2', password: JSON.stringify(creds2) },
|
|
210
|
+
{
|
|
211
|
+
account: 'expired-server',
|
|
212
|
+
password: JSON.stringify(expiredCreds),
|
|
213
|
+
},
|
|
214
|
+
{ account: 'bad-server', password: 'not-json' },
|
|
215
|
+
{
|
|
216
|
+
account: 'invalid-server',
|
|
217
|
+
password: JSON.stringify(structurallyInvalidCreds),
|
|
218
|
+
},
|
|
219
|
+
]);
|
|
220
|
+
const result = await storage.getAllCredentials();
|
|
221
|
+
expect(result.size).toBe(2);
|
|
222
|
+
expect(result.get('test-server')).toEqual(validCredentials);
|
|
223
|
+
expect(result.get('server2')).toEqual(creds2);
|
|
224
|
+
expect(result.has('expired-server')).toBe(false);
|
|
225
|
+
expect(result.has('bad-server')).toBe(false);
|
|
226
|
+
expect(result.has('invalid-server')).toBe(false);
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
describe('clearAll', () => {
|
|
230
|
+
it('should delete all credentials for the service', async () => {
|
|
231
|
+
mockKeytar.findCredentials.mockResolvedValue([
|
|
232
|
+
{ account: 'server1', password: '' },
|
|
233
|
+
{ account: 'server2', password: '' },
|
|
234
|
+
]);
|
|
235
|
+
mockKeytar.deletePassword.mockResolvedValue(true);
|
|
236
|
+
await storage.clearAll();
|
|
237
|
+
expect(mockKeytar.deletePassword).toHaveBeenCalledTimes(2);
|
|
238
|
+
expect(mockKeytar.deletePassword).toHaveBeenCalledWith(mockServiceName, 'server1');
|
|
239
|
+
expect(mockKeytar.deletePassword).toHaveBeenCalledWith(mockServiceName, 'server2');
|
|
240
|
+
});
|
|
241
|
+
it('should throw an aggregated error if deletions fail', async () => {
|
|
242
|
+
mockKeytar.findCredentials.mockResolvedValue([
|
|
243
|
+
{ account: 'server1', password: '' },
|
|
244
|
+
{ account: 'server2', password: '' },
|
|
245
|
+
]);
|
|
246
|
+
mockKeytar.deletePassword
|
|
247
|
+
.mockResolvedValueOnce(true)
|
|
248
|
+
.mockRejectedValueOnce(new Error('delete failed'));
|
|
249
|
+
await expect(storage.clearAll()).rejects.toThrow('Failed to clear some credentials: delete failed');
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
//# sourceMappingURL=keychain-token-storage.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"keychain-token-storage.test.js","sourceRoot":"","sources":["../../../../src/mcp/token-storage/keychain-token-storage.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,5 +3,9 @@
|
|
|
3
3
|
* Copyright 2025 Google LLC
|
|
4
4
|
* SPDX-License-Identifier: Apache-2.0
|
|
5
5
|
*/
|
|
6
|
-
export
|
|
6
|
+
export var TokenStorageType;
|
|
7
|
+
(function (TokenStorageType) {
|
|
8
|
+
TokenStorageType["KEYCHAIN"] = "keychain";
|
|
9
|
+
TokenStorageType["ENCRYPTED_FILE"] = "encrypted_file";
|
|
10
|
+
})(TokenStorageType || (TokenStorageType = {}));
|
|
7
11
|
//# sourceMappingURL=types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/mcp/token-storage/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../src/mcp/token-storage/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAkCH,MAAM,CAAN,IAAY,gBAGX;AAHD,WAAY,gBAAgB;IAC1B,yCAAqB,CAAA;IACrB,qDAAiC,CAAA;AACnC,CAAC,EAHW,gBAAgB,KAAhB,gBAAgB,QAG3B"}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
import { type Config } from '../config/config.js';
|
|
7
7
|
import { type Status } from '../core/coreToolScheduler.js';
|
|
8
8
|
import { type ThoughtSummary } from '../core/turn.js';
|
|
9
|
-
import type { PartListUnion } from '@google/genai';
|
|
9
|
+
import type { PartListUnion, GenerateContentResponseUsageMetadata } from '@google/genai';
|
|
10
10
|
/**
|
|
11
11
|
* Token usage summary for a message or conversation.
|
|
12
12
|
*/
|
|
@@ -24,7 +24,7 @@ export interface TokensSummary {
|
|
|
24
24
|
export interface BaseMessageRecord {
|
|
25
25
|
id: string;
|
|
26
26
|
timestamp: string;
|
|
27
|
-
content:
|
|
27
|
+
content: PartListUnion;
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
30
|
* Record of a tool call execution within a conversation.
|
|
@@ -108,8 +108,7 @@ export declare class ChatRecordingService {
|
|
|
108
108
|
*/
|
|
109
109
|
recordMessage(message: {
|
|
110
110
|
type: ConversationRecordExtra['type'];
|
|
111
|
-
content:
|
|
112
|
-
append?: boolean;
|
|
111
|
+
content: PartListUnion;
|
|
113
112
|
}): void;
|
|
114
113
|
/**
|
|
115
114
|
* Records a thought from the assistant's reasoning process.
|
|
@@ -118,16 +117,10 @@ export declare class ChatRecordingService {
|
|
|
118
117
|
/**
|
|
119
118
|
* Updates the tokens for the last message in the conversation (which should be by Gemini).
|
|
120
119
|
*/
|
|
121
|
-
recordMessageTokens(
|
|
122
|
-
input: number;
|
|
123
|
-
output: number;
|
|
124
|
-
cached: number;
|
|
125
|
-
thoughts?: number;
|
|
126
|
-
tool?: number;
|
|
127
|
-
total: number;
|
|
128
|
-
}): void;
|
|
120
|
+
recordMessageTokens(respUsageMetadata: GenerateContentResponseUsageMetadata): void;
|
|
129
121
|
/**
|
|
130
122
|
* Adds tool calls to the last message in the conversation (which should be by Gemini).
|
|
123
|
+
* This method enriches tool calls with metadata from the ToolRegistry.
|
|
131
124
|
*/
|
|
132
125
|
recordToolCalls(toolCalls: ToolCallRecord[]): void;
|
|
133
126
|
/**
|
|
@@ -97,15 +97,6 @@ export class ChatRecordingService {
|
|
|
97
97
|
return;
|
|
98
98
|
try {
|
|
99
99
|
this.updateConversation((conversation) => {
|
|
100
|
-
if (message.append) {
|
|
101
|
-
const lastMsg = this.getLastMessage(conversation);
|
|
102
|
-
if (lastMsg && lastMsg.type === message.type) {
|
|
103
|
-
lastMsg.content += message.content;
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
// We're not appending, or we are appending but the last message's type is not the same as
|
|
108
|
-
// the specified type, so just create a new message.
|
|
109
100
|
const msg = this.newMessage(message.type, message.content);
|
|
110
101
|
if (msg.type === 'gemini') {
|
|
111
102
|
// If it's a new Gemini message then incorporate any queued thoughts.
|
|
@@ -142,19 +133,25 @@ export class ChatRecordingService {
|
|
|
142
133
|
});
|
|
143
134
|
}
|
|
144
135
|
catch (error) {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
throw error;
|
|
148
|
-
}
|
|
136
|
+
console.error('Error saving thought:', error);
|
|
137
|
+
throw error;
|
|
149
138
|
}
|
|
150
139
|
}
|
|
151
140
|
/**
|
|
152
141
|
* Updates the tokens for the last message in the conversation (which should be by Gemini).
|
|
153
142
|
*/
|
|
154
|
-
recordMessageTokens(
|
|
143
|
+
recordMessageTokens(respUsageMetadata) {
|
|
155
144
|
if (!this.conversationFile)
|
|
156
145
|
return;
|
|
157
146
|
try {
|
|
147
|
+
const tokens = {
|
|
148
|
+
input: respUsageMetadata.promptTokenCount ?? 0,
|
|
149
|
+
output: respUsageMetadata.candidatesTokenCount ?? 0,
|
|
150
|
+
cached: respUsageMetadata.cachedContentTokenCount ?? 0,
|
|
151
|
+
thoughts: respUsageMetadata.thoughtsTokenCount ?? 0,
|
|
152
|
+
tool: respUsageMetadata.toolUsePromptTokenCount ?? 0,
|
|
153
|
+
total: respUsageMetadata.totalTokenCount ?? 0,
|
|
154
|
+
};
|
|
158
155
|
this.updateConversation((conversation) => {
|
|
159
156
|
const lastMsg = this.getLastMessage(conversation);
|
|
160
157
|
// If the last message already has token info, it's because this new token info is for a
|
|
@@ -175,10 +172,22 @@ export class ChatRecordingService {
|
|
|
175
172
|
}
|
|
176
173
|
/**
|
|
177
174
|
* Adds tool calls to the last message in the conversation (which should be by Gemini).
|
|
175
|
+
* This method enriches tool calls with metadata from the ToolRegistry.
|
|
178
176
|
*/
|
|
179
177
|
recordToolCalls(toolCalls) {
|
|
180
178
|
if (!this.conversationFile)
|
|
181
179
|
return;
|
|
180
|
+
// Enrich tool calls with metadata from the ToolRegistry
|
|
181
|
+
const toolRegistry = this.config.getToolRegistry();
|
|
182
|
+
const enrichedToolCalls = toolCalls.map((toolCall) => {
|
|
183
|
+
const toolInstance = toolRegistry.getTool(toolCall.name);
|
|
184
|
+
return {
|
|
185
|
+
...toolCall,
|
|
186
|
+
displayName: toolInstance?.displayName || toolCall.name,
|
|
187
|
+
description: toolInstance?.description || '',
|
|
188
|
+
renderOutputAsMarkdown: toolInstance?.isOutputMarkdown || false,
|
|
189
|
+
};
|
|
190
|
+
});
|
|
182
191
|
try {
|
|
183
192
|
this.updateConversation((conversation) => {
|
|
184
193
|
const lastMsg = this.getLastMessage(conversation);
|
|
@@ -199,7 +208,7 @@ export class ChatRecordingService {
|
|
|
199
208
|
// resulting message's type, and so it thinks that toolCalls may
|
|
200
209
|
// not be present. Confirming the type here satisfies it.
|
|
201
210
|
type: 'gemini',
|
|
202
|
-
toolCalls,
|
|
211
|
+
toolCalls: enrichedToolCalls,
|
|
203
212
|
thoughts: this.queuedThoughts,
|
|
204
213
|
model: this.config.getModel(),
|
|
205
214
|
};
|
|
@@ -234,7 +243,7 @@ export class ChatRecordingService {
|
|
|
234
243
|
}
|
|
235
244
|
});
|
|
236
245
|
// Add any new tools calls that aren't in the message yet.
|
|
237
|
-
for (const toolCall of
|
|
246
|
+
for (const toolCall of enrichedToolCalls) {
|
|
238
247
|
const existingToolCall = lastMsg.toolCalls.find((tc) => tc.id === toolCall.id);
|
|
239
248
|
if (!existingToolCall) {
|
|
240
249
|
lastMsg.toolCalls.push(toolCall);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chatRecordingService.js","sourceRoot":"","sources":["../../../src/services/chatRecordingService.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAe,MAAM,qBAAqB,CAAC;AAClD,OAAO,EAAe,MAAM,8BAA8B,CAAC;AAC3D,OAAO,EAAuB,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"chatRecordingService.js","sourceRoot":"","sources":["../../../src/services/chatRecordingService.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,7 +11,14 @@ import { ChatRecordingService } from './chatRecordingService.js';
|
|
|
11
11
|
import { getProjectHash } from '../utils/paths.js';
|
|
12
12
|
vi.mock('node:fs');
|
|
13
13
|
vi.mock('node:path');
|
|
14
|
-
vi.mock('node:crypto')
|
|
14
|
+
vi.mock('node:crypto', () => ({
|
|
15
|
+
randomUUID: vi.fn(),
|
|
16
|
+
createHash: vi.fn(() => ({
|
|
17
|
+
update: vi.fn(() => ({
|
|
18
|
+
digest: vi.fn(() => 'mocked-hash'),
|
|
19
|
+
})),
|
|
20
|
+
})),
|
|
21
|
+
}));
|
|
15
22
|
vi.mock('../utils/paths.js');
|
|
16
23
|
describe('ChatRecordingService', () => {
|
|
17
24
|
let chatRecordingService;
|
|
@@ -29,6 +36,13 @@ describe('ChatRecordingService', () => {
|
|
|
29
36
|
},
|
|
30
37
|
getModel: vi.fn().mockReturnValue('gemini-pro'),
|
|
31
38
|
getDebugMode: vi.fn().mockReturnValue(false),
|
|
39
|
+
getToolRegistry: vi.fn().mockReturnValue({
|
|
40
|
+
getTool: vi.fn().mockReturnValue({
|
|
41
|
+
displayName: 'Test Tool',
|
|
42
|
+
description: 'A test tool',
|
|
43
|
+
isOutputMarkdown: false,
|
|
44
|
+
}),
|
|
45
|
+
}),
|
|
32
46
|
};
|
|
33
47
|
vi.mocked(getProjectHash).mockReturnValue('test-project-hash');
|
|
34
48
|
vi.mocked(randomUUID).mockReturnValue('this-is-a-test-uuid');
|
|
@@ -91,7 +105,7 @@ describe('ChatRecordingService', () => {
|
|
|
91
105
|
expect(conversation.messages[0].content).toBe('Hello');
|
|
92
106
|
expect(conversation.messages[0].type).toBe('user');
|
|
93
107
|
});
|
|
94
|
-
it('should
|
|
108
|
+
it('should create separate messages when recording multiple messages', () => {
|
|
95
109
|
const writeFileSyncSpy = vi
|
|
96
110
|
.spyOn(fs, 'writeFileSync')
|
|
97
111
|
.mockImplementation(() => undefined);
|
|
@@ -110,14 +124,14 @@ describe('ChatRecordingService', () => {
|
|
|
110
124
|
vi.spyOn(fs, 'readFileSync').mockReturnValue(JSON.stringify(initialConversation));
|
|
111
125
|
chatRecordingService.recordMessage({
|
|
112
126
|
type: 'user',
|
|
113
|
-
content: '
|
|
114
|
-
append: true,
|
|
127
|
+
content: 'World',
|
|
115
128
|
});
|
|
116
129
|
expect(mkdirSyncSpy).toHaveBeenCalled();
|
|
117
130
|
expect(writeFileSyncSpy).toHaveBeenCalled();
|
|
118
131
|
const conversation = JSON.parse(writeFileSyncSpy.mock.calls[0][1]);
|
|
119
|
-
expect(conversation.messages).toHaveLength(
|
|
120
|
-
expect(conversation.messages[0].content).toBe('Hello
|
|
132
|
+
expect(conversation.messages).toHaveLength(2);
|
|
133
|
+
expect(conversation.messages[0].content).toBe('Hello');
|
|
134
|
+
expect(conversation.messages[1].content).toBe('World');
|
|
121
135
|
});
|
|
122
136
|
});
|
|
123
137
|
describe('recordThought', () => {
|
|
@@ -157,17 +171,24 @@ describe('ChatRecordingService', () => {
|
|
|
157
171
|
};
|
|
158
172
|
vi.spyOn(fs, 'readFileSync').mockReturnValue(JSON.stringify(initialConversation));
|
|
159
173
|
chatRecordingService.recordMessageTokens({
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
174
|
+
promptTokenCount: 1,
|
|
175
|
+
candidatesTokenCount: 2,
|
|
176
|
+
totalTokenCount: 3,
|
|
177
|
+
cachedContentTokenCount: 0,
|
|
164
178
|
});
|
|
165
179
|
expect(mkdirSyncSpy).toHaveBeenCalled();
|
|
166
180
|
expect(writeFileSyncSpy).toHaveBeenCalled();
|
|
167
181
|
const conversation = JSON.parse(writeFileSyncSpy.mock.calls[0][1]);
|
|
168
182
|
expect(conversation.messages[0]).toEqual({
|
|
169
183
|
...initialConversation.messages[0],
|
|
170
|
-
tokens: {
|
|
184
|
+
tokens: {
|
|
185
|
+
input: 1,
|
|
186
|
+
output: 2,
|
|
187
|
+
total: 3,
|
|
188
|
+
cached: 0,
|
|
189
|
+
thoughts: 0,
|
|
190
|
+
tool: 0,
|
|
191
|
+
},
|
|
171
192
|
});
|
|
172
193
|
});
|
|
173
194
|
it('should queue token info if the last message already has tokens', () => {
|
|
@@ -186,10 +207,10 @@ describe('ChatRecordingService', () => {
|
|
|
186
207
|
};
|
|
187
208
|
vi.spyOn(fs, 'readFileSync').mockReturnValue(JSON.stringify(initialConversation));
|
|
188
209
|
chatRecordingService.recordMessageTokens({
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
210
|
+
promptTokenCount: 2,
|
|
211
|
+
candidatesTokenCount: 2,
|
|
212
|
+
totalTokenCount: 4,
|
|
213
|
+
cachedContentTokenCount: 0,
|
|
193
214
|
});
|
|
194
215
|
// @ts-expect-error private property
|
|
195
216
|
expect(chatRecordingService.queuedTokens).toEqual({
|
|
@@ -197,6 +218,8 @@ describe('ChatRecordingService', () => {
|
|
|
197
218
|
output: 2,
|
|
198
219
|
total: 4,
|
|
199
220
|
cached: 0,
|
|
221
|
+
thoughts: 0,
|
|
222
|
+
tool: 0,
|
|
200
223
|
});
|
|
201
224
|
});
|
|
202
225
|
});
|
|
@@ -234,7 +257,14 @@ describe('ChatRecordingService', () => {
|
|
|
234
257
|
const conversation = JSON.parse(writeFileSyncSpy.mock.calls[0][1]);
|
|
235
258
|
expect(conversation.messages[0]).toEqual({
|
|
236
259
|
...initialConversation.messages[0],
|
|
237
|
-
toolCalls: [
|
|
260
|
+
toolCalls: [
|
|
261
|
+
{
|
|
262
|
+
...toolCall,
|
|
263
|
+
displayName: 'Test Tool',
|
|
264
|
+
description: 'A test tool',
|
|
265
|
+
renderOutputAsMarkdown: false,
|
|
266
|
+
},
|
|
267
|
+
],
|
|
238
268
|
});
|
|
239
269
|
});
|
|
240
270
|
it('should create a new message if the last message is not from gemini', () => {
|
|
@@ -273,7 +303,14 @@ describe('ChatRecordingService', () => {
|
|
|
273
303
|
type: 'gemini',
|
|
274
304
|
thoughts: [],
|
|
275
305
|
content: '',
|
|
276
|
-
toolCalls: [
|
|
306
|
+
toolCalls: [
|
|
307
|
+
{
|
|
308
|
+
...toolCall,
|
|
309
|
+
displayName: 'Test Tool',
|
|
310
|
+
description: 'A test tool',
|
|
311
|
+
renderOutputAsMarkdown: false,
|
|
312
|
+
},
|
|
313
|
+
],
|
|
277
314
|
});
|
|
278
315
|
});
|
|
279
316
|
});
|