repoburg 1.3.136 → 1.3.138

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.
Files changed (172) hide show
  1. package/CODEMAP.md +3 -11
  2. package/README.md +4 -4
  3. package/backend/.env +2 -2
  4. package/backend/CODEMAP.md +2 -3
  5. package/backend/dist/src/core-entities/llm-call-log.entity.d.ts +1 -1
  6. package/backend/dist/src/core-entities/llm-call-log.entity.js +3 -3
  7. package/backend/dist/src/core-entities/llm-call-log.entity.js.map +1 -1
  8. package/backend/dist/src/core-entities/session.entity.js +2 -2
  9. package/backend/dist/src/core-entities/session.entity.js.map +1 -1
  10. package/backend/dist/src/core-entities/system-prompt.entity.js +1 -1
  11. package/backend/dist/src/core-entities/system-prompt.entity.js.map +1 -1
  12. package/backend/dist/src/llm-call-logs/dto/llm-call-log.dto.d.ts +1 -1
  13. package/backend/dist/src/llm-call-logs/dto/llm-call-log.dto.js +1 -1
  14. package/backend/dist/src/llm-call-logs/dto/llm-call-log.dto.js.map +1 -1
  15. package/backend/dist/src/llm-call-logs/llm-call-logs.controller.js +1 -1
  16. package/backend/dist/src/llm-orchestration/action-handlers/manage-sub-agents.handler.js +1 -1
  17. package/backend/dist/src/llm-orchestration/action-handlers/overwrite-file.handler.js +1 -0
  18. package/backend/dist/src/llm-orchestration/action-handlers/overwrite-file.handler.js.map +1 -1
  19. package/backend/dist/src/llm-orchestration/action-handlers/quick-edit.handler.js +3 -0
  20. package/backend/dist/src/llm-orchestration/action-handlers/quick-edit.handler.js.map +1 -1
  21. package/backend/dist/src/llm-provider/llm-provider.interface.d.ts +3 -9
  22. package/backend/dist/src/llm-provider/llm-provider.interface.js +2 -9
  23. package/backend/dist/src/llm-provider/llm-provider.interface.js.map +1 -1
  24. package/backend/dist/src/llm-provider/llm-provider.module.js +1 -2
  25. package/backend/dist/src/llm-provider/llm-provider.module.js.map +1 -1
  26. package/backend/dist/src/llm-provider/proxy-llm.provider.d.ts +1 -3
  27. package/backend/dist/src/llm-provider/proxy-llm.provider.js +4 -12
  28. package/backend/dist/src/llm-provider/proxy-llm.provider.js.map +1 -1
  29. package/backend/dist/src/llm-responses/dto/sync-conversation.dto.js +2 -2
  30. package/backend/dist/src/llm-responses/dto/sync-conversation.dto.js.map +1 -1
  31. package/backend/dist/src/sessions/dto/session.dto.d.ts +1 -1
  32. package/backend/dist/src/sessions/dto/session.dto.js +7 -7
  33. package/backend/dist/src/sessions/dto/session.dto.js.map +1 -1
  34. package/backend/dist/src/sessions/sessions.service.js +14 -5
  35. package/backend/dist/src/sessions/sessions.service.js.map +1 -1
  36. package/backend/dist/src/sub-agents/dto/create-sub-agent.dto.js +1 -1
  37. package/backend/dist/src/sub-agents/dto/create-sub-agent.dto.js.map +1 -1
  38. package/backend/dist/src/sub-agents/dto/update-sub-agent.dto.js +1 -1
  39. package/backend/dist/src/sub-agents/dto/update-sub-agent.dto.js.map +1 -1
  40. package/backend/dist/src/sub-agents/sub-agent.entity.js +1 -1
  41. package/backend/dist/src/sub-agents/sub-agent.entity.js.map +1 -1
  42. package/backend/dist/src/system-prompts/dto/system-prompt.dto.js +2 -2
  43. package/backend/dist/src/system-prompts/dto/system-prompt.dto.js.map +1 -1
  44. package/backend/dist/tsconfig.build.tsbuildinfo +1 -1
  45. package/package.json +1 -2
  46. package/backend/dist/packages/gemini-core/examples/simple.d.ts +0 -1
  47. package/backend/dist/packages/gemini-core/examples/simple.js +0 -73
  48. package/backend/dist/packages/gemini-core/examples/simple.js.map +0 -1
  49. package/backend/dist/packages/gemini-core/index.d.ts +0 -3
  50. package/backend/dist/packages/gemini-core/index.js +0 -27
  51. package/backend/dist/packages/gemini-core/index.js.map +0 -1
  52. package/backend/dist/packages/gemini-core/src/code_assist/codeAssist.d.ts +0 -5
  53. package/backend/dist/packages/gemini-core/src/code_assist/codeAssist.js +0 -17
  54. package/backend/dist/packages/gemini-core/src/code_assist/codeAssist.js.map +0 -1
  55. package/backend/dist/packages/gemini-core/src/code_assist/converter.d.ts +0 -69
  56. package/backend/dist/packages/gemini-core/src/code_assist/converter.js +0 -129
  57. package/backend/dist/packages/gemini-core/src/code_assist/converter.js.map +0 -1
  58. package/backend/dist/packages/gemini-core/src/code_assist/oauth-credential-storage.d.ts +0 -8
  59. package/backend/dist/packages/gemini-core/src/code_assist/oauth-credential-storage.js +0 -84
  60. package/backend/dist/packages/gemini-core/src/code_assist/oauth-credential-storage.js.map +0 -1
  61. package/backend/dist/packages/gemini-core/src/code_assist/oauth2.d.ts +0 -12
  62. package/backend/dist/packages/gemini-core/src/code_assist/oauth2.js +0 -371
  63. package/backend/dist/packages/gemini-core/src/code_assist/oauth2.js.map +0 -1
  64. package/backend/dist/packages/gemini-core/src/code_assist/server.d.ts +0 -28
  65. package/backend/dist/packages/gemini-core/src/code_assist/server.js +0 -135
  66. package/backend/dist/packages/gemini-core/src/code_assist/server.js.map +0 -1
  67. package/backend/dist/packages/gemini-core/src/code_assist/setup.d.ts +0 -10
  68. package/backend/dist/packages/gemini-core/src/code_assist/setup.js +0 -94
  69. package/backend/dist/packages/gemini-core/src/code_assist/setup.js.map +0 -1
  70. package/backend/dist/packages/gemini-core/src/code_assist/types.d.ts +0 -106
  71. package/backend/dist/packages/gemini-core/src/code_assist/types.js +0 -28
  72. package/backend/dist/packages/gemini-core/src/code_assist/types.js.map +0 -1
  73. package/backend/dist/packages/gemini-core/src/config/config.d.ts +0 -22
  74. package/backend/dist/packages/gemini-core/src/config/config.js +0 -38
  75. package/backend/dist/packages/gemini-core/src/config/config.js.map +0 -1
  76. package/backend/dist/packages/gemini-core/src/config/models.d.ts +0 -6
  77. package/backend/dist/packages/gemini-core/src/config/models.js +0 -13
  78. package/backend/dist/packages/gemini-core/src/config/models.js.map +0 -1
  79. package/backend/dist/packages/gemini-core/src/config/storage.d.ts +0 -8
  80. package/backend/dist/packages/gemini-core/src/config/storage.js +0 -25
  81. package/backend/dist/packages/gemini-core/src/config/storage.js.map +0 -1
  82. package/backend/dist/packages/gemini-core/src/core/contentGenerator.d.ts +0 -23
  83. package/backend/dist/packages/gemini-core/src/core/contentGenerator.js +0 -63
  84. package/backend/dist/packages/gemini-core/src/core/contentGenerator.js.map +0 -1
  85. package/backend/dist/packages/gemini-core/src/core/geminiChat.d.ts +0 -34
  86. package/backend/dist/packages/gemini-core/src/core/geminiChat.js +0 -247
  87. package/backend/dist/packages/gemini-core/src/core/geminiChat.js.map +0 -1
  88. package/backend/dist/packages/gemini-core/src/core/geminiRequest.d.ts +0 -3
  89. package/backend/dist/packages/gemini-core/src/core/geminiRequest.js +0 -8
  90. package/backend/dist/packages/gemini-core/src/core/geminiRequest.js.map +0 -1
  91. package/backend/dist/packages/gemini-core/src/core/prompts.d.ts +0 -7
  92. package/backend/dist/packages/gemini-core/src/core/prompts.js +0 -69
  93. package/backend/dist/packages/gemini-core/src/core/prompts.js.map +0 -1
  94. package/backend/dist/packages/gemini-core/src/core/tokenLimits.d.ts +0 -5
  95. package/backend/dist/packages/gemini-core/src/core/tokenLimits.js +0 -25
  96. package/backend/dist/packages/gemini-core/src/core/tokenLimits.js.map +0 -1
  97. package/backend/dist/packages/gemini-core/src/index.d.ts +0 -18
  98. package/backend/dist/packages/gemini-core/src/index.js +0 -37
  99. package/backend/dist/packages/gemini-core/src/index.js.map +0 -1
  100. package/backend/dist/packages/gemini-core/src/mcp/token-storage/base-token-storage.d.ts +0 -14
  101. package/backend/dist/packages/gemini-core/src/mcp/token-storage/base-token-storage.js +0 -34
  102. package/backend/dist/packages/gemini-core/src/mcp/token-storage/base-token-storage.js.map +0 -1
  103. package/backend/dist/packages/gemini-core/src/mcp/token-storage/file-token-storage.d.ts +0 -19
  104. package/backend/dist/packages/gemini-core/src/mcp/token-storage/file-token-storage.js +0 -141
  105. package/backend/dist/packages/gemini-core/src/mcp/token-storage/file-token-storage.js.map +0 -1
  106. package/backend/dist/packages/gemini-core/src/mcp/token-storage/hybrid-token-storage.d.ts +0 -18
  107. package/backend/dist/packages/gemini-core/src/mcp/token-storage/hybrid-token-storage.js +0 -74
  108. package/backend/dist/packages/gemini-core/src/mcp/token-storage/hybrid-token-storage.js.map +0 -1
  109. package/backend/dist/packages/gemini-core/src/mcp/token-storage/index.d.ts +0 -6
  110. package/backend/dist/packages/gemini-core/src/mcp/token-storage/index.js +0 -24
  111. package/backend/dist/packages/gemini-core/src/mcp/token-storage/index.js.map +0 -1
  112. package/backend/dist/packages/gemini-core/src/mcp/token-storage/keychain-token-storage.d.ts +0 -26
  113. package/backend/dist/packages/gemini-core/src/mcp/token-storage/keychain-token-storage.js +0 -188
  114. package/backend/dist/packages/gemini-core/src/mcp/token-storage/keychain-token-storage.js.map +0 -1
  115. package/backend/dist/packages/gemini-core/src/mcp/token-storage/types.d.ts +0 -27
  116. package/backend/dist/packages/gemini-core/src/mcp/token-storage/types.js +0 -9
  117. package/backend/dist/packages/gemini-core/src/mcp/token-storage/types.js.map +0 -1
  118. package/backend/dist/packages/gemini-core/src/utils/errors.d.ts +0 -34
  119. package/backend/dist/packages/gemini-core/src/utils/errors.js +0 -103
  120. package/backend/dist/packages/gemini-core/src/utils/errors.js.map +0 -1
  121. package/backend/dist/packages/gemini-core/src/utils/partUtils.d.ts +0 -7
  122. package/backend/dist/packages/gemini-core/src/utils/partUtils.js +0 -108
  123. package/backend/dist/packages/gemini-core/src/utils/partUtils.js.map +0 -1
  124. package/backend/dist/packages/gemini-core/src/utils/quotaErrorDetection.d.ts +0 -16
  125. package/backend/dist/packages/gemini-core/src/utils/quotaErrorDetection.js +0 -60
  126. package/backend/dist/packages/gemini-core/src/utils/quotaErrorDetection.js.map +0 -1
  127. package/backend/dist/packages/gemini-core/src/utils/retry.d.ts +0 -14
  128. package/backend/dist/packages/gemini-core/src/utils/retry.js +0 -154
  129. package/backend/dist/packages/gemini-core/src/utils/retry.js.map +0 -1
  130. package/backend/dist/packages/gemini-core/src/utils/session.d.ts +0 -1
  131. package/backend/dist/packages/gemini-core/src/utils/session.js +0 -6
  132. package/backend/dist/packages/gemini-core/src/utils/session.js.map +0 -1
  133. package/backend/dist/packages/gemini-core/src/utils/userAccountManager.d.ts +0 -10
  134. package/backend/dist/packages/gemini-core/src/utils/userAccountManager.js +0 -106
  135. package/backend/dist/packages/gemini-core/src/utils/userAccountManager.js.map +0 -1
  136. package/backend/dist/src/gemini/gemini-llm.provider.d.ts +0 -12
  137. package/backend/dist/src/gemini/gemini-llm.provider.js +0 -126
  138. package/backend/dist/src/gemini/gemini-llm.provider.js.map +0 -1
  139. package/backend/dist/src/gemini/gemini.module.d.ts +0 -2
  140. package/backend/dist/src/gemini/gemini.module.js +0 -21
  141. package/backend/dist/src/gemini/gemini.module.js.map +0 -1
  142. package/backend/packages/gemini-core/CODEMAP.md +0 -30
  143. package/backend/packages/gemini-core/examples/simple.ts +0 -120
  144. package/backend/packages/gemini-core/index.ts +0 -15
  145. package/backend/packages/gemini-core/src/code_assist/codeAssist.ts +0 -37
  146. package/backend/packages/gemini-core/src/code_assist/converter.ts +0 -250
  147. package/backend/packages/gemini-core/src/code_assist/oauth-credential-storage.ts +0 -129
  148. package/backend/packages/gemini-core/src/code_assist/oauth2.ts +0 -541
  149. package/backend/packages/gemini-core/src/code_assist/server.ts +0 -236
  150. package/backend/packages/gemini-core/src/code_assist/setup.ts +0 -124
  151. package/backend/packages/gemini-core/src/code_assist/types.ts +0 -201
  152. package/backend/packages/gemini-core/src/config/config.ts +0 -75
  153. package/backend/packages/gemini-core/src/config/models.ts +0 -23
  154. package/backend/packages/gemini-core/src/config/storage.ts +0 -30
  155. package/backend/packages/gemini-core/src/core/contentGenerator.ts +0 -136
  156. package/backend/packages/gemini-core/src/core/geminiChat.ts +0 -385
  157. package/backend/packages/gemini-core/src/core/geminiRequest.ts +0 -19
  158. package/backend/packages/gemini-core/src/core/prompts.ts +0 -109
  159. package/backend/packages/gemini-core/src/core/tokenLimits.ts +0 -32
  160. package/backend/packages/gemini-core/src/index.ts +0 -35
  161. package/backend/packages/gemini-core/src/mcp/token-storage/base-token-storage.ts +0 -49
  162. package/backend/packages/gemini-core/src/mcp/token-storage/file-token-storage.ts +0 -184
  163. package/backend/packages/gemini-core/src/mcp/token-storage/hybrid-token-storage.ts +0 -97
  164. package/backend/packages/gemini-core/src/mcp/token-storage/index.ts +0 -14
  165. package/backend/packages/gemini-core/src/mcp/token-storage/keychain-token-storage.ts +0 -251
  166. package/backend/packages/gemini-core/src/mcp/token-storage/types.ts +0 -42
  167. package/backend/packages/gemini-core/src/utils/errors.ts +0 -112
  168. package/backend/packages/gemini-core/src/utils/partUtils.ts +0 -169
  169. package/backend/packages/gemini-core/src/utils/quotaErrorDetection.ts +0 -102
  170. package/backend/packages/gemini-core/src/utils/retry.ts +0 -265
  171. package/backend/packages/gemini-core/src/utils/session.ts +0 -9
  172. package/backend/packages/gemini-core/src/utils/userAccountManager.ts +0 -140
@@ -1,35 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2025 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- // Export config
8
- export * from './config/config';
9
-
10
- // Export Core Logic
11
- export * from './core/contentGenerator';
12
- export * from './core/geminiChat';
13
- export * from './core/prompts';
14
- export * from './core/tokenLimits';
15
- export * from './core/geminiRequest';
16
-
17
- export * from './code_assist/codeAssist';
18
- export * from './code_assist/oauth2';
19
- export * from './code_assist/server';
20
- export * from './code_assist/types';
21
-
22
- // Export utilities
23
- export * from './utils/errors';
24
- export * from './utils/quotaErrorDetection';
25
- export * from './utils/retry';
26
- export * from './utils/partUtils';
27
- export { sessionId } from './utils/session';
28
- export { Storage } from './config/storage';
29
- export * from './utils/userAccountManager';
30
-
31
- // MCP token storage for auth
32
- export type {
33
- OAuthToken,
34
- OAuthCredentials,
35
- } from './mcp/token-storage/types';
@@ -1,49 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2025 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- import type { TokenStorage, OAuthCredentials } from './types';
8
-
9
- export abstract class BaseTokenStorage implements TokenStorage {
10
- protected readonly serviceName: string;
11
-
12
- constructor(serviceName: string) {
13
- this.serviceName = serviceName;
14
- }
15
-
16
- abstract getCredentials(serverName: string): Promise<OAuthCredentials | null>;
17
- abstract setCredentials(credentials: OAuthCredentials): Promise<void>;
18
- abstract deleteCredentials(serverName: string): Promise<void>;
19
- abstract listServers(): Promise<string[]>;
20
- abstract getAllCredentials(): Promise<Map<string, OAuthCredentials>>;
21
- abstract clearAll(): Promise<void>;
22
-
23
- protected validateCredentials(credentials: OAuthCredentials): void {
24
- if (!credentials.serverName) {
25
- throw new Error('Server name is required');
26
- }
27
- if (!credentials.token) {
28
- throw new Error('Token is required');
29
- }
30
- if (!credentials.token.accessToken) {
31
- throw new Error('Access token is required');
32
- }
33
- if (!credentials.token.tokenType) {
34
- throw new Error('Token type is required');
35
- }
36
- }
37
-
38
- protected isTokenExpired(credentials: OAuthCredentials): boolean {
39
- if (!credentials.token.expiresAt) {
40
- return false;
41
- }
42
- const bufferMs = 5 * 60 * 1000;
43
- return Date.now() > credentials.token.expiresAt - bufferMs;
44
- }
45
-
46
- protected sanitizeServerName(serverName: string): string {
47
- return serverName.replace(/[^a-zA-Z0-9-_.]/g, '_');
48
- }
49
- }
@@ -1,184 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2025 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- import { promises as fs } from 'node:fs';
8
- import * as path from 'node:path';
9
- import * as os from 'node:os';
10
- import * as crypto from 'node:crypto';
11
- import { BaseTokenStorage } from './base-token-storage';
12
- import type { OAuthCredentials } from './types';
13
-
14
- export class FileTokenStorage extends BaseTokenStorage {
15
- private readonly tokenFilePath: string;
16
- private readonly encryptionKey: Buffer;
17
-
18
- constructor(serviceName: string) {
19
- super(serviceName);
20
- const configDir = path.join(os.homedir(), '.gemini');
21
- this.tokenFilePath = path.join(configDir, 'mcp-oauth-tokens-v2.json');
22
- this.encryptionKey = this.deriveEncryptionKey();
23
- }
24
-
25
- private deriveEncryptionKey(): Buffer {
26
- const salt = `${os.hostname()}-${os.userInfo().username}-gemini-cli`;
27
- return crypto.scryptSync('gemini-cli-oauth', salt, 32);
28
- }
29
-
30
- private encrypt(text: string): string {
31
- const iv = crypto.randomBytes(16);
32
- const cipher = crypto.createCipheriv('aes-256-gcm', this.encryptionKey, iv);
33
-
34
- let encrypted = cipher.update(text, 'utf8', 'hex');
35
- encrypted += cipher.final('hex');
36
-
37
- const authTag = cipher.getAuthTag();
38
-
39
- return iv.toString('hex') + ':' + authTag.toString('hex') + ':' + encrypted;
40
- }
41
-
42
- private decrypt(encryptedData: string): string {
43
- const parts = encryptedData.split(':');
44
- if (parts.length !== 3) {
45
- throw new Error('Invalid encrypted data format');
46
- }
47
-
48
- const iv = Buffer.from(parts[0], 'hex');
49
- const authTag = Buffer.from(parts[1], 'hex');
50
- const encrypted = parts[2];
51
-
52
- const decipher = crypto.createDecipheriv(
53
- 'aes-256-gcm',
54
- this.encryptionKey,
55
- iv,
56
- );
57
- decipher.setAuthTag(authTag);
58
-
59
- let decrypted = decipher.update(encrypted, 'hex', 'utf8');
60
- decrypted += decipher.final('utf8');
61
-
62
- return decrypted;
63
- }
64
-
65
- private async ensureDirectoryExists(): Promise<void> {
66
- const dir = path.dirname(this.tokenFilePath);
67
- await fs.mkdir(dir, { recursive: true, mode: 0o700 });
68
- }
69
-
70
- private async loadTokens(): Promise<Map<string, OAuthCredentials>> {
71
- try {
72
- const data = await fs.readFile(this.tokenFilePath, 'utf-8');
73
- const decrypted = this.decrypt(data);
74
- const tokens = JSON.parse(decrypted) as Record<string, OAuthCredentials>;
75
- return new Map(Object.entries(tokens));
76
- } catch (error: unknown) {
77
- const err = error as NodeJS.ErrnoException & { message?: string };
78
- if (err.code === 'ENOENT') {
79
- throw new Error('Token file does not exist');
80
- }
81
- if (
82
- err.message?.includes('Invalid encrypted data format') ||
83
- err.message?.includes(
84
- 'Unsupported state or unable to authenticate data',
85
- )
86
- ) {
87
- throw new Error('Token file corrupted');
88
- }
89
- throw error;
90
- }
91
- }
92
-
93
- private async saveTokens(
94
- tokens: Map<string, OAuthCredentials>,
95
- ): Promise<void> {
96
- await this.ensureDirectoryExists();
97
-
98
- const data = Object.fromEntries(tokens);
99
- const json = JSON.stringify(data, null, 2);
100
- const encrypted = this.encrypt(json);
101
-
102
- await fs.writeFile(this.tokenFilePath, encrypted, { mode: 0o600 });
103
- }
104
-
105
- async getCredentials(serverName: string): Promise<OAuthCredentials | null> {
106
- const tokens = await this.loadTokens();
107
- const credentials = tokens.get(serverName);
108
-
109
- if (!credentials) {
110
- return null;
111
- }
112
-
113
- if (this.isTokenExpired(credentials)) {
114
- return null;
115
- }
116
-
117
- return credentials;
118
- }
119
-
120
- async setCredentials(credentials: OAuthCredentials): Promise<void> {
121
- this.validateCredentials(credentials);
122
-
123
- const tokens = await this.loadTokens();
124
- const updatedCredentials: OAuthCredentials = {
125
- ...credentials,
126
- updatedAt: Date.now(),
127
- };
128
-
129
- tokens.set(credentials.serverName, updatedCredentials);
130
- await this.saveTokens(tokens);
131
- }
132
-
133
- async deleteCredentials(serverName: string): Promise<void> {
134
- const tokens = await this.loadTokens();
135
-
136
- if (!tokens.has(serverName)) {
137
- throw new Error(`No credentials found for ${serverName}`);
138
- }
139
-
140
- tokens.delete(serverName);
141
-
142
- if (tokens.size === 0) {
143
- try {
144
- await fs.unlink(this.tokenFilePath);
145
- } catch (error: unknown) {
146
- const err = error as NodeJS.ErrnoException;
147
- if (err.code !== 'ENOENT') {
148
- throw error;
149
- }
150
- }
151
- } else {
152
- await this.saveTokens(tokens);
153
- }
154
- }
155
-
156
- async listServers(): Promise<string[]> {
157
- const tokens = await this.loadTokens();
158
- return Array.from(tokens.keys());
159
- }
160
-
161
- async getAllCredentials(): Promise<Map<string, OAuthCredentials>> {
162
- const tokens = await this.loadTokens();
163
- const result = new Map<string, OAuthCredentials>();
164
-
165
- for (const [serverName, credentials] of tokens) {
166
- if (!this.isTokenExpired(credentials)) {
167
- result.set(serverName, credentials);
168
- }
169
- }
170
-
171
- return result;
172
- }
173
-
174
- async clearAll(): Promise<void> {
175
- try {
176
- await fs.unlink(this.tokenFilePath);
177
- } catch (error: unknown) {
178
- const err = error as NodeJS.ErrnoException;
179
- if (err.code !== 'ENOENT') {
180
- throw error;
181
- }
182
- }
183
- }
184
- }
@@ -1,97 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2025 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- import { BaseTokenStorage } from './base-token-storage';
8
- import { FileTokenStorage } from './file-token-storage';
9
- import type { TokenStorage, OAuthCredentials } from './types';
10
- import { TokenStorageType } from './types';
11
-
12
- const FORCE_FILE_STORAGE_ENV_VAR = 'GEMINI_FORCE_FILE_STORAGE';
13
-
14
- export class HybridTokenStorage extends BaseTokenStorage {
15
- private storage: TokenStorage | null = null;
16
- private storageType: TokenStorageType | null = null;
17
- private storageInitPromise: Promise<TokenStorage> | null = null;
18
-
19
- constructor(serviceName: string) {
20
- super(serviceName);
21
- }
22
-
23
- private async initializeStorage(): Promise<TokenStorage> {
24
- const forceFileStorage = process.env[FORCE_FILE_STORAGE_ENV_VAR] === 'true';
25
-
26
- if (!forceFileStorage) {
27
- try {
28
- const { KeychainTokenStorage } = await import(
29
- './keychain-token-storage'
30
- );
31
- const keychainStorage = new KeychainTokenStorage(this.serviceName);
32
-
33
- const isAvailable = await keychainStorage.isAvailable();
34
- if (isAvailable) {
35
- this.storage = keychainStorage;
36
- this.storageType = TokenStorageType.KEYCHAIN;
37
- return this.storage;
38
- }
39
- } catch (_e) {
40
- // Fallback to file storage if keychain fails to initialize
41
- }
42
- }
43
-
44
- this.storage = new FileTokenStorage(this.serviceName);
45
- this.storageType = TokenStorageType.ENCRYPTED_FILE;
46
- return this.storage;
47
- }
48
-
49
- private async getStorage(): Promise<TokenStorage> {
50
- if (this.storage !== null) {
51
- return this.storage;
52
- }
53
-
54
- // Use a single initialization promise to avoid race conditions
55
- if (!this.storageInitPromise) {
56
- this.storageInitPromise = this.initializeStorage();
57
- }
58
-
59
- // Wait for initialization to complete
60
- return await this.storageInitPromise;
61
- }
62
-
63
- async getCredentials(serverName: string): Promise<OAuthCredentials | null> {
64
- const storage = await this.getStorage();
65
- return storage.getCredentials(serverName);
66
- }
67
-
68
- async setCredentials(credentials: OAuthCredentials): Promise<void> {
69
- const storage = await this.getStorage();
70
- await storage.setCredentials(credentials);
71
- }
72
-
73
- async deleteCredentials(serverName: string): Promise<void> {
74
- const storage = await this.getStorage();
75
- await storage.deleteCredentials(serverName);
76
- }
77
-
78
- async listServers(): Promise<string[]> {
79
- const storage = await this.getStorage();
80
- return storage.listServers();
81
- }
82
-
83
- async getAllCredentials(): Promise<Map<string, OAuthCredentials>> {
84
- const storage = await this.getStorage();
85
- return storage.getAllCredentials();
86
- }
87
-
88
- async clearAll(): Promise<void> {
89
- const storage = await this.getStorage();
90
- await storage.clearAll();
91
- }
92
-
93
- async getStorageType(): Promise<TokenStorageType> {
94
- await this.getStorage();
95
- return this.storageType!;
96
- }
97
- }
@@ -1,14 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2025 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- export * from './types';
8
- export * from './base-token-storage';
9
- export * from './file-token-storage';
10
- export * from './hybrid-token-storage';
11
-
12
- export const DEFAULT_SERVICE_NAME = 'gemini-cli-oauth';
13
- export const FORCE_ENCRYPTED_FILE_ENV_VAR =
14
- 'GEMINI_FORCE_ENCRYPTED_FILE_STORAGE';
@@ -1,251 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2025 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- import * as crypto from 'node:crypto';
8
- import { BaseTokenStorage } from './base-token-storage';
9
- import type { OAuthCredentials } from './types';
10
-
11
- interface Keytar {
12
- getPassword(service: string, account: string): Promise<string | null>;
13
- setPassword(
14
- service: string,
15
- account: string,
16
- password: string,
17
- ): Promise<void>;
18
- deletePassword(service: string, account: string): Promise<boolean>;
19
- findCredentials(
20
- service: string,
21
- ): Promise<Array<{ account: string; password: string }>>;
22
- }
23
-
24
- const KEYCHAIN_TEST_PREFIX = '__keychain_test__';
25
-
26
- export class KeychainTokenStorage extends BaseTokenStorage {
27
- private keychainAvailable: boolean | null = null;
28
- private keytarModule: Keytar | null = null;
29
- private keytarLoadAttempted = false;
30
-
31
- async getKeytar(): Promise<Keytar | null> {
32
- // If we've already tried loading (successfully or not), return the result
33
- if (this.keytarLoadAttempted) {
34
- return this.keytarModule;
35
- }
36
-
37
- this.keytarLoadAttempted = true;
38
-
39
- try {
40
- // Try to import keytar without any timeout - let the OS handle it
41
- const moduleName = 'keytar';
42
- const module = await import(moduleName);
43
- this.keytarModule = module.default || module;
44
- } catch (error) {
45
- console.error(error);
46
- }
47
- return this.keytarModule;
48
- }
49
-
50
- async getCredentials(serverName: string): Promise<OAuthCredentials | null> {
51
- if (!(await this.checkKeychainAvailability())) {
52
- throw new Error('Keychain is not available');
53
- }
54
-
55
- const keytar = await this.getKeytar();
56
- if (!keytar) {
57
- throw new Error('Keytar module not available');
58
- }
59
-
60
- try {
61
- const sanitizedName = this.sanitizeServerName(serverName);
62
- const data = await keytar.getPassword(this.serviceName, sanitizedName);
63
-
64
- if (!data) {
65
- return null;
66
- }
67
-
68
- const credentials = JSON.parse(data) as OAuthCredentials;
69
-
70
- if (this.isTokenExpired(credentials)) {
71
- return null;
72
- }
73
-
74
- return credentials;
75
- } catch (error) {
76
- if (error instanceof SyntaxError) {
77
- throw new Error(`Failed to parse stored credentials for ${serverName}`);
78
- }
79
- throw error;
80
- }
81
- }
82
-
83
- async setCredentials(credentials: OAuthCredentials): Promise<void> {
84
- if (!(await this.checkKeychainAvailability())) {
85
- throw new Error('Keychain is not available');
86
- }
87
-
88
- const keytar = await this.getKeytar();
89
- if (!keytar) {
90
- throw new Error('Keytar module not available');
91
- }
92
-
93
- this.validateCredentials(credentials);
94
-
95
- const sanitizedName = this.sanitizeServerName(credentials.serverName);
96
- const updatedCredentials: OAuthCredentials = {
97
- ...credentials,
98
- updatedAt: Date.now(),
99
- };
100
-
101
- const data = JSON.stringify(updatedCredentials);
102
- await keytar.setPassword(this.serviceName, sanitizedName, data);
103
- }
104
-
105
- async deleteCredentials(serverName: string): Promise<void> {
106
- if (!(await this.checkKeychainAvailability())) {
107
- throw new Error('Keychain is not available');
108
- }
109
-
110
- const keytar = await this.getKeytar();
111
- if (!keytar) {
112
- throw new Error('Keytar module not available');
113
- }
114
-
115
- const sanitizedName = this.sanitizeServerName(serverName);
116
- const deleted = await keytar.deletePassword(
117
- this.serviceName,
118
- sanitizedName,
119
- );
120
-
121
- if (!deleted) {
122
- throw new Error(`No credentials found for ${serverName}`);
123
- }
124
- }
125
-
126
- async listServers(): Promise<string[]> {
127
- if (!(await this.checkKeychainAvailability())) {
128
- throw new Error('Keychain is not available');
129
- }
130
-
131
- const keytar = await this.getKeytar();
132
- if (!keytar) {
133
- throw new Error('Keytar module not available');
134
- }
135
-
136
- try {
137
- const credentials = await keytar.findCredentials(this.serviceName);
138
- return credentials
139
- .filter((cred) => !cred.account.startsWith(KEYCHAIN_TEST_PREFIX))
140
- .map((cred: { account: string }) => cred.account);
141
- } catch (error) {
142
- console.error('Failed to list servers from keychain:', error);
143
- return [];
144
- }
145
- }
146
-
147
- async getAllCredentials(): Promise<Map<string, OAuthCredentials>> {
148
- if (!(await this.checkKeychainAvailability())) {
149
- throw new Error('Keychain is not available');
150
- }
151
-
152
- const keytar = await this.getKeytar();
153
- if (!keytar) {
154
- throw new Error('Keytar module not available');
155
- }
156
-
157
- const result = new Map<string, OAuthCredentials>();
158
- try {
159
- const credentials = (
160
- await keytar.findCredentials(this.serviceName)
161
- ).filter((c) => !c.account.startsWith(KEYCHAIN_TEST_PREFIX));
162
-
163
- for (const cred of credentials) {
164
- try {
165
- const data = JSON.parse(cred.password) as OAuthCredentials;
166
- if (!this.isTokenExpired(data)) {
167
- result.set(cred.account, data);
168
- }
169
- } catch (error) {
170
- console.error(
171
- `Failed to parse credentials for ${cred.account}:`,
172
- error,
173
- );
174
- }
175
- }
176
- } catch (error) {
177
- console.error('Failed to get all credentials from keychain:', error);
178
- }
179
-
180
- return result;
181
- }
182
-
183
- async clearAll(): Promise<void> {
184
- if (!(await this.checkKeychainAvailability())) {
185
- throw new Error('Keychain is not available');
186
- }
187
-
188
- const servers = this.keytarModule
189
- ? await this.keytarModule
190
- .findCredentials(this.serviceName)
191
- .then((creds) => creds.map((c) => c.account))
192
- .catch((error: Error) => {
193
- throw new Error(
194
- `Failed to list servers for clearing: ${error.message}`,
195
- );
196
- })
197
- : [];
198
- const errors: Error[] = [];
199
-
200
- for (const server of servers) {
201
- try {
202
- await this.deleteCredentials(server);
203
- } catch (error) {
204
- errors.push(error as Error);
205
- }
206
- }
207
-
208
- if (errors.length > 0) {
209
- throw new Error(
210
- `Failed to clear some credentials: ${errors.map((e) => e.message).join(', ')}`,
211
- );
212
- }
213
- }
214
-
215
- // Checks whether or not a set-get-delete cycle with the keychain works.
216
- // Returns false if any operation fails.
217
- async checkKeychainAvailability(): Promise<boolean> {
218
- if (this.keychainAvailable !== null) {
219
- return this.keychainAvailable;
220
- }
221
-
222
- try {
223
- const keytar = await this.getKeytar();
224
- if (!keytar) {
225
- this.keychainAvailable = false;
226
- return false;
227
- }
228
-
229
- const testAccount = `${KEYCHAIN_TEST_PREFIX}${crypto.randomBytes(8).toString('hex')}`;
230
- const testPassword = 'test';
231
-
232
- await keytar.setPassword(this.serviceName, testAccount, testPassword);
233
- const retrieved = await keytar.getPassword(this.serviceName, testAccount);
234
- const deleted = await keytar.deletePassword(
235
- this.serviceName,
236
- testAccount,
237
- );
238
-
239
- const success = deleted && retrieved === testPassword;
240
- this.keychainAvailable = success;
241
- return success;
242
- } catch (_error) {
243
- this.keychainAvailable = false;
244
- return false;
245
- }
246
- }
247
-
248
- async isAvailable(): Promise<boolean> {
249
- return this.checkKeychainAvailability();
250
- }
251
- }
@@ -1,42 +0,0 @@
1
- /**
2
- * @license
3
- * Copyright 2025 Google LLC
4
- * SPDX-License-Identifier: Apache-2.0
5
- */
6
-
7
- /**
8
- * Interface for OAuth tokens.
9
- */
10
- export interface OAuthToken {
11
- accessToken: string;
12
- refreshToken?: string;
13
- expiresAt?: number;
14
- tokenType: string;
15
- scope?: string;
16
- }
17
-
18
- /**
19
- * Interface for stored OAuth credentials.
20
- */
21
- export interface OAuthCredentials {
22
- serverName: string;
23
- token: OAuthToken;
24
- clientId?: string;
25
- tokenUrl?: string;
26
- mcpServerUrl?: string;
27
- updatedAt: number;
28
- }
29
-
30
- export interface TokenStorage {
31
- getCredentials(serverName: string): Promise<OAuthCredentials | null>;
32
- setCredentials(credentials: OAuthCredentials): Promise<void>;
33
- deleteCredentials(serverName: string): Promise<void>;
34
- listServers(): Promise<string[]>;
35
- getAllCredentials(): Promise<Map<string, OAuthCredentials>>;
36
- clearAll(): Promise<void>;
37
- }
38
-
39
- export enum TokenStorageType {
40
- KEYCHAIN = 'keychain',
41
- ENCRYPTED_FILE = 'encrypted_file',
42
- }